Redis 實現全局唯一 ID
分佈式系統中由於跨進程跨系統,在某些場景中,我們需要生成全局的唯一 ID,例如訂單系統,併發情況下,不同的系統需要同時生成不一樣的訂單 ID 方便後續的訂單下單與查詢等等。
全局唯一 ID 生成策略
-
UUID
-
Redis 自增
-
snowflake 算法
-
數據庫自增
-
百度開源的 UidGenerator
-
美圖點評的 Leaf
Redis 自增 ID 策略
-
每天一個 key,方便統計訂單量
-
ID 構造:時間戳 + 計數器
ID 的組成部分:
-
符號位:1bit,永遠爲 0,表示正數
-
時間戳:31bit,最大 2147483648 秒,大概 69 年
-
序列號:32bit,秒內的計數器,支持每秒產生 2^32 個不同 ID
利用 redis 生成全局唯一 ID,其實 redis 扮演的角色就是一個計數器的作用,方便後續的統計。
優點:高性能,高併發,唯一性,遞增性,安全性。
缺點:需要依賴 redis 去實現
代碼實現
/**
* @author issavior
*/
@Component
public class RedisIdWorker {
/**
* 開始時間戳
*/
private static final long BEGIN_TIMESTAMP = 1640995200L;
/**
* 序列號的位數
*/
private static final int COUNT_BITS = 32;
private final StringRedisTemplate stringRedisTemplate;
public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
public long nextId(String keyPrefix) {
// 1.生成時間戳
LocalDateTime now = LocalDateTime.now();
long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
long timestamp = nowSecond - BEGIN_TIMESTAMP;
// 2.生成序列號
// 2.1.獲取當前日期,精確到天
String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
// 2.2.自增長
Long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);
// 3.拼接並返回
return timestamp << COUNT_BITS | (count == null ? 0 : count);
}
/**
* 獲取2022年1月1號0點0時0分的時間戳
* @param args
*/
public static void main(String[] args) {
LocalDateTime startLocalTime = LocalDateTime.of(2022, 1, 1, 0, 0, 0);
long startTime = startLocalTime.toEpochSecond(ZoneOffset.UTC);
System.out.println(startTime);
LocalDateTime now = LocalDateTime.now();
String date = now.format(DateTimeFormatter.ofPattern("yyyy:MM:dd:HH:mm"));
System.out.println(date);
}
}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/8qB6W7xRjffm7WI3qaO_zw