MogoDB 分片鍵
MongoDB 根據分片鍵分割 collection 中的文檔,然後分配到分片集群的成員中。
分片鍵可以是一個存在於每個文件中的索引字段或者復合索引字段。
MongoDB 使用不同範圍的分片鍵值來分割 collection 中的數據。不同分片鍵範圍是不重疊的並且每個分片鍵範圍與一個 chunk 關聯。
選擇分片鍵
選擇的分片鍵要盡量使 chunks 平滑的分配到集群的分片中。如果不那麽做,會影響集群的性能:
- 假設所有的 chunks 都被分配到一個 分片中,那麽整個集群的能力就是這一臺分片的能力
- 假設 chunks 沒有均勻分配,集中在一個分片中,那麽這個分片可能會成為瓶頸。因為總的耗時取決於最慢的那個分片
為了選擇出好的分片鍵,還需要了解分片鍵的以下性質
- 基數性
- 頻率
- 單調改變
基數性
分片鍵的基數性決定了平衡器可以創建的最大 chunks 數目。
在任意時刻,一個唯一的鍵值對只能存在於不超過一個的 chunk 中。現有一個基數性為 4 的分片鍵,那麽在集群中最多有 4 個(有效的) chunks,因為增加額外的分片不會帶來收益,每個 chunk 儲存一個唯一的分片鍵。
然而高的基數性也不能保證數據在集群中平滑分配,這還與頻率和單調性有關。當選擇分片鍵時,這三個因素都要考慮到。
頻率
分片鍵的頻率指給定的分片鍵值在文件中多常出現。
如果大部分的文件只包含一部分分片鍵,那麽儲存大部分文件的分片會成為集群的瓶頸。如果大部分文件只包含一個分片鍵,那麽對應的 chunk 會很大並且不可分割。這就會降低集群的性能。
如果你的數據模型需要在一個高頻率的分片鍵,考慮使用一個唯一的或者低頻率的復合索引代替。
單調改變的分片鍵
單調改變指分片鍵是單調遞增或單調遞減的,這樣的分片鍵更容易插入到集群中的一個分片中(而不是均勻分配)。
發生這種情況的原因是每個集群都有兩個 chunk 捕捉超出邊界的分片鍵。一個捕捉超出(分片鍵的)最大值的分片鍵,一個捕捉小於最小值的分片鍵。
如果一個分片鍵是單調遞增的,那麽在一定時刻之後,所有新增都會進入到 [maxKey, 正無窮]
這個 chunk。同理,單調遞減的分片鍵會進入 [負無窮, minKey]
。包含對應 chunk 的分片就會成為寫操作的瓶頸。
唯一索引
只有使用整個分片鍵作為其前綴的唯一索引才能確保其是跨分片唯一的[2]。
哈希分片
哈希分片使用一個字段的哈希索引作為分片鍵來分割數據。
哈希分片以犧牲查詢隔離性為代價來提供分布更加均勻的分片集群。分片值相鄰的文檔更不可能在同樣的分片上,因此對應給定的範圍查詢 mongos 更可能去執行廣播查詢。同時,mongos 也能匹配相等的查詢到一個分片上。
哈希分片鍵
選擇作為哈希分片鍵的字段應該有高基數性。假設沒有高基數性,那麽數據就會集中到某些分片上而不是均勻分配到所有分片,然後數據過多的分片會造成瓶頸。
理想的哈希分片鍵是單調性的字段,比如 ObjectId 或者時間。
分片鍵的限制
大小
分片鍵的大小不能超過 512 bytes。
分片鍵索引類型
分片鍵的索引可以是在分片鍵上遞增的索引,一個以分片鍵為前綴的在分片鍵上遞增的復合索引或是一個哈希索引。
分片鍵索引不能是在分片鍵字段上的多鍵索引、文本索引或者地理空間索引。
分片鍵不可改變
如果你一定要改變分片鍵:
- 導出所有數據
- Drop 舊的分片 collection
- 設置新的分片鍵
- 預先分割分片鍵的範圍來確保初始分配是均勻的
- 導入數據
文檔中的分片鍵不可改變
你不能修改分片鍵在文本中的對應字段的值。
參考
- https://docs.mongodb.com/manual/core/sharding-shard-key/#shard-key
- https://docs.mongodb.com/manual/reference/limits/#sharded-clusters
MogoDB 分片鍵