成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

簡單實用!利用Redis輕松實現高并發全局ID生成器

數據庫 Redis
今天我就給大家帶來一個神器級的解決方案——Redis 分布式 ID 生成器!配合 SpringBoot3.0,讓你的 ID 生成變得既簡單又高效。

我相信你會經常遇到要生成唯一 ID 的場景,比如標識每次請求、生成一個訂單編號、創建用戶需要創建一個用戶 ID。

謝霸戈:這還不簡單,用 UUID 不就行了。

UUID 確實是個好東西,生成的 ID 全球唯一,但是有兩個致命缺陷。

  • 不是遞增的。MySQL 中索引的數據結構是 B+Tree,這種數據結構的特點是索引樹上的節點的數據是有序的,而如果使用 UUID 作為主鍵,那么每次插入數據時,因為無法保證每次產生的 UUID 有序,所以就會出現新的 UUID 需要插入到索引樹的中間去,這樣可能會頻繁地導致頁分裂,使性能下降。
  • 太占用內存。每個 UUID 由 36 個字符組成,在字符串進行比較時,需要從前往后比較,字符串越長,性能越差。另外字符串越長,占用的內存越大,由于頁的大小是固定的,這樣一個頁上能存放的關鍵字數量就會越少,這樣最終就會導致索引樹的高度越大,在索引搜索的時候,發生的磁盤 IO 次數越多,性能越差。

謝霸戈:那咋辦呢?

別急,今天我就給大家帶來一個神器級的解決方案——Redis 分布式 ID 生成器!配合 SpringBoot3.0,讓你的 ID 生成變得既簡單又高效。

分布式 ID 要滿足什么要求

在進入正文前,先介紹下分布式 ID 應該滿足哪些特性。

分布式 ID 生成器需要滿足以下特性。

  1. 有序性之單調遞增,想要分而治之、二分法查找就必須實現。另外,MySQL 是你們用的最多的數據庫,B+ 樹為了維護 ID 的有序性,就會頻繁的在索引的中間位置插入而挪動后面節點的位置,甚至導致頻繁的頁分裂,這對于性能的影響是極大的。
  2. 全局唯一性,ID 不唯一就會出現主鍵沖突。
  3. 高性能,生成 ID 是高頻操作,如果性能緩慢,系統的整體性能都會受到限制。
  4. 高可用,也就是在給定的時間間隔內,一個系統總的可用時間占的比例。
  5. 存儲空間小,用 MySQL 的 InnoDB B+樹來說,普通索引(非聚集索引)會存儲主鍵值,主鍵越大,每個 Page 頁可以存儲的數據就越少,訪問磁盤 I/O 的次數就會增加。

Redis String 實現分布式 ID

Redis 集群能保證高可用和高性能,為了節省內存,ID 可以使用數字的形式,并且通過遞增的方式來創建新的 ID。

防止重啟數據丟失,你還需要把 Redis AOF 持久化開啟。

MySQL:“開啟 AOF 持久,為了性能設置成 everysec 策略還是有可能丟失一秒的數據,所以你還可以使用一個異步機制將生成的最大 ID 持久化到一個 MySQL。”

好主意,在生成 ID 之后發送一條消息到 MQ 消息隊列中,把值持久化到 MySQL 中。

我們可以使用 Redis String 數據類型來實現,key 用于區分不同業務場景的 ID 生成器,value 存儲 ID。

String 數據類型提供了 INCR 指令,它能把 key 中存儲的數字加 1 并返回客戶端。如果 key 不存在,那么 key 的 value 先被初始化成 0,再執行加 1 操作并返回給客戶端。

Redis,作為一個高性能的內存數據庫,天生就適合處理高并發的場景。它的“單線程”模型更是讓它在處理 ID 生成時如魚得水。

Redis 的操作是原子性的,這就意味著在整個過程中,不會有任何的并發問題出現,從而確保了 ID 的唯一性。

設計思路

設計思路如下圖所示。

圖 2-4

  1. 假設訂單 ID 生成器的 key 是“counter:order”,當應用服務啟動的時候先從數據庫中查詢出最大值 M。執行 EXISTS counter:order 判斷是否存在 key。
  • Redis 中不存在 key “counter:order”,執行 SET counter:order M 將 M 值作寫入 Redis。
  • Redis 中存在 key “counter:order”,值為 K,那么就比較 M 和 K 的值,執行 SET counter:order max(M, N)將最大值寫入 Redis,相等的話就不操作。
  1. 應用服務啟動完成后,每次需要生成 ID 的時候,應用程序就向 Redis 服務器發送 INCR counter:order指令。
  2. 應用程序將獲取到的 ID 值發送到 MQ 消息隊列,消費者監聽隊列把值更新到 MySQL。

SpringBoot 代碼實現

接下來,我們結合 SpringBoot3.0 來打造一個強大且易用的 Redis 分布式 ID 生成器。

首先,我們需要在 SpringBoot 項目中引入 redis 的依賴。在pom.xml文件中添上這行代碼:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

搞定依賴后,我們得告訴 SpringBoot 怎么連接到 Redis。打開application.yml文件,填上 Redis 的服務地址和端口:

spring:
  application:
    name: redis
  redis:
    host: 127.0.0.1
    port: 6379
    password: magebyte
    timeout: 6000

