連接池居然這么簡(jiǎn)單?
精選?服務(wù)連接池,數(shù)據(jù)庫連接池,緩存連接池,連接池是微服務(wù)分層架構(gòu)中不可或缺的一個(gè)組件,本篇講講連接池的原理,以及實(shí)現(xiàn)細(xì)節(jié)。
通常如何通過連接訪問下游?
工程架構(gòu)中有很多訪問下游的需求,下游包括但不限于服務(wù)/數(shù)據(jù)庫/緩存,其通訊步驟是為:
- 與下游建立一個(gè)連接;
- 通過這個(gè)連接,收發(fā)請(qǐng)求;
- 交互結(jié)束,關(guān)閉連接,釋放資源;
不管是服務(wù)/數(shù)據(jù)庫/緩存,官方會(huì)提供不同語言的Driver、Document、DemoCode來指導(dǎo)使用方建立連接與調(diào)用接口。
以MongoDB的C++官方DriverAPI為例:
畫外音:建立連接、發(fā)送請(qǐng)求、關(guān)閉連接,都非常清晰。
這個(gè)DBClientConnection就是一個(gè)與MongoDB的連接,官方Driver通過它提供了若干API,讓用戶可以對(duì)MongoDB進(jìn)行連接,增刪查改,關(guān)閉的操作,從而實(shí)現(xiàn)不同的業(yè)務(wù)邏輯。
為什么需要連接池?
當(dāng)并發(fā)量很低的時(shí)候,連接可以臨時(shí)建立,但當(dāng)服務(wù)吞吐量達(dá)到幾百、幾千的時(shí)候,建立連接connect和銷毀連接close就會(huì)成為瓶頸,此時(shí)該如何優(yōu)化呢?
- 當(dāng)服務(wù)啟動(dòng)的時(shí)候,先建立好若干連接Array[DBClientConnection];
- 當(dāng)請(qǐng)求到達(dá)的時(shí)候,再從Array中取出一個(gè),執(zhí)行下游操作,執(zhí)行完放回;
從而避免反復(fù)的建立和銷毀連接,以提升性能。
而這個(gè)對(duì)Array[DBClientConnection]進(jìn)行維護(hù)的數(shù)據(jù)結(jié)構(gòu),就是連接池。
有了連接池之后,數(shù)據(jù)庫操作的偽代碼變?yōu)椋?/p>
畫外音:取出連接、發(fā)送請(qǐng)求、放回連接,也非常清晰。
連接池核心原理與實(shí)現(xiàn)是怎么樣的呢?
可以看到連接池ConnectionPool主要有三個(gè)核心接口:
- Init:初始化Array[DBClientConnection],這個(gè)接口只在服務(wù)啟動(dòng)時(shí)調(diào)用一次;
- GetConnection:請(qǐng)求每次需要訪問數(shù)據(jù)庫時(shí),不connect一個(gè)新連接,而是通過連接池的這個(gè)接口來拿連接;
- FreeConnection:請(qǐng)求每次訪問完數(shù)據(jù)庫時(shí),不是close一個(gè)連接,而是把這個(gè)連接放回連接池;
連接池核心數(shù)據(jù)結(jié)構(gòu)是怎樣的呢?
連接池至少包含兩個(gè)核心數(shù)據(jù)結(jié)構(gòu):
- 連接數(shù)組Array DBClientConnection[N];
- 互斥鎖數(shù)組Array lock[N];
連接池核心接口,是如何通過核心數(shù)據(jù)結(jié)構(gòu)的操縱,實(shí)現(xiàn)連接池功能的呢?
畫外音:把所有連接和互斥鎖初始化。
畫外音:找一個(gè)可用的連接,鎖住,并返回連接。
畫外音:找到連接,把鎖釋放。
會(huì)發(fā)現(xiàn),連接池管理核心并沒有想象的復(fù)雜。
除了核心代碼,連接池還需要考慮哪些因素呢?
- 需要實(shí)施連接可用性檢測(cè),如果有連接失效,需要重建連接;
- 通過freeArray,connectionMap等數(shù)據(jù)結(jié)構(gòu),可以讓取出連接和放回連接都達(dá)到O(1)時(shí)間復(fù)雜度;
- 可以通過hash取連接,實(shí)現(xiàn)id串行化;
- 每條連接被取到的概率必須相同,以實(shí)現(xiàn)負(fù)載均衡;
- 如果有下游故障,失效連接必須剔除,以實(shí)現(xiàn)故障自動(dòng)轉(zhuǎn)移;
- 如果有下游新增,需要?jiǎng)討B(tài)擴(kuò)充連接池,以實(shí)現(xiàn)服務(wù)自動(dòng)發(fā)現(xiàn);
思路比結(jié)論更重要,希望大家有收獲。?