分享大厂分布式唯一ID设计方案,快来围观
??點擊上方?好好學java?,選擇?星標?公眾號
重磅資訊、干貨,第一時間送達 今日推薦:終于放棄了單調的swagger-ui了,選擇了這款神器—knife4j個人原創+1博客:點擊前往,查看更多作者:老顧聊技術
www.toutiao.com/i6682672464708764174
前言
上一篇文章中介紹了分布式唯一ID你想了解一線大廠的分布式唯一ID生成方案嗎??留了一個懸念,這里老顧就介紹一下兩種大廠的方案思路。希望能夠幫到大家。
改造數據庫主鍵自增
老顧在前一篇文章中介紹了利用數據庫的自增主鍵的特性,可以實現分布式ID;這個ID比較簡短明了,適合做userId,正好符合如何永不遷移數據和避免熱點? 根據服務器指標分配數據量(揭秘篇)文章中的ID的需求。但這個方案有嚴重的問題:
1、一旦步長定下來,不容易擴容
2、數據庫壓力山大
我們小伙伴們看看怎么優化這個方案,先看數據庫壓力大,為什么壓力大?是因為我們每次獲取ID的時候,都要去數據庫請求一次。那我們可以不可以不要每次去取?
附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,這是本人這幾年及春招的總結,目前,已經拿到了大廠offer,拿去不謝!
下載方式
1.?首先掃描下方二維碼
2.?后臺回復「Java面試」即可獲取
思路我們可以請求數據庫得到ID的時候,可設計成獲得的ID是一個ID區間段。
我們看上圖,有張id規則表:
1、id表示為主鍵,無業務含義。
2、biz_tag為了表示業務,因為整體系統中會有很多業務需要生成ID,這樣可以共用一張表維護
3、max_id表示現在整體系統中已經分配的最大ID
4、desc描述
5、update_time表示每次取的ID時間
我們再來看看整體流程:
1、【用戶服務】在注冊一個用戶時,需要一個用戶ID;會請求【生成ID服務(是獨立的應用)】的接口
2、【生成ID服務】會去查詢數據庫,找到user_tag的id,現在的max_id為0,step=1000
3、【生成ID服務】把max_id和step返回給【用戶服務】;并且把max_id更新為max_id = max_id + step,即更新為1000
4、【用戶服務】獲得max_id=0,step=1000;
5、 這個用戶服務可以用ID=【max_id + 1,max_id+step】區間的ID,即為【1,1000】
6、【用戶服務】會把這個區間保存到jvm中
7、【用戶服務】需要用到ID的時候,在區間【1,1000】中依次獲取id,可采用AtomicLong中的getAndIncrement方法。
8、如果把區間的值用完了,再去請求【生產ID服務】接口,獲取到max_id為1000,即可以用【max_id + 1,max_id+step】區間的ID,即為【1001,2000】
這個方案就非常完美的解決了數據庫自增的問題,而且可以自行定義max_id的起點,和step步長,非常方便擴容。
而且也解決了數據庫壓力的問題,因為在一段區間內,是在jvm內存中獲取的,而不需要每次請求數據庫。即使數據庫宕機了,系統也不受影響,ID還能維持一段時間。
競爭問題
以上方案中,如果是多個用戶服務,同時獲取ID,同時去請求【ID服務】,在獲取max_id的時候會存在并發問題。
如用戶服務A,取到的max_id=1000 ;用戶服務B取到的也是max_id=1000,那就出現了問題,Id重復了。那怎么解決?
其實方案很多,加分布式鎖,保證同一時刻只有一個用戶服務獲取max_id。當然也可以用數據庫自身的鎖去解決。
利用事務方式加行鎖,上面的語句,在沒有執行完之前,是不允許第二個用戶服務請求過來的,第二個請求只能阻塞。
突發阻塞問題
上圖中,多個用戶服務獲取到了各自的ID區間,在高并發場景下,id用的很快,如果3個用戶服務在某一時刻都用完了,同時去請求【ID服務】。因為上面提到的競爭問題,所有只有一個用戶服務去操作數據庫,其他二個會被阻塞。
小伙伴就會問,有這么巧嗎?同時id用完。我們這里舉的是3個用戶服務,感覺概率不大;如果是100個用戶服務呢?概率是不是一下子大了。
出現的現象就是一會兒突然系統耗時變長,一會兒好了,就是這個原因導致的,怎么去解決?
雙buffer方案
在一般的系統設計中,雙buffer會經常看到,怎么去解決上面的問題也可以采用雙buffer方案。
在設計的時候,采用雙buffer方案,上圖的流程:
1、當前獲取ID在buffer1中,每次獲取ID在buffer1中獲取
2、當buffer1中的Id已經使用到了100,也就是達到區間的10%
3、達到了10%,先判斷buffer2中有沒有去獲取過,如果沒有就立即發起請求獲取ID線
程,此線程把獲取到的ID,設置到buffer2中。
4、如果buffer1用完了,會自動切換到buffer2
5、buffer2用到10%了,也會啟動線程再次獲取,設置到buffer1中
6、依次往返
雙buffer的方案,小伙伴們有沒有感覺很酷,這樣就達到了業務場景用的ID,都是在jvm內存中獲得的,從此不需要到數據庫中獲取了。允許數據庫宕機時間更長了。
因為會有一個線程,會觀察什么時候去自動獲取。兩個buffer之間自行切換使用。就解決了突發阻塞的問題。
總結
此方案是美團公司使用的分布式ID算法,小伙伴們如果想了解更深,可以去網上搜下,老顧這里應該介紹了比較詳細了。
當然此方案美團還做了一些別的優化,監控id使用頻率,自動設置步長step,從而達到對id節省使用。
此ID方案非常適合老顧前幾篇文章中的id需求如何永不遷移數據和避免熱點? 根據服務器指標分配數據量(揭秘篇)?。
但此ID存在一定的問題,就是太過連續,競爭對手可以預測,不適合訂單ID。那還有沒有別的方案。下次老顧介紹一下美團的另一種生成ID方案。謝謝!!!
最后,再附上我歷時三個月總結的?Java 面試 + Java 后端技術學習指南,這是本人這幾年及春招的總結,目前,已經拿到了大廠offer,拿去不謝!
下載方式
1.?首先掃描下方二維碼
2.?后臺回復「Java面試」即可獲取
總結
以上是生活随笔為你收集整理的分享大厂分布式唯一ID设计方案,快来围观的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 去哪面试都会问的HashMap
- 下一篇: 程序员入职国企,1周上班5小时,晒出薪资