高併發系統設計40講之 池化技術

系統架構中,數據庫的連接時間比SQL的執行時間要長,
爲了提高效率,使用數據庫連接池將連接預先建立好

用連接池預先建立數據庫連接

數據庫連接池有兩個最重要的配置:最小連接數和最大連接數,它們控制着從連接池中獲取連接的流程:

  1. 如果當前連接數小於最小連接數,則創建新的連接處理數據庫請求;
  2. 如果連接池中有空閒連接則複用空閒連接;
  3. 如果空閒池中沒有連接並且當前連接數小於最大連接數,則創建新的連接處理請求;
  4. 如果當前連接數已經大於等於最大連接數,則按照配置中設定的時間(C3P0 的連接池配置是 checkoutTimeout)等待舊的連接可用;
  5. 如果等待超過了這個設定時間則向用戶拋出錯誤。

連接池故障:

  1. 數據庫的域名對應的 IP 發生了變更,池子的連接還是使用舊的 IP,當舊的 IP 下的數據庫服務關閉後,再使用這個連接查詢就會發生錯誤;
  2. MySQL 有個參數是“wait_timeout”,控制着當數據庫連接閒置多長時間後,數據庫會主動地關閉這條連接。這個機制對於數據庫使用方是無感知的,所以當我們使用這個被關閉的連接時就會發生錯誤。

如何保持連接池可用:

  1. 啓動一個線程來定期檢測連接池中的連接是否可用,比如使用連接發送“select 1”的命令給數據庫看是否會拋出異常,如果拋出異常則將這個連接從連接池中移除,並且嘗試關閉。目前 C3P0 連接池可以採用這種方式來檢測連接是否可用,也是我比較推薦的方式。
  2. 在獲取到連接之後,先校驗連接是否可用,如果可用纔會執行 SQL 語句。比如 DBCP 連接池的 testOnBorrow 配置項,就是控制是否開啓這個驗證。這種方式在獲取連接時會引入多餘的開銷,在線上系統中還是儘量不要開啓,在測試服務上可以使用。
用線程池預先創建線程

JDK 1.5 中引入的 ThreadPoolExecutor 就是一種線程池的實現,它有兩個重要的參數:coreThreadCount 和 maxThreadCount,它的執行原理和數據庫連接池類似
在這裏插入圖片描述
線程池中使用的隊列的堆積量也是我們需要監控的重要指標,尤其對於實時性要求比較高的任務。
如果你使用線程池請一定記住不要使用無界隊列。可能使用無界隊列後,任務就永遠不會被丟棄。但是大量的任務堆積會佔用大量的空間,一旦內存空間被佔滿就會頻繁的觸發full GC,造成服務不可用。

池化技術的核心思想是空間換時間,對於創建過程比較耗時的,統一放在一個池子裏管理,以達到提升性能和資源複用的目的。

存在的缺陷:
存儲池子中的對象肯定需要消耗多餘的內存,如果對象沒有被頻繁使用,就會造成內存上的浪費
池子中的對象需要在系統啓動的時候就預先創建完成,這在一定程度上增加了系統啓動時間

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章