分佈式Id - redis方式

本篇分享內容是關於生成分佈式Id的其中之一方案,除了redis方案以外還有如:數據庫,雪花算法,mogodb(object_id也是數據庫)等方案,對於redis來講是咱們經常使用並接觸比較多的,所以主要談談結合redis生成分佈式id方案。redis

  • 分佈式Id設計流程圖
  • 基於redis的hash自動increment累加生成有序Id
  • 按期刪除無用hash列

分佈式Id設計流程圖(有點粗略)

 

基於redis的hash自動increment累加生成有序Id

使用redis方案生成id,其中之一的方式主要使用increment(遞增),無論是string、hash等都具備該方法,爲了更方便管理咱們id生成key這裏建議使用hash的列的方式,如下內容都基於springboot分享;算法

固然,第一步咱們須要建立一個hash和hkey才行,至於在業務第一次被訪問來建立這個hash仍是經過服務自動建立這個看業務和流量,這裏的hkey是有必定規則的(固然不用侷限性),這裏我按照日期格式來作key,能夠有以下代碼:spring

 1     /**
 2      * 生成天天的初始Id
 3      * @param hashName
 4      * @return
 5      */
 6     public String initPrimaryId(String hashName) {
 7         Assert.hasLength(hashName, "hashName不能爲空");
 8 
 9         String hashCol = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
10         //自定義編號規則
11         String hashColVal = hashCol + "00001";
12         redisTemplate.opsForHash().putIfAbsent(hashName, hashCol, hashColVal);
13         return hashCol;
14     }

上面很容易理解,hash中key是有天天日期格式組成,意思天天都須要生成一個新的日期key,經過putIfAbsent達到不重複添加的原則,至於hval能夠根據自定義編號規則來生成一串數字字符(注:必定要數字);有了上面的基礎,咱們僅僅須要increment來累加,redis即幫咱們完整hval+1的操做,固然能夠自定義累加數,以下代碼:數據庫

 1     /**
 2      * 獲取分佈式Id
 3      *
 4      * @param hashName
 5      * @return
 6      */
 7     public long getPrimaryId(String hashName) {
 8         try {
 9             String hashCol = initPrimaryId(hashName);
10             return redisTemplate.opsForHash().increment(hashName, hashCol, 1);
11         } catch (Exception ex) {
12             ex.printStackTrace();
13         }
14         return 0;
15     }

按期刪除無用hash列

就上面咱們經過hash來設置天天id只增初始值,hash的hkey佈局用自動過時功能,所以咱們須要代碼中維護一套清除來hkey的機制,既然id是根據日期生成,咱們能夠就用往前推n天的方式達到清除老hkey目的:springboot

 1     /**
 2      * 刪除多少天以前的cols
 3      * @param hashName
 4      * @param lessDay
 5      * @return
 6      */
 7     public Long removePrimaryByLessDay(String hashName, int lessDay) {
 8         try {
 9             //當前日期
10             String hashCol = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
11             long idl = Long.valueOf(hashCol) - lessDay;
12 
13             String[] removeCols = redisTemplate.opsForHash().entries(hashName).keySet().stream().
14                     map(key -> key.toString()).
15                     filter(key -> idl > Long.valueOf(key)).  //從+1開始,避免刪除當天數據
16                     toArray(String[]::new);
17 
18             if (ArrayUtils.isNotEmpty(removeCols)) {
19                 return redisTemplate.opsForHash().delete(hashName, removeCols);
20             }
21         } catch (Exception ex) {
22             ex.printStackTrace();
23         }
24         return 0L;
25     }

按照日期來生成分佈式id,達到id不重複的目的,這也就是分佈式id(不重複),看起來簡單其實若是在高流量衝擊下,須要考慮的東西要不少,好比:何時生成初始Id、在多個服務器保證服務器時間儘量同樣狀況下,該保留多少日期hkey等;服務器

就上面代碼對初始Id就作的不是很好,在業務獲取Id時候,會去檢測並建立id,這樣與redis交互就多了一次,一般能夠用服務來一次性生成當前日期日後推n天的hkey,這樣就避免了在業務獲取id時候,還要去putIfAbsent一次驗證,減小了請求次數。實在不行能夠使用lua腳本放在一次請求去作put和increment,你可能會用到:less

1             RedisScript script = new DefaultRedisScript("");
2             redisTemplate.execute(script, Arrays.asList(""));
相關文章
相關標籤/搜索