MongoDB 是一個基于分布式文件存儲的數(shù)據(jù)庫。由 C++ 語言編寫,一般生產(chǎn)上建議以共享分片的形式來部署。 但是MongoDB官方也提供了其它語言的客戶端操作API。如下圖所示: 提供了C、C++、C#、.net、GO、java、Node.js、PHP、python、scala等各種語言的版本,如下圖所示: MongoDB的操作分為同步操作和異步操作以及響應(yīng)式編程操作 官方JAVA API的路徑:https://docs./ecosystem/drivers/java/ 我們這里以3.11的java 版本為例。各個版本的API對MongoDB服務(wù)的支持情況。 使用API時,先引入maven依賴 <!-- https:///artifact/org.mongodb/mongo-java-driver --> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>3.11.1</version> </dependency>
1、關(guān)于MongoDB Client的初始化和關(guān)閉。 從官方介紹來看,一般建議Client只需要一個建立一個長連接實例,然后使用時,都使用這個實例就可以,也就是可以用java的單例模式來創(chuàng)建連接實例。
//mongoClient連接 protected static MongoClient mongoClient; public synchronized static MongodbClient getInstance(String mongodbUrl) { if (null == mongoClient) { mongoClient = MongoClients.create(mongodbUrl); if(null != mongoClient){ log.info("mongoClient init success!"); } else{ log.info("mongoClient init failed!"); } } return mongodbClient; }
直接通過mongodb的host和port來創(chuàng)建client: MongoClient mongoClient = MongoClients.create("mongodb://host1:27017"); client連接到一個 Replica Set: 本文作者:張永清,轉(zhuǎn)載請注明出處:MongoDB Java API操作很全的整理以及共享分片模式下的常見操作整理 MongoClient mongoClient = MongoClients.create("mongodb://host1:27017,host2:27017,host3:27017"); MongoClient mongoClient = MongoClients.create("mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplicaSet"); 或者通過MongoClientSettings.builder() 來輔助生成連接字符串來創(chuàng)建client: MongoClient mongoClient = MongoClients.create( MongoClientSettings.builder() .applyToClusterSettings(builder -> builder.hosts(Arrays.asList( new ServerAddress("host1", 27017), new ServerAddress("host2", 27017), new ServerAddress("host3", 27017)))) .build()); 連接關(guān)閉: public void close() { if(null!=mongoClient){ mongoClient.close(); mongoClient=null; } } 2、關(guān)于MongoDB 的基本操作 //創(chuàng)建Collection
public MongoDatabase getDatabase(String dataBaseName){ return mongoClient.getDatabase(dataBaseName); } public List<String> listCollectionNames(String dataBaseName){ 3、關(guān)于MongoDB 的查詢操作 //通過id(objectid)精確查詢 public FindIterable<Document> findMongoDbDocById(String dataBaseName, String collectionName, String id){ BasicDBObject searchDoc = new BasicDBObject().append("_id", id); return getCollectionByName(dataBaseName,collectionName).find(searchDoc); } //通過id(objectid)模糊查詢 public FindIterable<Document> findMongoDbDocByIdRegex(String dataBaseName, String collectionName, String id){ BasicDBObject searchDoc = new BasicDBObject().append("_id", new BasicDBObject("$regex",id)); return getCollectionByName(dataBaseName,collectionName).find(searchDoc); } //通過開始id和結(jié)束id 查詢(根據(jù)objectId范圍查詢) public FindIterable<Document> findMongoDbDocById(String dataBaseName, String collectionName, String startId,String endId){ BasicDBObject searchDoc = new BasicDBObject().append("_id", new BasicDBObject("$gte", startId).append("$lte", endId)); return getCollectionByName(dataBaseName,collectionName).find(searchDoc); } public FindIterable<Document> findMongoDbDoc(String dataBaseName, String collectionName,BasicDBObject basicDBObject){ return getCollectionByName(dataBaseName,collectionName).find(basicDBObject); } //限制查詢返回的條數(shù) public FindIterable<Document> findMongoDbDoc(String dataBaseName, String collectionName,BasicDBObject basicDBObject,Integer limitNum){ return findMongoDbDoc(dataBaseName,collectionName,basicDBObject).limit(limitNum) ; } public FindIterable<Document> findMongoDbDocById(String dataBaseName, String collectionName, String startId,String endId,Integer limitNum){ return findMongoDbDocById(dataBaseName,collectionName,startId,endId).limit(limitNum); } /** * 降序查詢(排序) * @param dataBaseName * @param collectionName * @param startId * @param endId * @param sortField 排序字段 * @return */ public FindIterable<Document> findMongoDbDocByIdDescSort(String dataBaseName, String collectionName, String startId,String endId,String sortField){ return findMongoDbDocById(dataBaseName,collectionName,startId,endId).sort(new Document().append(sortField, -1)); } public FindIterable<Document> findMongoDbDocByIdDescSort(String dataBaseName, String collectionName, String startId,String endId,String sortField,Integer limitNum){ return findMongoDbDocByIdDescSort(dataBaseName,collectionName,startId,endId,sortField).limit(limitNum); } /** * 降序查詢(排序) * @param dataBaseName * @param collectionName * @param startId * @param endId * @param sortField 排序字段 * @return */ public FindIterable<Document> findMongoDbDocByIdAscSort(String dataBaseName, String collectionName, String startId,String endId,String sortField){ return findMongoDbDocById(dataBaseName,collectionName,startId,endId).sort(new Document().append(sortField, 1)); } public FindIterable<Document> findMongoDbDocByIdAscSort(String dataBaseName, String collectionName, String startId,String endId,String sortField,Integer limitNum){ return findMongoDbDocByIdAscSort(dataBaseName,collectionName,startId,endId,sortField).limit(limitNum); } 4、關(guān)于MongoDB 的插入操作 //插入操作,注意插入時,如果數(shù)據(jù)已經(jīng)存在會報錯,插入時必須數(shù)據(jù)不存在,不會自動進(jìn)行覆蓋 //插入單條記錄 public void insertDoc(String dataBaseName, String collectionName, Document document){ getCollectionByName(dataBaseName,collectionName).insertOne(document); } //插入多條記錄 public void insertDoc(String dataBaseName, String collectionName,List<? extends Document> listData){ getCollectionByName(dataBaseName,collectionName).insertMany(listData); } 5、關(guān)于MongoDB 的更新操作 //更新單條 public void updateDoc(String dataBaseName, String collectionName, Bson var1, Bson var2){ getCollectionByName(dataBaseName,collectionName).updateOne(var1,var2); } public void updateDoc(String dataBaseName, String collectionName, Bson var1, List<? extends Bson> list){ getCollectionByName(dataBaseName,collectionName).updateOne(var1,list); } //批量更新 public void updateDocs(String dataBaseName, String collectionName, Bson var1, Bson var2){ getCollectionByName(dataBaseName,collectionName).updateMany(var1,var2); } public void updateDocs(String dataBaseName, String collectionName, Bson var1, List<? extends Bson> list){ getCollectionByName(dataBaseName,collectionName).updateMany(var1,list); } 6、關(guān)于MongoDB 的刪除操作 //單條刪除 public DeleteResult deleteDoc(String dataBaseName, String collectionName, Bson var1){ return getCollectionByName(dataBaseName,collectionName).deleteOne(var1); } //批量刪除 public DeleteResult deleteDocs(String dataBaseName, String collectionName,Bson var1){ return getCollectionByName(dataBaseName,collectionName).deleteMany(var1); } 7、關(guān)于MongoDB 的替換操作 本文作者:張永清,轉(zhuǎn)載請注明出處:MongoDB Java API操作很全的整理以及共享分片模式下的常見操作整理 //存在就替換,不存在的話就插入 public UpdateResult replaceDoc(String dataBaseName, String collectionName, Bson var1, Document var2,ReplaceOptions var3){ return getCollectionByName(dataBaseName,collectionName).replaceOne(var1,var2,var3); } public UpdateResult replaceDoc(String dataBaseName, String collectionName, Bson var1, Document var2){ return getCollectionByName(dataBaseName,collectionName).replaceOne(var1,var2); } //調(diào)用示例(設(shè)置存在就替換,不存在的話就插入) Document documentQuery = new Document("_id", docId); Document document = new Document("_id", docId); ReplaceOptions replaceOptions = new ReplaceOptions(); replaceOptions.upsert(true); String dataBaseName="zhangyonqing"; String collectionName="zhangyonqing"; replaceDoc(dataBaseName,collectionName,documentQuery,document,replaceOptions);
8、關(guān)于MongoDB 的bulkWrite操作?。ㄅ繉懭耄?/strong>,對于數(shù)據(jù)很多時,效率很高 public BulkWriteResult bulkWrite(String dataBaseName, String collectionName, List<? extends WriteModel<? extends Document>> listData){ return getCollectionByName(dataBaseName,collectionName).bulkWrite(listData); } 9、關(guān)于MongoDB 的分頁查詢 mongodb的分頁查詢可以有多種思路來實現(xiàn)。 思路一:采用類似mysql的limit start end 的這種。 獲取到總的數(shù)量: //查詢總數(shù) public long countDocs(String dataBaseName, String collectionName,Bson var1){ if(null==var1){ return getCollectionByName(dataBaseName,collectionName).countDocuments(); } return getCollectionByName(dataBaseName,collectionName).countDocuments(var1); } // 分頁查詢,采用skip+limit的方式,在用了總數(shù)后,就可以分頁了,skip的意思是前面跳過多少數(shù)據(jù)。但是這種方式在數(shù)據(jù)量大的時候效率不高,因為skip會導(dǎo)致全表掃描。 public FindIterable<Document> findMongoDbDoc(String dataBaseName, String collectionName,BasicDBObject basicDBObject,Integer skip,Integer limit){ return getCollectionByName(dataBaseName,collectionName).find(basicDBObject).skip(skip).limit(limit); } 思路二:利用limit 以及排序的方式,獲取分頁的上一頁的最后一條記錄的objectId,然后使用排序+$gte操作(大于)+limit 來獲取當(dāng)頁的數(shù)據(jù)。找到一個可以排序的字段,比如objectId或者時間字段都可以排序。這個也是mongodb官方推薦的方式,這種做飯可以避免全表掃描。 思路三:在數(shù)據(jù)量不大的時候,使用代碼進(jìn)行分頁。比如從mongodb中查詢出一個list對象后,對list對象做代碼分頁。 public class ListUtil { public static List getPagingList(List list,Integer start,Integer length){ start = start<0?0:start; //默認(rèn)為10 length = length<=0?10:length; Integer size = list.size(); if(start>size){ start = size; } Integer toIndex = (start+length-1)>=size?size:(start+length-1); if(toIndex<=0){ toIndex = size; } return list.subList(start,toIndex); }
二、異步操作API mongodb異步驅(qū)動程序提供了異步api,可以利用netty或java 7的asynchronoussocketchannel實現(xiàn)快速、無阻塞的i/o,maven依賴 <dependencies> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-async</artifactId> <version>3.11.1</version> </dependency> </dependencies> 官方地址:http://mongodb./mongo-java-driver/3.11/driver-async/getting-started/installation/ 異步操作必然會涉及到回調(diào),回調(diào)時采用ResultCallback<Document> 本文作者:張永清,轉(zhuǎn)載請注明出處:MongoDB Java API操作很全的整理以及共享分片模式下的常見操作整理 SingleResultCallback<Document> callbackPrintDocuments = new SingleResultCallback<Document>() { @Override public void onResult(final Document document, final Throwable t) { System.out.println(document.toJson()); } }; SingleResultCallback<Void> callbackWhenFinished = new SingleResultCallback<Void>() { @Override public void onResult(final Void result, final Throwable t) { System.out.println("Operation Finished!"); } }; 異步insert操作 collection.insertMany(documents, new SingleResultCallback<Void>() { @Override public void onResult(final Void result, final Throwable t) { System.out.println("Documents inserted!"); } }); 異步刪除操作 collection.deleteMany(gte("i", 100), new SingleResultCallback<DeleteResult>() { @Override public void onResult(final DeleteResult result, final Throwable t) { System.out.println(result.getDeletedCount()); } }); 異步更新操作 collection.updateMany(lt("i", 100), inc("i", 100), new SingleResultCallback<UpdateResult>() { @Override public void onResult(final UpdateResult result, final Throwable t) { System.out.println(result.getModifiedCount()); } }); 異步統(tǒng)計操作 collection.countDocuments( new SingleResultCallback<Long>() { @Override public void onResult(final Long count, final Throwable t) { System.out.println(count); } });
三、MongoDB Reactive Streams 操作API 官方的MongoDB reactive streams Java驅(qū)動程序,為MongoDB提供異步流處理和無阻塞處理。 完全實現(xiàn)reactive streams api,以提供與jvm生態(tài)系統(tǒng)中其他reactive streams的互操作,一般適合于大數(shù)據(jù)的處理,比如spark,flink,storm等。 <dependencies> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-reactivestreams</artifactId> <version>1.12.0</version> </dependency> </dependencies> 官方地址:http://mongodb./mongo-java-driver-reactivestreams/ 會包含如下三部分:
API問的地址:http://mongodb./mongo-java-driver-reactivestreams/1.12/javadoc/
代碼示例: //建立連接 MongoClient mongoClient = MongoClients.create(mongodbUrl); //獲得數(shù)據(jù)庫對象 MongoDatabase database = client.getDatabase(databaseName); //獲得集合 MongoCollection collection = database.getCollection(collectionName); //異步返回Publisher FindPublisher publisher = collection.find(); //訂閱實現(xiàn) publisher.subscribe(new Subscriber() { @Override public void onSubscribe(Subscription str) { System.out.println("start..."); //執(zhí)行請求 str.request(Integer.MAX_VALUE); } @Override public void onNext(Document document) { //獲得文檔 System.out.println("Document:" + document.toJson()); } @Override public void onError(Throwable t) { System.out.println("error occurs."); } @Override public void onComplete() { System.out.println("finished."); } }); 四、MongoDB 共享分片模式安裝 這里以mongodb4.2.0版本和操作系統(tǒng)CentOS Linux release 7.6.1810 (Core) 為例: 1、從官網(wǎng)下載mongodb-linux-x86_64-rhel7的安裝包。 分片模式安裝包括三部分:shard、config、router MongoDB分片模式下的架構(gòu)圖如下: (1)mongos :數(shù)據(jù)路由,和客戶端打交道的模塊。mongos本身沒有任何數(shù)據(jù),他也不知道該怎么處理這數(shù)據(jù),去找config server (2)config server:所有存、取數(shù)據(jù)的方式,所有shard節(jié)點的信息,分片功能的一些配置信息??梢岳斫鉃檎鎸崝?shù)據(jù)的元數(shù)據(jù)。 (3)shard:真正的數(shù)據(jù)存儲位置,以chunk為單位存數(shù)據(jù)。 Mongos本身并不持久化數(shù)據(jù),Sharded cluster所有的元數(shù)據(jù)都會存儲到Config Server,而用戶的數(shù)據(jù)會分散存儲到各個shard。Mongos啟動后,會從配置服務(wù)器加載元數(shù)據(jù),開始提供服務(wù),將用戶的請求正確路由到對應(yīng)的碎片。 Mongos的路由功能 當(dāng)數(shù)據(jù)寫入時,MongoDB Cluster根據(jù)分片鍵設(shè)計寫入數(shù)據(jù)。 當(dāng)外部語句發(fā)起數(shù)據(jù)查詢時,MongoDB根據(jù)數(shù)據(jù)分布自動路由至指定節(jié)點返回數(shù)據(jù)。 分片的主要目的: 高數(shù)據(jù)量和吞吐量的數(shù)據(jù)庫應(yīng)用會對單機的性能造成較大壓力,大的查詢量會將單機的CPU耗盡,大的數(shù)據(jù)量對單機的存儲壓力較大,最終會耗盡系統(tǒng)的內(nèi)存而將壓力轉(zhuǎn)移到磁盤IO上。 為了解決這些問題,有兩個基本的方法: 垂直擴展和水平擴展。 垂直擴展:增加更多的CPU和存儲資源來擴展容量。 水平擴展:將數(shù)據(jù)集分布在多個服務(wù)器上。水平擴展即分片。 分片設(shè)計思想:分片為應(yīng)對高吞吐量與大數(shù)據(jù)量提供了方法。使用分片減少了每個分片需要處理的請求數(shù),因此,通過水平擴展,集群可以提高自己的存儲容量和吞吐量。舉例來說,當(dāng)插入一條數(shù)據(jù)時,應(yīng)用只需要訪問存儲這條數(shù)據(jù)的分片,使用分片減少了每個分片存儲的數(shù)據(jù)。 分片的好處: 1.對集群進(jìn)行抽象,讓集群“不可見”: MongoDB自帶了一個叫做mongos的專有路由進(jìn)程。mongos就是掌握統(tǒng)一路口的路由器,其會將客戶端發(fā)來的請求準(zhǔn)確無誤的路由到集群中的一個或者一組服務(wù)器上,同時會把接收到的響應(yīng)拼裝起來發(fā)回到客戶端。 2.保證集群總是可讀寫: MongoDB通過多種途徑來確保集群的可用性和可靠性。將MongoDB的分片和復(fù)制功能結(jié)合使用,在確保數(shù)據(jù)分片到多臺服務(wù)器的同時,也確保了每分?jǐn)?shù)據(jù)都有相應(yīng)的備份,這樣就可以確保有服務(wù)器換掉時,其他的從庫可以立即接替壞掉的部分繼續(xù)工作。 3.使集群易于擴展: 當(dāng)系統(tǒng)需要更多的空間和資源的時候,MongoDB使我們可以按需方便的擴充系統(tǒng)容量。 2、部署shard,這里我們部署3個shard 創(chuàng)建shard1.config 配置文件,文件內(nèi)容: #數(shù)據(jù)路徑 dbpath=/data3/mongodb/data/shard1 #日志路徑 #是否后臺運行 創(chuàng)建shard2.config 配置文件,文件內(nèi)容: dbpath=/data1/mongodb/data/shard2 創(chuàng)建shard3.config 配置文件,文件內(nèi)容:
dbpath=/data1/mongodb/data/shard3 分別啟動上面的3個共享分片 啟動方式:mongod -f 配置文件對應(yīng)的路徑 mongod -f /opt/mongodb/mongodb-linux-x86_64-rhel70-4.2.0/shard/shard1.config mongod -f /opt/mongodb/mongodb-linux-x86_64-rhel70-4.2.0/shard/shard2.config mongod -f /opt/mongodb/mongodb-linux-x86_64-rhel70-4.2.0/shard/shard3.config 如果需要限制內(nèi)存的大小,可以在啟動參數(shù)后面增加--wiredTigerCacheSizeGB 0.2 ,這里的0.2 代表緩存的大小。 關(guān)于MongoDB緩存的介紹: With WiredTiger, MongoDB utilizes both the WiredTiger internal cache and the filesystem cache. Starting in MongoDB 3.4, the default WiredTiger internal cache size is the larger of either:
For example, on a system with a total of 4GB of RAM the WiredTiger cache will use 1.5GB of RAM ( By default, WiredTiger uses Snappy block compression for all collections and prefix compression for all indexes. Compression defaults are configurable at a global level and can also be set on a per-collection and per-index basis during collection and index creation. Different representations are used for data in the WiredTiger internal cache versus the on-disk format:
Via the filesystem cache, MongoDB automatically uses all free memory that is not used by the WiredTiger cache or by other processes. To adjust the size of the WiredTiger internal cache, see NOTE The To accommodate the additional consumers of RAM, you may have to decrease WiredTiger internal cache size. The default WiredTiger internal cache size value assumes that there is a single If you run To view statistics on the cache and eviction rate, see the 更多信息,可以參考http://docs./manual/faq/diagnostics/#memory-diagnostics-for-the-wiredtiger-storage-engine 3、部署config,這里我們部署1個config 創(chuàng)建mongo.config配置文件,文件內(nèi)容: dbpath=/data3/mongodb/config/data 啟動config :mongod -f 配置文件對應(yīng)的路徑 mongod -f /opt/mongodb/mongodb-linux-x86_64-rhel70-4.2.0/config/mongo.config 4、部署router,這里我們部署1個router 創(chuàng)建router.config配置文件,文件內(nèi)容: logpath=/opt/mongodb/mongodb-linux-x86_64-rhel70-4.2.0/router/logs/mongorouter.log 啟動router:mongos -f 配置文件對應(yīng)的路徑 mongos -f /opt/mongodb/mongodb-linux-x86_64-rhel70-4.2.0/router/router.config 5、 初始化shard server,配置每個shard的副本集 連接到每一臺共享分片 mongo 10.100.xx.xx:37017 備注有每個分片配置幾個副本集是可以自己選擇的,下面這個是配置1個副本集 rs.initiate({_id:"shard1RS",members:[{_id:1,host:"10.100.xx.xx:37017",priority:2},{_id:2,host:"192.168.xx.xx:37017"}]}) mongo 10.100.xx.xx:47017 rs.initiate({_id:"shard2RS",members:[{_id:1,host:"10.100.xx.xx:47017",priority:2},{_id:2,host:"192.168.xx.xx:47017"}]}) mongo 10.100.xx.xx:57017 rs.initiate({_id:"shard2RS",members:[{_id:1,host:"10.100.xx.xx:57017",priority:2},{_id:2,host:"192.168.xx.xx:57017"}]}) 6、 配置分片 通過路由連接到mongo:mongo 10.100.xx.xx:17017 連接成功后切換到admin模式:use admin 添加對應(yīng)的3個分片 db.runCommand({"addShard":"shard1RS/10.100.xx.xx:37017" ,"maxsize":1024}) db.runCommand({"addShard":"shard2RS/10.100.xx.xx2:47017" ,"maxsize":1024}) db.runCommand({"addShard":"shard3RS/10.100.xx.xx:57017" ,"maxsize":1024}) 判斷當(dāng)前是否是shard集群:db.runCommand({isdbgrid:1}); 查看分片的狀態(tài)信息:可用命令db.runCommand({listshards:1}) 7、 其他操作 刪除分片: use admin db.runCommand( { removeShard: "shard1RS" } ) 給集群新增用戶:
首先使用帶有“userAdmin”角色的用戶登錄集群,執(zhí)行如下命令
use admin
至此,就完成了新增一個用戶備份整個集群的用戶 給集群用戶新增權(quán)限: use admin db.grantRolesToUser( 查詢所有DB的分片存儲信息,包括chunks數(shù)、shard key信息: db.printShardingStatus() 獲取collection各個分片的數(shù)據(jù)存儲情況: db.collection.getShardDistribution() 顯示本mongos集群所有DB的信息, 包含了Shard Key信息: sh.status() 僅顯示分片: use config db.shards.find() balancer是sharded集群的負(fù)載均衡工具,新建集群的時候默認(rèn)開啟,除非你在config里把它關(guān)閉掉: db.settings.find() 手動啟動balancer: sh.startBalancer() 判斷當(dāng)前balancer是否在跑: sh.isBalancerRunning()
五、MongoDB 分片模式下如何選擇分片鍵 分片鍵shard key:MongoDB中數(shù)據(jù)的分片是以集合為基本單位的,集合中的數(shù)據(jù)通過片鍵(Shard key)被分成多部分。其實片鍵就是在集合中選一個鍵,用該鍵的值作為數(shù)據(jù)拆分的依據(jù)。 所以一個好的片鍵對分片至關(guān)重要。片鍵必須是一個索引,通過sh.shardCollection加會自動創(chuàng)建索引(前提是此集合不存在的情況下)。一個自增的片鍵對寫入和數(shù)據(jù)均勻分布就不是很好,因為自增的片鍵總會在一個分片上寫入,后續(xù)達(dá)到某個閥值可能會寫到別的分片。但是按照片鍵查詢會非常高效。 隨機片鍵對數(shù)據(jù)的均勻分布效果很好。注意盡量避免在多個分片上進(jìn)行查詢。在所有分片上查詢,mongos會對結(jié)果進(jìn)行歸并排序。 對集合進(jìn)行分片時,你需要選擇一個片鍵,片鍵是每條記錄都必須包含的,且建立了索引的單個字段或復(fù)合字段,MongoDB按照片鍵將數(shù)據(jù)劃分到不同的數(shù)據(jù)塊中,并將數(shù)據(jù)塊均衡地分布到所有分片中。 為了按照片鍵劃分?jǐn)?shù)據(jù)塊,MongoDB使用基于范圍的分片方式或者 基于哈希的分片方式。 注意:
以范圍為基礎(chǔ)的分片Sharded Cluster:Sharded Cluster支持將單個集合的數(shù)據(jù)分散存儲在多shard上,用戶可以指定根據(jù)集合內(nèi)文檔的某個字段即shard key來進(jìn)行范圍分片(range sharding)。
對于基于范圍的分片,MongoDB按照片鍵的范圍把數(shù)據(jù)分成不同部分。 假設(shè)有一個數(shù)字的片鍵:想象一個從負(fù)無窮到正無窮的直線,每一個片鍵的值都在直線上畫了一個點。MongoDB把這條直線劃分為更短的不重疊的片段,并稱之為數(shù)據(jù)塊,每個數(shù)據(jù)塊包含了片鍵在一定范圍內(nèi)的數(shù)據(jù)。在使用片鍵做范圍劃分的系統(tǒng)中,擁有”相近”片鍵的文檔很可能存儲在同一個數(shù)據(jù)塊中,因此也會存儲在同一個分片中。 基于哈希的分片:分片過程中利用哈希索引作為分片的單個鍵,且哈希分片的片鍵只能使用一個字段,而基于哈希片鍵最大的好處就是保證數(shù)據(jù)在各個節(jié)點分布基本均勻。
對于基于哈希的分片,MongoDB計算一個字段的哈希值,并用這個哈希值來創(chuàng)建數(shù)據(jù)塊。在使用基于哈希分片的系統(tǒng)中,擁有”相近”片鍵的文檔很可能不會存儲在同一個數(shù)據(jù)塊中,因此數(shù)據(jù)的分離性更好一些。 Hash分片與范圍分片互補,能將文檔隨機的分散到各個chunk,充分的擴展寫能力,彌補了范圍分片的不足,但不能高效的服務(wù)范圍查詢,所有的范圍查詢要分發(fā)到后端所有的Shard才能找出滿足條件的文檔。 分片鍵選擇建議:1、遞增的sharding key
2、隨機的sharding key
3、混合型key
分片注意: 分片鍵是不可變、分片鍵必須有索引、分片鍵大小限制512bytes、分片鍵用于路由查詢。 MongoDB不接受已進(jìn)行collection級分片的collection上插入無分片鍵的文檔(也不支持空值插入)、 數(shù)據(jù)庫開啟分片: 在共享分片模式下,創(chuàng)建完數(shù)據(jù)庫后,需要對數(shù)據(jù)庫開啟分片功能,并對數(shù)據(jù)庫下的表的字段指定分片算法 通過路由連接到mongoDb后,使用use admin 切換到admin模式。 開啟數(shù)據(jù)庫分片的命令:db.runCommand({"enablesharding":"數(shù)據(jù)庫名稱"}) ,例如對對庫hdctest開啟分片 :db.runCommand({"enablesharding":"hdctest"}) 對庫hdctest下的表person按字段ID配置hash分片算法 :db.runCommand({"shardcollection":"hdctest.person","key":{_id:'hashed'}}) 對庫hdctest下的表person按字段ID配置按照id升序或者降序配置分片算法(升序和降序 用1和-1表示): db.runCommand({shardcollection:"hdctest.person",key:{_id:1}}) 另外需要注意的是:對表中按照字段進(jìn)行分片時,需要預(yù)先創(chuàng)建索引才能配置分片算法(索引和分片算法保持一致,對id進(jìn)行分片,那么就對id創(chuàng)建索引)。 按照id升序索引:db.person.createIndex( {"_id": 1},{"name":'idx_id'}) 按照createTime 降序索引:db.person.createIndex( {"createTime": -1 },{"name":'idx_createTime'}) 六、MongoDB 如何創(chuàng)建索引 1.為普通字段添加索引,并且為索引命名 db.集合名.createIndex( {"字段名": 1 },{"name":'idx_字段名'}) 說明: (1)索引命名規(guī)范:idx_<構(gòu)成索引的字段名>。如果字段名字過長,可采用字段縮寫。 (2)字段值后面的 1 代表升序;如是 -1 代表 降序。
2.為內(nèi)嵌字段添加索引 db.集合名.createIndex({"字段名.內(nèi)嵌字段名":1},{"name":'idx_字段名_內(nèi)嵌字段名'})
3.通過后臺創(chuàng)建索引 db.集合名.createIndex({"字段名":1},{"name":'idx_字段名',background:true})
4:組合索引 db.集合名.createIndex({"字段名1":-1,"字段名2":1},{"name":'idx_字段名1_字段名2',background:true})
5.設(shè)置TTL 索引 db.集合名.createIndex( { "字段名": 1 },{ "name":'idx_字段名',expireAfterSeconds: 定義的時間,background:true} ) 說明 :expireAfterSeconds為過期時間(單位秒)
6.createIndex() 接收可選參數(shù)匯總
|
|