1. 程式人生 > >Mongodb 分片、配置分片、選擇片鍵、分片管理

Mongodb 分片、配置分片、選擇片鍵、分片管理

Mongodb分片

1.分片(sharding)是指將資料拆分,將其分散存放在不同的機器上的過程。有時也用分割槽(partitioning)來表示這個概念。將資料分散到不同的機器上,不需要功能強大的大型計算機就可以

    儲存更多的資料,處理更大的負載。

2. MongoDB支援自動分片(autosharding),可以使資料庫架構對應用程式不可見,也可以簡化系統管理。對應用程式而言,好像始終在使用一個單機的MongoDB伺服器一樣。另一方面,

    mongoDB自動處理資料在分片上的分佈,也更容易新增和刪除分片技術。

3. 複製與分片的區別:複製時讓多臺伺服器都擁有同樣的資料副本,每一臺伺服器都是其他伺服器的映象,而每一個分片都和其他分片擁有不同的資料子集。

4.路由伺服器:為了對應用程式隱藏資料庫架構的細節,在分片之前要先執行mongos進行一次路由過程。這個路由伺服器維護這一個"內容列表",指明瞭每個分片包含什麼資料內容。應用

    程式只需要連線路由伺服器,就可以像使用單機一樣進行正常的請求了。

5. 執行sh.status()可以看到叢集的狀態:分片摘要信心、資料庫摘要資訊、集合摘要資訊。

6.要對一個集合分片,首先你要對這個集合的資料庫啟用分片,執行如下命令:sh.enableSharding("test")

7.片鍵:片鍵是集合的一個鍵,MongoDB根據這個鍵拆分資料。例如:username 。在啟用分片之前,先在希望作為片鍵的鍵上建立索引:db.users.ensureIndex({"username":1})

8. 對集合分片:sh.shardCollection("test.users",{"username":1})

9.集合被拆分為多個數據塊,每個資料塊都是集合的一個數據子集。這是按照片鍵的範圍排列的({"username":minValue}-->>{"username":maxValue}指出了每個資料塊的範圍)。

10.包含片鍵的查詢能夠直接被髮送到目標分片或者是叢集分片的一個子集。這樣的查詢叫做定向查詢(targetd query)。有些查詢必須被髮送到所有分片,這樣的查詢叫做分散-聚合查詢(

      scatter-gather query);mongos將查詢分散到所有的分片上,然後經各個分片的查詢結果聚集起來。

11.cluster.stop() 關閉整個叢集。

BSON型別

配置分片:

1. 何時進行分片:決定何時分片是一個值得權衡的問題。通常不必太早分片,因為分片不僅會增加部署的操作複雜度,還要求做出設計決策,而改決策以後很難再改。另外最好也不要在系統

    執行太久之後再分片,因為在一個過載的系統上不停機進行分配是很困難的。

2. 分片的目的:增加可用的RAM,增加可用磁碟空間,減輕單臺伺服器的負載,處理單個mongod無法承受的吞吐量。

3. 一般情況下至少應該建立3個或者以上的分片。

