在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
一,为什么需要生成唯一id(发号器)?1,在分布式和微服务系统中, 生成唯一id相对困难, 常用的方式: uuid不具备可读性,作为主键存储时性能也不够好, mysql的主键,在分库时使用不够方便,高并发时性能没有保障 所以在这里我们演示使用redis+lua生成唯一id
2,使用redis性能虽好,但仍然要考虑单点故障问题, 这里建议在生产环境中使用主从+哨兵或集群方式
说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest 对应的源码可以访问这里获取: https://github.com/liuhongdi/ 说明:作者:刘宏缔 邮箱: [email protected]
二,本演示项目的相关信息1,项目地址: https://github.com/liuhongdi/redisuniqueid
2,项目原理: 利用redis中lua脚本的原子性,避免产生重复id的问题
3,项目结构:
三,lua代码说明id.lua local id_key = 'id_key_'..KEYS[1] local current = redis.call('get',id_key) if current == false then redis.call('set',id_key,1) return '1' end --redis.log(redis.LOG_NOTICE,' current:'..current..':') local result = tonumber(current)+1 --redis.log(redis.LOG_NOTICE,' result:'..result..':') redis.call('set',id_key,result) return tostring(result) 说明: id_key变量作为存储的kv对的key 如果变量不存在,设置id_key值为1并返回 如果变量存在,值加1后返回 注意转为字符串形式后返回,方便java代码接收
四,java代码说明RedisLuaUtil.java @Service public class RedisLuaUtil { @Resource private StringRedisTemplate stringRedisTemplate; private static final Logger logger = LogManager.getLogger("bussniesslog"); /* run a lua script luaFileName: lua file name,no path keyList: list for redis key return:lua return value,type is string */ public String runLuaScript(String luaFileName,List<String> keyList) { DefaultRedisScript<String> redisScript = new DefaultRedisScript<>(); redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/"+luaFileName))); redisScript.setResultType(String.class); String argsone = "none"; //String result = stringRedisTemplate.execute(redisScript, keyList,argsone); String result = ""; try { result = stringRedisTemplate.execute(redisScript, keyList,argsone); } catch (Exception e) { logger.error("发生异常",e); throw new ServiceException(ResponseCode.LUA_ERROR.getMsg()); } return result; } } 说明:功能用来运行resource目录下的lua脚本
IdServiceImpl.java @Service public class IdServiceImpl implements IdService { @Resource private RedisLuaUtil redisLuaUtil; /* * 调用lua得到唯一id * 返回:唯一的自增id,字符串形式 * */ @Override public String getId(String idType) { List<String> keyList = new ArrayList(); keyList.add(idType); String res = redisLuaUtil.runLuaScript("id.lua",keyList); System.out.println("-----res:"+res); return res; } } 说明:得到自增id的service
五,测试发号器效果1,从redis删除已创建的key 127.0.0.1:6379> del id_key_formtoken (integer) 1 127.0.0.1:6379> get id_key_formtoken (nil)
2,用ab发起测试 #-c:20个并发 #-n:共20个请求 [liuhongdi@localhost ~]$ ab -c 20 -n 20 http://127.0.0.1:8080/order/getid
3,查看输出效果 -----res:1 -----res:2 -----res:3 -----res:4 -----res:5 -----res:6 -----res:8 -----res:7 -----res:9 -----res:10 -----res:11 -----res:12 -----res:13 -----res:14 -----res:15 -----res:16 -----res:17 -----res:20 -----res:19 -----res:18 并发情况下,仍然正确的按自增的顺序生成id
六,查看spring boot的版本. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE)
|
请发表评论