zoukankan      html  css  js  c++  java
  • spring boot:redis+lua实现顺序自增的唯一id发号器(spring boot 2.3.1)

    一,为什么需要生成唯一id(发号器)?

    1,在分布式和微服务系统中,

      生成唯一id相对困难,

      常用的方式:

       uuid不具备可读性,作为主键存储时性能也不够好,

       mysql的主键,在分库时使用不够方便,高并发时性能没有保障

       所以在这里我们演示使用redis+lua生成唯一id

    2,使用redis性能虽好,但仍然要考虑单点故障问题,

       这里建议在生产环境中使用主从+哨兵或集群方式

      

    说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

             对应的源码可以访问这里获取: https://github.com/liuhongdi/

    说明:作者:刘宏缔 邮箱: 371125307@qq.com

    二,本演示项目的相关信息

    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)
  • 相关阅读:
    【Leetcode Top-K问题 BFPRT】第三大的数(414)
    【Leetcode 堆、快速选择、Top-K问题 BFPRT】数组中的第K个最大元素(215)
    BFPRT算法
    对快速排序的分析 Quick Sort
    内部排序算法汇总
    【Leetcode堆和双端队列】滑动窗口最大值(239)
    Python里的堆heapq
    【Leetcode堆】数据流中的第K大元素(703)
    【Leetcode栈】有效的括号(20)
    【Leetcode链表】分隔链表(86)
  • 原文地址:https://www.cnblogs.com/architectforest/p/13177918.html
Copyright © 2011-2022 走看看