4. 啟動伺服器:

   1). 配置伺服器:配置伺服器相當於叢集的大腦,儲存著叢集和分片的元資料,即各分片包含哪些資料的資訊。因此,應該首先建立配置伺服器,鑑於它所包含的的資料極端重要性,必須啟用

         其日誌功能,並確保其資料儲存在非易失性驅動器上。每個配置伺服器都應該位於單獨的物理機上,最好是分佈在不同地址位置的機器上。

         a. 啟動配置伺服器:mongod --configsvr --dbpath  /var/lib/mongodb -f  /var/lib/config/mognd.conf  。需要啟動三臺配置伺服器,且都是可寫的。

             為什麼是3臺配置伺服器?因為我們需要考慮不時之需。但是,也不需要過多的配置伺服器,因為配置伺服器上的確認操作比較耗時。另外,如果有伺服器宕機了,叢集源資料就會變成只讀的。

             --configsvr 選項指定mongod為新配置伺服器。該選項並非必選項,因為它所做的不過是將mongod的預設監聽埠改為27019,並大預設的資料目錄改為/data/configdb而已(可以使用

             --port 和 --dbpath 選項修改這兩項配置)。但建議使用--configsvr選項,因為它比價直白地說明了這些配置伺服器的用途。

             配置伺服器的1KB相當於200MB知識資料,它儲存的真實資料的分佈表。由於配置伺服器並不需要太多的資源,因此可以將其部署在執行著其他程式的伺服器上。 

   2). mongos程序:三個配置伺服器均處於執行狀態後,啟動一個mongos程序供應用程式連線。mongos程序需要配置伺服器的地址,所以必須使用--configdb選項啟動mongos:

          mongos --configdb config-1:27019,config-2:27019,config-3:27019 -f /var/lib/mongos.conf

          預設情況下,mongos執行在27017埠。mongos本身不儲存資料,它會在啟動時從配置伺服器載入叢集資料。

         可以啟動任意數量的mongos程序。通常的設定時每個應用程式伺服器使用一個mongos程序(與應用伺服器執行在同一臺機器上)

          每個mongos程序必須按照列表排序,使用相同的配置伺服器列表。

    3). 將副本集轉換為分片:有兩種可能性:已經有一個副本集,或者從零開始建立叢集。下例假設我們已經擁有了一個副本集。如果是從零開始的話,可先初始化一個空的副本集,然後按照本例操作。

         a. 告知mongos副本集名稱和副本整合員列表:sh.addShard("spock/server-1:27017,server-2:27017,server-4:27017")  mongos能夠自動檢測到沒有包含在副本整合員表中的成員。

         b. 副本集作為分片新增到集群后,就可以將應用程式設定從連線到副本集改為連線到mongos。

         c. 副本集名稱spokc被作為分片名稱。如果之後希望移除這個分片或者是向這個分片遷移資料,可以使用spock來標誌這個分片。

         d. 配置完分片後,必須將客戶端設定為將所有請求傳送到mongos,而不是副本集。同時配置防火牆規則,以確保客戶端不能直接將請求傳送到分片。

         e. 有一個--shardsvr選項,與前面介紹的--configsvr選項類似,它也沒什麼實用性(只是將預設埠改為27018),但在操作中建議使用該選項。

         f. 不建議建立單mongod伺服器分片(而不是副本集分片),將單一伺服器分片轉換為副本集需要停機操作。

   4). 增加叢集容量:通過增加分片來增加叢集容量。

   5). 資料分片:除非明確指定規則,否則MongoDB不會自動對資料進行拆分。如果有必要,必須明確告知資料庫和集合。加入對music資料庫中的artists集合按照name進行分片,

          db.enableSharding("music")         對資料庫分片是對集合分片的先決條件

          sh.shardCollection("music.artists",{"name":1})   對集合分片,集合會按照name鍵進行分片。如果是對已存在的集合分片,那麼name鍵上必須有索引,否則會返回錯誤。

          shardCollection()命令會經集合拆分為多個數據塊,這是MongoDB遷移資料的基本單元。命令執行後,MongoDB會均衡的將資料分散到叢集的分片上。

