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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM