生活随笔
收集整理的這篇文章主要介紹了
mongo连接分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
摘要
在前面的文章中有分析過關系型數據庫的連接,以及連接池的原理。在mongo數據庫同樣存在,經常看到有網友在問mongo 連接了數據庫要不要關,怎么關。內置的數據庫連接池是單線程還是多線程,mongo服務器為什么會殺游標,殺連接諸如此類的問題,其實這類問題基本上就是連接池的問題,而很多和關系型數據庫是類似的,并不是mongo獨有的。
本文旨在梳理這些問題,進行一個全面的分析。
Client 連接分析
客戶端連接通過driver jar去連接,以java為例,通過mongo-java-driver
連接mongo,這一點和關系型數據庫一樣,不同的是關系型數據庫有一套標準的阻塞型的,寫入JDK的數據庫操作實現,即JDBC。而mongo則是完全有driver提供。在mongo-java-driver 3.0版本之前只提供了同步的driver操作,3.x之后開始提供異步的driver操作,這邊不做擴散,后續會有相關博文介紹異步的數據庫操作,本文只介紹同步driver操作。
數據庫操作
一個基于mongo-java-driver-2.14.x的mongo操作流程
public static void main(final String[] args) {try {final String host = "localhost";// 連接配置屬性final MongoClientOptions clientOptions = new MongoClientOptions.Builder().writeConcern(WriteConcern.ACKNOWLEDGED).readPreference(ReadPreference.secondaryPreferred()).connectionsPerHost(10).socketTimeout(5000).build();final List<MongoCredential> credentialsList = new ArrayList<MongoCredential>();final String str = "test";final char[] psd = str.toCharArray();final MongoCredential credential = MongoCredential.createCredential("test","test",psd);credentialsList.add(credential);final ServerAddress address = new ServerAddress(host, 27017);//包含了一個內置的數據庫連接池final MongoClient client = new MongoClient(address, credentialsList, clientOptions);final DB db = client.getDB("test");final DBCollection postCollection = db.getCollection("test");postCollection.findOne();//連接關閉,釋放資源client.close();} catch (final UnknownHostException e) {e.printStackTrace();}}
這只是一個sample 實際應用中,MongoClient在一個jvm中只應該有一個實例,由他管理連接,進行數據庫操作。
client與數據庫的交互,mongo 協議也是基于TCP的
幾個重要的類
MongoClientOptions: 數據庫連接配置項
DB: database連接
DBCollection: collection操作
所以mongo連接的配置核心就在于MongolientOptions類了。比較重要的配置就是
connectionsPerHost,對于線上環境,如果連接數據庫的應用比較多,這個連接數不宜過大
socketTimeout: 數據庫操作超時時間,一般5s中,對于慢操作,不應該一直占用連接,會損害應用性能,阻塞其他操作
private int minConnectionsPerHost; //每個節點的最小連接數 private int connectionsPerHost = 100; // 每個節點的連接數private int threadsAllowedToBlockForConnectionMultiplier = 5; //最大等待線程private int maxWaitTime = 1000 * 60 * 2; // 獲取連接最大等待時間private int maxConnectionIdleTime; // 連接池最大空閑時間private int maxConnectionLifeTime;private int connectTimeout = 1000 * 10; // 連接最大時間private int socketTimeout = 0; // 操作最大時間private boolean socketKeepAlive = false;private boolean autoConnectRetry = false;private long maxAutoConnectRetryTime = 0;// 心跳檢測,保持TCP連接private int heartbeatFrequency = Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalMS", "5000"));private int minHeartbeatFrequency = Integer.parseInt(System.getProperty("com.mongodb.updaterIntervalNoMasterMS", "500"));private int heartbeatConnectTimeout = Integer.parseInt(System.getProperty("com.mongodb.updaterConnectTimeoutMS", "20000"));private int heartbeatSocketTimeout = Integer.parseInt(System.getProperty("com.mongodb.updaterSocketTimeoutMS", "20000"));
可以和關系型數據庫連接池的實現對比一下
initialSize:初始連接數
maxActive: 最大連接數量
minIdle: 最小連接數量
maxWait: 獲取連接最大等待時間ms
minEvictableIdleTimeMillis:連接保持空閑而不被驅逐的最小時間
timeBetweenEvictionRunsMillis:銷毀線程的時間檢測
testOnBorrow:申請連接時執行,比較影響性能
validationQuery:testOnBorrow為true檢測是否是有效連接sql
testWhileIdle:申請連接的時候檢測
mongo 內置的連接池管理比較簡單,沒有進行連接池的連接有效管理,通過heartbeat間隔一段時間發送數據包給mongo 服務器,確保連接有效,這一點和之前介紹的有點區別,之前的銷毀掉無用的連接。這樣會增加額外的網絡和CPU負擔。
看下mongo 創建MongoClient的時候會去初始化連接池。等到進行數據庫操作的時候,再去PooledConnectionProvider中獲取一個連接,進行操作
總結
通過以上分析,對于mongo driver 3.x 以下的mongo數據庫連接池與關系型數據庫連接池并無區別。只是連接池的實現方式不一樣,比如一個用鎖,一個用信號量。容器的選型也不太一樣,但是這些并不會影響到大部分的應用開發者對于連接的配置和理解?;氐介_頭提出的幾個問題,看到這里自然就有答案了。而對于服務器kill掉游標這個問題,游標本身也不是mongo獨有的,客戶端通過游標控制結果數量的讀取,游標本身也是占用不少資源的,所以不能一直占有,服務器kill掉游標,所以游標占用時間太長??梢酝ㄟ^db.serverStatus().metrics.cursor去查看timeout的游標,找出耗時操作,進行優化。
"cursor": {
"timedOut": "NumberLong(99)"
"open": {
"noTimeout": "NumberLong(0)"
"pinned": "NumberLong(3)"
"total": "NumberLong(3)"
}
}
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的mongo连接分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。