5. MongoDB如何追蹤叢集資料

    1). MongoDB將文件分組為塊(chunk),每個塊由給定片鍵特定範圍內的文件組成。一個塊只存在於一個分片上,所以MongoDB用一個比較小的表就能夠維護跟分片的對映。

    2). 當一個塊增長到特定大小時,MongoDB會自動將其拆分為兩個較小的塊。

    3). 一個常見的誤解釋同一個塊內的資料儲存在磁碟的同一片區域。這是不正確的,塊並不影響mongod儲存集合資料的方式。

    4). 塊資訊儲存在config.chunks集合中。左閉右開。

    5). 可以使用複合片鍵,工作方式與使用複合索引進行排序一樣。

    6). 拆分塊:mongos會記錄在每個塊中插入了多少資料,一旦達到某個閾值,就會檢查是否需要對塊進行拆分。mongos就會在配置伺服器更新這個塊的源資訊。塊拆分中只需要改變塊源資料即可,

         而無需進行資料移動。進行拆分時,配置伺服器會建立新的塊文件,同時修改舊的塊範圍,拆分完成以後,mongos會重置對原始塊的追蹤器,同時為新的塊建立新的追蹤器。

   7). 分片有時可能會找不到任何可用的拆分點,因為合法拆分塊方法有限。具有相同片鍵的文件必須儲存在相同的塊中。

    8). 如果mongos試圖進行拆分時有一個伺服器掛了,那麼mongos就無法更新源資料。mongos不斷重複發起拆分請求卻無法進行拆分的過程,叫做拆分風暴。防止拆分風暴的唯一方法是儘可能保證

         配置伺服器的可用和健康。也可以重啟mongos,重置引入計數器,這樣他就不會再處於拆分閾值點了。

    9). 如果mongos程序不斷重啟,它們的計數器可能永遠也不會到達閾值點,因此塊的增加不存在最大值,也就無法到達閾值點。

   10). 防止無法拆分的兩種方法:一是減少mongos程序的波動,二是使塊的大小比實際預期小一些,這樣就更容易達到拆分閾值點。

    11). 可以在mongos啟動時指定--nosplit選項,從而關閉塊的拆分。

6. 均衡器:均衡器負責資料的遷移。它會週期性地檢查分片間是否存在不均衡,如果存在,則會開始塊的遷移。雖然均衡器通常被看成單一的實體,但每個mongos有時也會扮演均衡器的角色。

    每隔幾秒,mongos就會嘗試變身均衡器。如果沒有其他可用的均衡器,mongos就會對整個叢集加鎖,以防止配置伺服器對整個叢集進行修改,然後做一次均衡。

    mongos成為均衡器後,就會檢查每個集合的分塊表,從而檢視是否有分片達到了均衡閾值。

選擇片鍵

1.對集合進行分片時,要選擇一或兩個欄位用於拆分資料,這個鍵就叫做片鍵。

2.拆分資料最常用的資料分發方式有三種:升序片鍵、隨機分發的片鍵和基於位置的片鍵。

    1). 升序片鍵:升序片鍵通常有點類似於"date"欄位或者是ObjectId,是一種隨著時間穩定增長的欄位。缺點:例如ObjectId可能會導致接下來的所有的寫入操作都在同一塊分片上。

    2). 隨機分發的片鍵:隨機分發的片鍵可以是使用者名稱,郵件地址,UDID,MD5雜湊值或者資料集中其他一些沒有規律的鍵。缺點:MongoDB在隨機訪問超出RAM大小的資料時效率不高。

    3). 基於位置的片鍵:基於位置的片鍵可以是使用者的IP、經緯度、或者地址。這裡的"位置"比較抽象,不必與實際的物理位置欄位相關。

         如果希望特定範圍內的塊出現在特定的分片中,可以為分片新增tag,然後為塊指定相應的tag

