分片集群
分片組件
為了能夠分擔數據庫的讀寫壓力,并且解決服務器的磁盤空間的利用情況,可以將數據分布到多臺服務器,并且每部分數據都存在副本來保證數據的高可用。實現這樣的一個架構稱作分片集群。一個分片集群有多個分片組成,并且每個分片都有一個或多個副本。每個分片都是一個獨立的副本集。分片集群的結構圖如下:
每個分片集群有三部分組成mongos、mongoconfig和mongodb。
mongos
mongos充當了路由器的角色,負責將客戶端的請求路由到分片,但是對于客戶端來說這是透明的。mongos為了提高操作數據的效率,會緩存一部分元數據。但是在mongos重啟或者新加入一個mongos或者有數據塊遷移,才會從配置服務器獲取元數據。
mongoconfig
配置服務器是一種特殊的mongod,它持有分片集群的元數據,這些元數據描述了分片系統的狀態和組織,以及數據庫數據的分布情況。
mongodb
mongodb是用來存儲數據的真正位置,數據庫的集合會按照一定的規則分配到多個分片上,每個分片上存儲的數據只是一個集合的子集,所有分片上的數據總和為整個數據庫的數據。
分片概述
分片鍵
每個集合在分片時,需要通過一個鍵來劃分,這個鍵是文檔中任何索引的單一或者符合字段。集合分片有兩種形式:基于范圍劃分和基于哈希值劃分。
基于范圍劃分
字段值在一定范圍的文檔會落在相同的分片上,例如用戶的首字母的范圍在[a,z],在按照范圍劃分后,[a,m]在分片1,(m,z]在分片2。但是也存在一定的缺點,在某一范圍的請求過多時,會導致分片的負載過大,使系統沒有得到正確的擴展。
基于哈希值的劃分
哈希劃分是根據每個字段值的哈希值分配到指定的片上。這樣就會保證即使字段值相近的文檔也不會存儲在同一個分片上。這樣就會保證數據均勻的分布在分片上,但是也會存在一定的缺點,在查詢一定范圍中的文檔時,效率會降低,因為一定范圍的文檔可能會存在于多個分片。
數據塊
通過分片鍵分割的集合組成一定大小的數據塊,這些數據塊的大小默認為64MB,例如現在有一個博文的帖子,該集合按照日期date進行分片,集合分布在3個分片上,分片1:從最早的時間到2009年7月,分片2:從2009年8月到2011年12月,分片3:從2012年1月到現在。
1、客戶端在查詢數據時,首先會訪問mongos。
2、mongos會查詢本地路由表,查找該數據存在于哪個分片,并將請求發送到分片3。
3、分片3會將結果返回給mongos,符合條件的數據可能在多個分片,mongos會將所有復合條件的數據合并后返回到客戶端。
在創建集合時,只有一個數據塊存在于一個分片中,數據塊的范圍為(-∞,+∞),隨著數據的不斷增多,會將數據按照一定的值進行分塊。
數據平衡過程
數據塊劃分
在數據的不斷增大,mongo會根據數據塊的大小隨時進行分塊,如果數據塊的大小大于64MB就行進行分塊,使數據塊保持在小于或者等于指定大小。插入和更新操作都會觸發劃分操作。劃分操作會導致配置服務器的元數據修改。
平衡器
數據塊的劃分可能會導致集群失衡,出現失衡的情況會觸發平衡器。當有一個分片上的數據庫多余其他分片,平衡器會將多余的數據塊,分配到其他平衡器上,保證每個分片上的數據塊相等。集群中的任何一個mongos都可以初始化平衡器程序,在完成數據塊從一個數據塊到另一個數據塊時,會導致配置服務器上元數據的變更,同時在平衡器移動數據庫時會對數據庫性能造成影響。所以在數據塊移動時分為兩種策略:
1、可以在達到一定閾值后,觸發平衡器。這個閾值標識分片上最大數量和最小數量之間的差值。
2、在指定的時間段內進行數據塊遷移。
數據遷移過程:
1、mongos會發送moveChunk命令到源分片。
2、源分片在接收到moveChunk命令后,會創建數據塊的文檔副本,并對副本進行排序。在此期間mongos接收到的客戶端請求都會繼續路由到源分片,。
3、目標分片開始從源分片接收數據副本。
4、一旦所有的數據接收完畢,就會開始初始化目標分片剛才遷移的數據,以保證在此期間產生的數據變更。
5、一旦同步完成,源分片上的數據就會刪除。
集群片鍵
片鍵的好與壞直接關系到整個集群的性能,片鍵的選擇可能會出現一下集中情況:
小基數片鍵
也就是說片鍵的值只有幾個可以存在,集群只能通過這幾個值進行分片。但是隨著文檔的不斷增加,分片上的數據不斷積累,由于字段值的數量有限,最終導致分片上的數據庫的大小不斷增大。也就是說一個鍵有N個值,那就只能有N個數據塊,因此也只能有N個分片。例如有一個集合中的每個文檔都有一個字段contient這個字段,這個字段只有7個值,Asia、Europe、North America、South America、Africa、Oceania和Antarctica。但是隨著數據的不斷增多包含7個值中的任何一個值的文檔都會不斷增大,從而導致每個數據塊也在不斷增大,這樣機會失去分片的意義。
升序片鍵
如時間戳作為片鍵,隨著數據的不斷增減,數據塊從一個分為兩個,但是對數據的插入都會坐落到第二個數據塊,當第二個數據塊達到一定的大小,就會再次分為兩個,同時新數據繼續做落到最后一個數據塊,該時間戳作為的片鍵為升序片鍵。
隨機片鍵
當某一個字段的取值是隨機的,那么當數據插入時,會隨機的分配到多個分片。雖然隨著數據的不斷增多,數據均勻的分布到分片集群,但是也會對數據庫的操作效率變低。
好片鍵
一個好的分片鍵既要保證良好的數據局部性也不會因為太局部而產生熱點。例如{coarselyAsecond:1,search:1}這樣的組合鍵來實現目標,coarselyAsecond字段對應多個數據塊,但是search會在對應的多個數據塊上搜索到指定的數據,也就是說coarselyAsecond字段對應局部數據,search字段是一個常用的檢索字段。
使用集群
查詢中的計數功能
在查詢復合某一條件的文檔數時,mongos會將請求發送到每個分片,并將查詢的結果合并后返回給客戶端。但是當有一個數據塊在移動時,數據可能存在于兩個分片,這樣在查詢的文檔坐落在兩個分片上時,查詢的結果可能大于實際的數量。這是mongo目前存在的一個問題,可能在以后的幾個版本得到解決。
唯一索引
在分片集群中存在各種索引,但是唯一索引除了分片鍵之外難以實現。例如文檔{"_id":ObjectId("89sw89d89cud8we8dw"),“userName”:"abc","email":"1121111111@qq.com"},在這個文檔中如果唯一索引是username,在插入文檔時搜索所有的分片沒有userName=abc的文檔,開始插入文檔,但是此時其他的客戶端也在插入userName=abc的文檔,并查詢每個分片時也沒有出現userName=abc的文檔并進行插入工作,兩個客戶端同時插入userName=abc的文檔就很難保證索引的唯一性。分片鍵能夠保證唯一性是因為每個文檔會按分片鍵值存儲在一個數據塊上。由此可以了解到,在插入文檔時,自動生成的id很難保證唯一性,除非id作為分片鍵。
更新
在按照條件進行更新操作時,如果條件不是分片鍵那么在進行更新時會多所有的分片進行查詢并執行更新操作,這樣會降低數據庫的效率。只有在使用分片鍵后,查詢會落在一個數據塊上。所以在更新數據時盡量帶有分片鍵作為條件,否則就會報錯。如果不帶有分片鍵,可以執行批量更新來避免報錯。
基于標簽分片
1、啟動分片集群,啟動的步驟為:啟動配置服務器,啟動路由服務器,啟動分片服務器。
2、將分片標記為標簽:sh.addShardTag("分片名稱1","標簽名稱1"),...,sh.addShardTag("分片名稱N","標簽名稱N")。
3、在某一集合上的所有數據塊都放在一個分片上:sh.addTagRange("集合1",{“字段1”:"MinKey"},{"字段1":MaxKey},"標簽名稱")
4、如果在此之前使用了分片鍵,將集合均勻的分布到多個分片,此時就會發生數據塊的移動。
使用標簽進行擴展
當集群中有三個標簽(dramas、actions、comedies),三個分片(shard0000、shard0001、shard0002),三個集合(movies.drama、movies.action、movies.comedy),對應結構如下:
現在需要將action分布在兩個分片上,而其他集合分布在兩外一個分片上。操作如下:
1、將標簽為dramas和comedies的標簽分布到shard0000分片上而actions分布到另外兩個分片上。sh.addShardTag("shard0000","comedies"),sh.removeShardTag("shard0002","comedies"),sh.addShardTag("shard0002","actions")。
2、在經過一段時間后,重新查看數據塊的分片會發現集合movies.drama和movies.comedy的數據塊全部存在于shard0000上,集合movies.action的數據塊存在于shard0001和shard0002上。
分片操作
?1、設置多個分片服務器,并且每個分片服務器都有多個從服務器。
分片1的primary節點的配置文件:
所在的服務器的ip為192.168.121.12
dbpath=/usr/local/mongodb01/data //數據存儲位置 logpath=/usr/local/mongodb01/logs //日志存儲位置 port=27020 //實例運行端口 fork=true //是否后臺運行 replSet=db0 //復制集的名稱 journal=true //否否開啟journal日志 bind_ip=0.0.0.0 //綁定的ip分片1的secondary節點的配置文件:
所在的服務器的ip為192.168.121.14
dbpath=/usr/local/mongodb01/data //數據存儲位置 logpath=/usr/local/mongodb01/logs //日志存儲位置 port=27019 //實例運行端口 fork=true //是否后臺運行 replSet=db0 //復制集的名稱 journal=true //否否開啟journal日志 bind_ip=0.0.0.0 //綁定的ip分片2的arbiter節點的配置文件:
所在的服務器的ip為192.168.121.12
dbpath=/usr/local/mongodb01/data //數據存儲位置 logpath=/usr/local/mongodb01/logs //日志存儲位置 port=27021 //實例運行端口 fork=true //是否后臺運行 replSet=db0 //復制集的名稱 journal=true //否否開啟journal日志 bind_ip=0.0.0.0 //綁定的ip設置分片1集群的配置:
rs.initiate({“_id:db0”,“members”:[{"_id":0,"host":"192.168.121.12:27020","priorty":"2"},{"_id":1,"host":"192.168.121.14:27019","priorty":"1"},{"_id":2,"host":"192.168.121.12:27021","priorty":"1","arbiterOnly" : true"}]})
2、將分片2和分片3按照分片1的操作設置為復制集。
每一個分片都是一個獨立的復制集,將所有的分片整合后就是整個mongo數據庫。
3、配置configure服務器
configure服務器與mongodb服務器沒有區別,數據庫中保存的數據為整個分片集群的配置信息。config服務器在3.2版本之后在配置時需要設置為復制集的模式。
configure服務器的primary節點配置:
所在的服務器ip為192.168.121.12
dbpath=/usr/local/mongocfg01/data //數據存儲位置 logpath=/usr/local/mongocfg01/logs //日志存儲位置 port=27018 //實例運行端口 fork=true //是否后臺運行 replSet=cfg0 //復制集的名稱 journal=true //否否開啟journal日志 bind_ip=0.0.0.0 //綁定的ipconfigure服務器的secondary節點配置:
所在服務器的ip為192.168.121.14
dbpath=/usr/local/mongocfg02/data //數據存儲位置 logpath=/usr/local/mongocfg02/logs //日志存儲位置 port=27018 //實例運行端口 fork=true //是否后臺運行 replSet=cfg0 //復制集的名稱 journal=true //否否開啟journal日志 bind_ip=0.0.0.0 //綁定的ipconfigure服務器的arbiter節點配置:
所在服務器的ip為192.168.121.12
dbpath=/usr/local/mongocfg03/data //數據存儲位置 logpath=/usr/local/mongocfg03/logs //日志存儲位置 port=27019 //實例運行端口 fork=true //是否后臺運行 replSet=cfg0 //復制集的名稱 journal=true //否否開啟journal日志 bind_ip=0.0.0.0 //綁定的ipconfigure服務器復制集的配置:
rs.initiate({“_id:db0”,“members”:[{"_id":0,"host":"192.168.121.12:27018","priorty":"2"},{"_id":1,"host":"192.168.121.14:27018","priorty":"1"}, {"_id":2,"host":"192.168.121.12:27019","priorty":"1","arbiterOnly" : true"}]})
4、配置mongos路由服務器
在配置路由服務器時,可以配置多個以此保證當其中一個服務器掛掉后,整個業務系統能夠正常運行。
配置內容如下:
路由服務器的ip為192.168.121.12和192.168.121.14
logpath=/usr/local/mongos01/logs port=27017 fork=true configdb=cfg0/192.168.121.12:27018,192.168.121.12:27019,192.168.121.14:27018 bind_ip=0.0.0.05、添加分片到集群
sh.addShard("db0/192.168.121.12:27020")
sh.addShard("db1/192.168.121.12:27022")
sh.addShard("db2/192.168.121.14:27021")
執行sh.status()發現所有的從節點也會主動加入到分片集群中。
6、啟動分片集群
啟動所有的配置服務器
啟動所有的路由服務器
啟動所有的分片服務器
7、添加一個新分片
設置新分片的復制集:primary節點為192.168.121.14:27023,secondary節點為192.168.121.12:27024,arbiter節點為192.168.121.14:27024
添加新分片到分片集群:db.addShard("db3/192.168.121.14:27024')
驗證是否添加成功,運行db.runCommand({listshards:1})
查看集合中文檔的數量,會發現結合數量在不斷增加,此時mongos在進行數據塊的平衡。
8、移除一個分片
在移除分片后,mongos會自動將該分片上的數據塊移除,然后才執行移除分片的命令。
執行移除分片的命令為:db.runCommand({removeShard:"192.168.121.14:27024"})
執行該命令后,經過一段時間,繼續執行移除分片的指令,返回的結果中有一個state字段,值為“ongoing”標識數據塊在遷移過程中,值為"complete"標識數據塊遷移完成。
可以執行listshards指令來查看分片集群中各個分片的狀態:db.runCommand({listshards:1}),就會發現移除的分片已經不再分片集群中。
9、創建數據庫并添加分片集合
首先在進群中創建數據庫eshop和集合users,并插入文檔,此時集合只在一個分片上存儲,因為沒有進行集合分片。
使數據庫支持分片:sh.enableSharding("eshop")
由于需要為分片集合提供分片鍵,并且分片鍵必須是索引,所以需要在分片鍵上創建索引:db.users.ensureIndex({city:1})。如果分片鍵是復合鍵,就需要創建復合索引。
為分片結合設置分片鍵:sh.shardCollection("eshop.users",{city:1})。
轉載于:https://www.cnblogs.com/youzhongmin/p/8306969.html
總結
- 上一篇: 仿抖音短视频系统源码,获取系统图片
- 下一篇: win10系统多台电脑无界共享键鼠软件