萬事俱備,只欠東風!接下來,我們編寫一個 ID 生成器工具類。這個工具類負責與 Redis 交互,生成唯一的 ID。這里我們使用 Redis 的INCR命令,它能讓 ID 自增,確保每次獲取的 ID 都是唯一的。

@Component
public class OrderIdGenerator implements InitializingBean {

    private final StringRedisTemplate redisTemplate;

    /**
     * 操作數據庫 dao
     */
    private final IdGeneratorMapper idGeneratorMapper;

    private static final String KEY = "counter:order";

    /**
     * 數據庫中的 ID 值
     */
    private String dbId;

    @Autowired
    public OrderIdGenerator(StringRedisTemplate redisTemplate, IdGeneratorMapper idGeneratorMapper) {
        this.redisTemplate = redisTemplate;
        this.idGeneratorMapper = idGeneratorMapper;
    }

    public Long generateId(String key) {
        return redisTemplate.opsForValue().increment(key, 1);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 從數據庫查詢最大 ID
        this.dbId = idGeneratorMapper.getMaxID(KEY);

        Boolean hasKey = redisTemplate.hasKey(KEY);
        if (Boolean.TRUE.equals(hasKey)) {
            // key 存在,比較 dbId 與 redisValue,取出最大值
            String redisValue = redisTemplate.opsForValue().get(KEY);
            String targetValue = max(this.dbId, redisValue);
        } else {

自定義 ID 規則

不過呢,光有唯一的 ID 還不夠,我們還得讓它更符合業務的實際需求。比如訂單編號吧,我們可能希望它的格式是ORD-20240528-0001,其中ORD是業務標識,20240528是日期,0001是當天的序號。

public String generateCustomId(String key, String prefix, String datePattern) {
    long sequence = redisTemplate.opsForValue().increment(key, 1);
    return String.format("%s-%s-%04d", prefix, new SimpleDateFormat(datePattern).format(new Date()), sequence);
}

那具體怎么用呢?讓我們在業務代碼中一探究竟!想象一下,在一個電商系統中,當一個新的訂單如流星般劃過天際,我們迫不及待地想要一個獨一無二的 ID 來標記它時——很簡單,只需調用我們的generateCustomId方法,傳入訂單相關的參數即可。

@Service
public class OrderService {
    private final RedisIdGenerator idGenerator;

    @Autowired
    public OrderService(RedisIdGenerator idGenerator) {
        this.idGenerator = idativeIdGenerator;
    }

    public Order createOrder(OrderRequest request) {
        String orderId = idGenerator.generateCustomId("order:id", "ORD", "yyyyMMdd");
        Order order = new Order();
        order.setId(orderId);
        // 其他業務邏輯...
        return order;
    }
}
責任編輯:姜華 來源: 碼哥跳動
相關推薦

2022-12-29 08:43:54

IDredis

2017-07-01 16:02:39

分布式ID生成器

2019-12-27 10:00:34

開源技術 軟件

2022-07-25 10:27:36

背景生成器工具前端

2024-01-26 08:28:41

工單號生成器場景

2022-03-03 08:30:41

GeneratorES6函數

2025-03-11 08:50:00

CASID分布式

2020-08-21 13:15:29

開發技能代碼

2011-12-23 13:42:05

JavaScript

2010-09-07 16:31:17

SQL語句insert

2021-04-22 21:15:38

Generator函數生成器

2015-08-25 11:07:58

2025-01-23 08:36:27

CSS開發工具

2022-02-15 10:30:58

UUID

2025-01-06 09:06:04

JavaScriptWeb 開發Generators

2016-01-08 10:55:31

PHP莫斯電碼生成器

2016-12-21 10:55:55

PHP莫斯電碼生成器

2017-03-20 17:49:21

Java Web模板代碼

2024-11-01 15:51:06

2021-07-14 07:17:37

Springboot分布式UIDGenerato
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 草草影院ccyy| 欧美日韩视频在线 | 国产精品国产精品国产专区不卡 | 色综合视频 | 中文字幕精品视频在线观看 | 免费在线成人 | 国产精品99久久免费观看 | 久久久久久久久久久久91 | 高清亚洲 | 欧美视频在线一区 | 成人亚洲一区 | 日韩成人在线网站 | 91精品国产色综合久久 | 国产精品成人一区二区 | 91.com视频| 99精品欧美一区二区蜜桃免费 | 国产精品久久久久久久 | 91在线一区 | 亚洲一区在线播放 | 成人h动漫亚洲一区二区 | 国产午夜精品视频 | 51ⅴ精品国产91久久久久久 | 国产区在线看 | 精品在线一区 | 99热精品在线 | 成人午夜免费福利视频 | 亚洲欧美国产视频 | 亚洲国产黄色av | 在线一区二区国产 | 久久国产欧美日韩精品 | 蜜桃视频一区二区三区 | 成人性视频免费网站 | 午夜丰满寂寞少妇精品 | 午夜精品一区二区三区在线播放 | 性网站免费 | 一区二区三区四区五区在线视频 | 中文字幕一区二区三区日韩精品 | 欧美一级欧美一级在线播放 | 精品国产久| 国产精品视频在线观看 | www.黄色片视频 |