聊聊全局服務ID-Snowflake
團隊文化:進取,分享,快樂,責任!
團隊願景:做最好的產品,打造有影響力的團隊!
一:前言
很多業務系統,都有生成一個記錄標示的需求,例如
1) 訂單標示:order-id
2) 醫生標示:doctor-id
3) 消息標示:message-id
業務往往都會根據這個記錄標示去查詢一條記錄信息。這就要求這個標示要就具有唯一性。如果作為MySql資料庫主鍵(針對大部分業務團隊資料庫MySql 引擎InnoDB)又要求這個唯一ID具有有序性(原因在此不贅述)。 由此可以看出全局服務ID的兩大核心要素:
1)全局唯一性
2)趨勢有序性(分散式系統中嚴格有序代價大)
二:常見做法
1.UUID
優點:
1)無需遠程調用,生成性能高
不足:
1) 無序、結構無規則
2) 長字元串作為主鍵、索引效率低下
這種做法基本上不被推薦(也因使用場景而定)
2.使用資料庫auto_increment 來生成全局唯一遞增ID
優點:
1) 利用資料庫自帶功能,簡單
2) 能保證唯一性、遞增性
不足:
1) 結構形式單一
例如:起始值 0,步長 1,產生id依次為0,1,2,3,4,5等,會暴露數據量(訂單量等)一些敏感信息。
2) 不易擴容
例如剛開始單庫,後期擴容為雙庫,那奇數或者偶數的id(或者取模,方式很多)會被移動到另一個庫中,如果以後在擴容,還要移動。
很多業務團隊也會在此思路基礎上進行變種改進
A)設置不同步長來進行資料庫水平擴容提高系統的高可用、高性能;
B)對ID進行結構規劃,前x位為時間戳,後y位為遞增數等等;
C)「一次提取多次使用」,在資料庫中只設置當前遞增數,讀取後可用遞增數保存到內存中。
團隊中的一些業務也在使用這種方式。
3.redis、zk、mongoDB等也可以生產全局ID,再此不詳細介紹。
4.Snowflake(雪花演算法,本文我想重點介紹的內容)
大部分開發者應該都知道Snowflake,它是Twitter開源的分散式ID生成演算法,結果是一個Long型的ID。其核心思想是:
除最高位可以不用外(以後可用來擴展),其他位均可自由浮動,自由組合。
我們團隊負責京東醫藥、互聯網醫療業務,業務中需要大量使用到唯一ID這種業務標示。年初的時候團隊一直想做一個統一的全局ID生成服務,後期經過調研,選擇了snowflake開發了GSI(global service id)系統,目前醫療業務(血糖儀項目)在嘗試使用中。
下圖為GSI設計思路:
9bit業務號能支持512種業務
4bit機器號能支持16台伺服器(GSI以JSF(京東內部RPC)形式對外提供服務)
20bit自增序列理論上單位時間內支持產生1048576個自增序列號
30bit秒級時間戳支持使用34年
① 內部採用JDK CAS演算法秒級單位內生成自增序列(棄用了synchronize,ReentrantLock(jdk1.8中對synchronize優化的也很好));
② 支持一次生成多個ID,業務調用方可以自己存在內存或緩存中;
③ 支持反解,
【備註:business表示業務號,machine表示機器號(注意機器號非機器ip),seq表示單位時間內自增序列號,time表示秒級時間戳】
不足:依賴機器時鐘,如果對機器時鐘回撥,會導致產生相同ID(正常情況不會出現此種情況)
技術服務於業務,只有最適合業務的技術才能體現出它的意義,我們不必糾結於那種更好,只要能滿足你的業務就ok,關於GSI的介紹就到這裡(後續考慮將GSI開源)


TAG:我就是程序員 |