3. 片鍵策略:

   1). 雜湊片鍵:如果追求的是資料載入速度的極致,那麼雜湊片鍵是最佳選擇。雜湊片鍵可使其他任何鍵隨機分發,因此,如果打算在大量查詢中使用使用升序鍵,但同時又希望寫入資料隨機分發的話,

         雜湊片鍵會是一個非常好的選擇。缺點:無法使用雜湊片鍵做指定目標的範圍查詢。  

         建立步驟: db.users.ensureIndex({"username":"hashed"})   ,   sh.shardCollection("app.users",{"username":"hashed"})

    2). GridFS的雜湊片鍵

    3). 流水策略:如果有一些伺服器比其他伺服器更強大,我們可能希望讓這些強大的伺服器處理更多的負載。比如說:加入有一個使用SSD的分片能夠處理10倍於其他機器的負載。我們可以強制將所有新資料

         插入到SSD,然後讓均衡器將舊的塊移動到其他分片上。

         a. 為SSD指定一個標籤:sh.addShardTag("shard-name","ssd")

         b. 將升序鍵的當前值一直到正無窮範圍的塊都指定分佈在SSD分片上:sh.addTagRange("dbName.collName",{"_id":ObjectId()},...{"_id":MaxKey},"ssd") 

             所有插入請求均會路由到這個塊上,這個塊始終位於標籤的ssd的分片上。

         c. 除非修改標籤範圍,否則從升序鍵的當前值一直到正無窮都被固定在這個分片上。可以建立一個定時任務每天更新一次標籤範圍:

             use config

             var tag =db.tags.findOne({"ns":"dbName.collName",..."max":{"shardKey":MaxKey}})

             tag.min.shardKey = ObjectId()

             db.tags.save(tag)

             這樣前一天的資料就會被移動到其他分片上了。

             此策略的另一個缺點:需要修改才能進行擴充套件。如果寫請求超出了SSD的處理能力,無法進行負載均衡。

        4). 多熱點:寫請求分佈在叢集中時,分片是最高效的。這種技術會建立多個熱點(最好在每個分片上都建立幾個熱點),寫請求於是會均衡地分佈在叢集內,而在單個分片上則是以升序分佈的。

                        為了實現這種方式,需使用複合片鍵。複合片鍵中的第一個值只是比較粗略的隨機值,勢也比較低。

4. 片鍵規則和指導方針:

    1). 片鍵限制:片鍵不可以是陣列。文件一旦插入,其片鍵就無法修改了。要修改文件的片鍵值,就必須先刪除文件。

    2). 片鍵的勢:選擇一個值會變化的的鍵非常重要,即值很多,隨著資料量的增大可以分出更多的片鍵。分片在勢比較高的欄位上效能更佳。

5. 控制資料分發

    1). 對多個數據庫和集合使用一個叢集:通過tag標記,將重要的資料放到效能更好的伺服器上,將不重要的資料放在效能一般的伺服器上。

    2). 手動分片:如果不希望資料被自動分發,可以關閉均衡器,使用moveChunk命令手動對資料進行遷移。

分片管理

1. 檢查叢集狀態:

    1). 使用sh.status檢視叢集摘要資訊: 塊的數量比較多時,sh.status()命令會概述塊的狀態,而非打印出每個塊的相關資訊。如需檢視所有的塊,可使用sh.status(true)命令。

         sh.status()顯示的所有資訊都來自config資料庫。執行sh.status()命令,使用MapReduce獲取這一資料。因此,如果啟動資料庫時指定--noscripting選項,則無法執行sh.status()命令。

    2). 檢查配置資訊:

         a. 叢集相關的所有配置資訊都儲存在配置伺服器上config資料庫的集合中。可以直接訪問該資料庫,不過shell提供了一些輔助函式。

         b. 永遠不要直接連線到配置伺服器,以防止配置伺服器資料被不小心修改或刪除。應該先連線到mongos,然後通過config資料庫來查詢相關資訊:use config

             如果通過mongos操作配置資料,mongos會保證將修改同步到所有配置伺服器,也會防止危險的操作發生,如意外刪除config資料庫等。

         c. 總的來說,不應直接修改config資料庫中的任何資料。如果確實修改了某些資料,通常需要重啟所有的mongos伺服器,才能看到效果。

         d. config中幾個關鍵集合:

             shards : 跟蹤記錄叢集中所有分片的資訊。

             databases: 跟蹤記錄叢集中所有資料庫的資訊,不管資料庫有沒有分片。

             collections: 跟蹤記錄所有分片集合的資訊(非分片集合資訊除外)

             chunks: 記錄集合中所有塊的資訊。

             changelog: 跟蹤記錄叢集的操作,因為該集合會記錄所有拆分和遷移的操作。

             tags: 該集合的建立是在為系統配置分片標籤時發生的。每個標籤都與一個塊範圍相關聯。

             settings: 該集合含有當前的均衡器設定和塊大小的文件資訊。通過修改該集合的文件,可開啟和關閉均衡器,也可以修改塊的大小。注意,應總是連線到mongos修改該集合的值。

