
????我從沒有深入了解過數(shù)據(jù)庫連接池,我一直都把它當著理解幽靈引用(phantom reference)的一個示例。我參與的大部分項目里,數(shù)據(jù)庫連接池都已經(jīng)包含在我們選擇的框架里??偠灾?,對很多系統(tǒng)而言,數(shù)據(jù)庫連接池是一個必要的組件,但是它被你用來和數(shù)據(jù)庫交互的對象關(guān)系管理器(object-relational manager)所隱藏,對你而言是不可見的。
????后來,我在Stack Overflow上回答了這個問題。為了回答這個問題,我特地把玩了一下數(shù)據(jù)庫連接池,寫了一個更長的答案。然后我意識到一個問題,數(shù)據(jù)庫連接池,哪怕是最新的實現(xiàn),都把目前最新的數(shù)據(jù)庫管理的最佳實踐給包含進去。其中兩個特別重要的,就是:
- 數(shù)據(jù)庫的憑證需要處理: 我所用過的所有連接池都需要你在配置文件里填寫數(shù)據(jù)庫憑證,也就是用戶名和密碼。這也就意味著,對一個有安全意識的開發(fā)人員,你需要從某個地方獲取這個配置,然后加入到配置文件里?;蛘?,對于一個沒有安全意識的開發(fā)人員,直接將它們明文存儲在一個文本文件里。不管是那個場景,你都是做一次配置,也就是在應用啟動的時候。如果需要修改的話,你需要重啟應用。這樣的話,定期更新憑證就變得比較麻煩了,因為你需要定期更新憑證來避免因為它們被泄露而導致的問題。一種極端的場景就是,Amzon的RDS支持每15分鐘更新一次憑證。但是,即使你的憑證是一個月更新一次,但是你還是需要重啟所有的服務,這樣的話,這個簡單的操作就變成了一個大的應用變更,而且只能手動操作,并且會增加應用的宕機時間(downtime)。
- 故障恢復不重要:較早的時候,從主機切到備機來進行故障恢復是一個大事件,往往需要一個多人的電話會議,然后手動進行操作。即使是最簡單的情況下,你也需要把一臺備機切成主機,不過使用基于日志的異步同步策略,總還是會有數(shù)據(jù)丟失的可能性。而且,隨著集群式的數(shù)據(jù)庫(例如Amazon Aurora)的不斷增加,故障恢復可能會在我們不知道的情況下自動進行。如果我們的應用沒法感知到當前是處于故障恢復期間的一個時間段的話,那么就會有問題了。
????一個針對以上兩個問題的解決方案是給連接池添加一個鉤子,用來調(diào)用用戶自定義的代碼,然后獲取需要的信息。例如,對于從靜態(tài)文件里讀取用戶名和密碼的方式,可以替換成調(diào)用一個用戶自定義的函數(shù)讀取文件來獲取。
????然后就沒問題了,但是這也讓我想到了另外一個問題:實際上最根本的問題在于連接池在嘗試解決兩個不同的問題。第一個問題是管理連接池:創(chuàng)建連接,保持連接,銷毀連接,如果應用沒有主動關(guān)閉的話,還要對連接進行回收,并且要做到對性能的影響減到最少。第二個問題是建立連接,這個問題隨著使用的數(shù)據(jù)庫不同,會稍微有所變化。
????我認為數(shù)據(jù)庫連接池演進的下一個階段就是把這些操作進行分離,然后連接池管理的代碼會分解成一個可以自由搭配和組合的組件棧。對于有些人可能需要一個MySQL連接池的工廠(factory),然后需要使用IAM憑證提供者(provider),以及需要一個在每次獲取連接之后,一旦發(fā)現(xiàn)連接是只讀的,就拋出異常的檢查策略(connection check)。另外一些人可能需要一個Postgresql的連接池工廠(factory),使用一個基于環(huán)境的憑證提供者(provider),而且只需要基本的連接檢查(connection check)即可。
????這里比較棘手的一個問題就是如何設(shè)計接口。我不認為我剛剛所提到的分成三部分的方式是正確的。但是我能肯定的是,僅僅重寫javax.sql.DataSource肯定是不夠的。除此之外,哪怕API已經(jīng)設(shè)計好了,實現(xiàn)它也是需要很大的工作量的,但是我想還是能夠找到很多人來參與貢獻代碼的。
那么最后的問題就是:有沒有哪個數(shù)據(jù)庫連接池的維護者跟我有相似的想法,并且愿意做這樣的拆分呢?