由於最近接觸了流水號生成相關的項目代碼,但是遇到了并發問題導致了生成的號出現了重複的情況。爲了厘清其中的關鍵點,於是實現相關代碼去保證正確的流水號生成,幫助排查相關問題是有必要的。此外流水號生成在許多場景多有出現,多熟悉實踐相關邏輯會比較有幫助。
經和 AI 溝通得知,流水號生成的實現方式一般有三種,包含數據庫行鎖,號段模式和利用 redis 原子性實現。其中號段模式少了 redis,但是比簡單使用數據庫行鎖應對的并發量要大,當前的項目情況下,redis
一般不會安裝,因此優先瞭解以數據庫爲主的號段模式實現會是一個比較好的入門途徑。
一般情況下,常見的流水號是按天生成的,當天生成的流水號唯一,不重複。此外需要適配不同的業務模式,考慮使用不同的業務前綴。因此流水號的格式變成業務前綴+日期+順序號的形式。
流水號一般情況下,也不需要呈現按數字逐個增長的特性,一些數字沒有用到其實不影響整體的流程。這樣的情況下適配號段模式,在宕機或者應用重啓的情況下,仍然保證流程可用,而不會產生影響。
根據以上需求,數據庫需要保存業務前綴,日期等所需信息,以及號段需要的當前最大號及遞增步長。 具體如下:
| 名稱 | 類型 | 説明 | 描述 |
|---|---|---|---|
| prefix | varchar | 業務前綴 | PK |
| seq_date | varchar | 日期 | PK |
| max_seq | int | 當前已分配最大序列號 | |
| step | int | 遞增步長 | |
| update_time | datetime | 更新日期 |
Ⅰ、整體流程
Ⅱ、實現細節
insert into series_segment(prefix, seq_date, max_seq, step, update_time)
values (:prefix, :seqDate, 0, :step, CURRENT_TIMESTAMP)
ON DUPLICATE KEY UPDATE max_seq = max_seq
Ⅲ、并發安全性
我認爲并發安全即是要保證并發過程中的不變量不變。對於號段模式代碼來説,生成的序列號最大值不超過數據庫裏對應行的最大值即可。此外需要保證生成序列號唯一。
這一步實現相關功能,然後傳入對應的業務模式前綴,觀察是否獲得序列號,并且數據庫號段數據正確即可,序列號沒有超過號段最大值即可。
壓力測試目標
測試維度
| 维度 | 数值 |
|---|---|
| 并发线程数 | 50 / 100 / 200 |
| 每线程请求次数 | 1,000 |
| 总请求数 | 50,000 ~ 200,000 |
| prefix | 数量 1、5、10(混合) |
| date | 固定当天 |
壓力測試確實是有必要的,我在功能測試只能保證基本可用。但是上壓力測試以後,確實發現了幾個并發問題,無法保證上面的并發要求。此外號段模式可以將步長減少,這樣并發壓力會更大,數據庫訪問頻次也會增多,可看出更多的問題。