回覆列表
-
1 # 會點程式碼的大叔
-
2 # wuda0112
MongoDB是分散式的,那麼它是如何保證全域性主鍵唯一的呢?首先看下MongoDB ObjectId的資料結構
ObjectId由12個Byte組成,分成4個部分
4個byte用於表示當前時間,只到秒(可以考慮下為什麼不是毫秒?)3個byte用於表示當前機器,將網絡卡資訊編碼到3個byte中2個byte用於表示當前程序id2個byte用於自增數優點
不同主機之間,由於網絡卡資訊是不一樣的,因此生成的id是不可能衝突的在同一個主機上,即使部署了多個例項,由於它們的程序ID是不一樣的,因此生成的id也不可能衝突看到這裡就感覺這樣的方案簡直就是完美,不用任何配置,就自動的生成了全域性唯一ID。比起Snowflake演算法好用多了!
那我們不是直接就可以拿到Mysql中用於主鍵欄位了?等等,事情沒那麼簡單!想想mysql數字型別BigInt的最大值,BigInt由8 byte組成,如圖
存不了一個ObjectId的值,這就尷尬了!
但是如果是用Decimal來存ObjectId的值呢?曾經問過我們的DBA,他說從來沒見過,有點怪!大家覺得可行嗎?
可以的。
全域性唯一 ID有些同學可能會有疑問,MySQL 資料庫本身就有自增長的主鍵,為什麼還需要別的元件協助生成呢?
如果是單臺 MySQL 資料庫的話,當然是用本身的自增長序列就可以了,但是如果我們做了分庫分表之後呢?比如使用者表 userTable 資料量達到了 4000 萬,單表有些吃力,我們將 userTable 拆成兩張表儲存到兩個 MySQL 資料庫中;這時候如果再使用資料庫本身的自增序列,倒是也不會有錯,每一個表內的主鍵不會重複,但是表和表比較的話,主鍵 ID 可能會發生重複;這時候就需要使用元件或者演算法,生成全域性唯一 ID 了。
MongoDB ObjectIdMongoDB 的 ObjectId ,也是可以用於全域性唯一 ID 的。
{"_id": ObjectId("5d47ca7528021724ac19f745")}
MongoDB 的 ObjectId 共佔 12 個位元組,其中:
3.2 之前的版本(包括 3.2):4 位元組時間戳 + 3 位元組機器識別符號(機器 ID) + 2 位元組程序 ID + 3位元組隨機計數器;
3.2 之後版本:4 位元組時間戳 + 5 位元組隨機值 + 3 位元組遞增計數器;
其中時間戳位元組可以保證毫秒級唯一,節機器識別符號考慮到了分散式,位元組程序 ID 保證了同一臺伺服器執行多個例項時的唯一性,位元組遞增計數器保證了同一個時間點內 ID 的唯一性。
優缺點不管是老版本還是新版本,MongoDB 的 ObjectId 至少都可以保證叢集內的唯一,我們可以搭建一個全域性唯一 ID 生成的服務,利用 MongoDB 生成 ObjectId 並對外提供服務(MongoDB 的各語言驅動都實現了 ObjectId 的生成演算法)。
優點:MongoDB 的效能不錯,可以使用叢集部署,保證其高可用;ID 內自帶一些含義,比如時間戳,必要的時候可以進行反解;
缺點:和資料庫一樣,需要引入對應的元件/軟體,增加了系統的複雜度;最關鍵的是,這兩種方案都意味著生成全域性唯一 ID 的系統(服務),會成為一個單點,在軟體架構中,單獨就意味著風險;如果這個服務出現問題,那麼所有依賴於這個服務的系統都會崩潰掉。