2. 檢視網路連線:

    1). 檢視連線統計:可以使用connPoolStats命令,檢視mongos和mongod之間的連線資訊:db.adminCommand({"connPoolStats":1})

                            在一個分片上執行connPoolStats,輸出資訊中可以看到該分片與其他分片間的連線,包括連線到其他分片做資料遷移的連線。

    2). 限制連線數量: 可在mongos的命令列配置中使用maxConns選項,這樣可以限制mongos能夠建立的連線數量。可以使用下面公式計算分片能夠處理的來自單一mongos連線數量:

                              maxConns = 20000 - (mongos程序的數量 * 3 ) - (每個副本集的成員數量 * 3 ) - (其他/mongos程序的數量)

                              MongoDB如果沒有安全退出,那些已經開啟的套接字很可能沒有被關閉。

                              在出現大量重新連線時,除了重啟程序,沒有其他特殊有效的方法。

3. 伺服器管理

    1). 新增伺服器:使用addShard命令,向叢集中新增新的分片

    2). 修改分片的伺服器:要修改分片的成員,需直接連線到分片的主伺服器上,然後對副本集進行重新配置。叢集配置會自動檢測更改,並將其更新到config.shards上。

    3). 通常來說,不應從叢集中刪除分片。執行removeShard命令排除資料和檢視排出進度。

    4). 修改配置伺服器:修改配置伺服器非常困難,而且有風險,通常還需要停機。注意,修改配置伺服器前,應做好備份。

                                首先必須關閉所有mongos程序,然後使用新的--configdb引數重啟所有mongos程序。

4. 資料均衡:

    1). 均衡器:均衡器只使用塊的數量,而非資料大小,作為衡量分片間是否均衡的指標。自動均衡總是根據資料集的當前狀態來決定資料遷移,而不考慮資料集歷史狀態。我們可以手動均衡資料集塊的數量。

    2). 修改塊的大小:塊的大小預設為64M,這個大小的塊既易於遷移,又不至於導致過多的流失。使用shell連線到mongos,修改config.setting集合,從而完成塊大小的修改。

          該設定的有效範圍是整個叢集:它會影響所有集合的資料庫。因此,如需對一個集合使用較小的塊,而對另一個集合使用較大的塊,比較好的解決方式是取一個折中值(或者將這兩個值放到不同的集合中)。

          如果MongoDB頻繁進行資料遷移或文件增大,則可能需要增加塊的大小。

    3). 遷移塊:同一塊內的所有資料都位於同一分片上。如該分片的塊數量比其他分片多,則MongoDB會將其中的一部分塊遷移到其他塊數量較少的分片上。移動快的過程叫遷移,MongoDB就是這樣在叢集中

         實現資料均衡的。可在shell中使用moveChunk輔助函式,手動移動塊。

         如果某個塊的大小超出了系統指定的最大值,mongos則會拒絕移動這個塊。移動之前必須先手動拆分這個塊,可以使用splitAt命令對塊進行拆分。特大塊,無法被拆分。

    4). 特大塊:某些片鍵,值比較少,例如:日期等。可能會形成超出設定的最大塊大小的塊,這種塊成為特大塊.

         出現特大塊的表現之一是,某個分片的大小增長速度要比其他分片塊的多。也可使用sh.status()來檢查是否出現了特大塊;特大塊會存在一個jumbo屬性。

         a. 分發特大塊,一個複雜的過程

         b. 防止特大塊的出現:修改片鍵,細化片鍵的粒度

    5). mongos有時無法從配置伺服器正確更新配置。如果發現配置有誤,mongos的配置過舊或無法找到應有的資料,可以使用flushRouterConfig命令手動重新整理所有快取:db.adminCommand({"flushRouterConfig":1})

         如flushRouterConfig命令沒能解決問題,則應重啟所有的mongos或者mongod程序,以便清除所有可能的快取。