資源池(從內存池到連接池)


 

在編程的世界里,經常會遇到連接池,那連接池到底是什么呢?

什么是池?

池,一種資源抽象的形象化說法。編程世界中的池是一組資源, 可以隨時使用, 但不隨時地創建和釋放。資源池(resource pool)被認為是一種設計模式,這里的資源主要是指系統資源, 這些資源不專屬於某個進程或內部資源。客戶端向池請求資源, 並使用返回的資源進行指定的操作。當客戶端使用完資源后, 會把資源放回池中而不是釋放或丟棄掉。

任何技術都有自己的應用邊界,

 

池作為一種資源使用技術,典型的使用情形是:

  • 當獲取資源的成本較高的時候
  • 當請求資源的頻率很高且使用資源總數較低的時候
  • 當面對性能問題,涉及到處理時間延遲的時候

池中的資源主要有兩類:

需要系統調用(system call) 的系統資源,或主演需要網絡通信的遠程資源, 如數據庫連接、套接字連接、線程和內存分配等等。

池中的資源一般不包括像字體庫或圖片等大的數據對象, 那些資源的存儲一般是通過是數據緩存或數據庫技術實現的。由於資源池的存在, 從池中獲取資源所需的時間變成了可預知的,從而在一定程度上解決性能的問題。

根據資源的類型,資源池一般包括連接池、線程池和內存池。

連接池

連接池是創建和管理一個網絡連接資源池的技術,這些連接一般預先准備好被任何需要它們的線程或者進程使用。網絡連接根據連接的生命周期可以粗略的分為兩種:長鏈接和短鏈接。

就web應用而言,短連接就是一般的http請求,長連接如websocket

短鏈接適合大部分應用。對於遠程方法的執行時間遠大於連接創建時間(看網絡情況大約為數毫秒)的時候,其連接創建時間可以被忽略,此時短連接策略基本不會有較大性能損失。另外,對於非頻繁調用火災對延遲時間不敏感的服務也適合使用短連接策略。

對於高並發或者高吞吐量的應用,網絡連接的創建消耗是很大的,對於這種應用應該使用長連接策略的連接池實現。

這里寫圖片描述

連接池中的幾個常用參數

在各種連接池的實現中,常用的參數一般有:連接數相關,連接時間相關,有效性相關。

連接數 
設計一個連接池,要確定池中的連接數量,包括最小空閑連接數,最大空閑連接數,連接池最大持有連接數。當然連接數可以變化,動態縮放,確定每次增加/減少的連接數量。

連接的有效性 
保證連接池中的連接有效性,相當於增加了連接心跳的檢測。同時,還有從池中獲取客戶端接口時的有效性,將客戶端接口歸還連接池時的有效性,當配置或實現了相關的管理服務,可以通過管理工具觀察連接池的使用情況。例如對於Java的應用,如果配置了JMX服務的話,可以通過JMX管理工具觀察Java連接池的狀態。

連接有效性測試可以減少長連接失效造成的遠程調用失敗,對於那些對連接失效而造成的調用失敗很敏感的服務,可以開啟各種合適的連接有效性測試策略來保障所取得的客戶端是連接正常的。

時間相關參數 
為了保持池中連接的有效性,空閑連接檢測時間也就是心跳間隔,這往往取決於業務使用連接池的場景。另外,還有從連接池中獲取連接的最大等待時間,一般地默認為-1,即無可用連接會拋出異常,當設為0時表示無窮大。

網絡通信連接池

網絡通信的連接池主要節省創建TCP連接的時間從而降低了請求的總處理時間。客戶端為每個服務端實例維護一個連接池。如果連接池中有空閑連接,則復用這個連接。如果連接池中沒有空閑連接,則會建立一個新的TCP連接或者等待池中出現空閑的連接。

當客戶端使用池中連接處理完一個請求時,如果連接池中的空閑連接數小於連接池的大小,則將當前使用的連接放入連接池。 如果連接池中的空閑連接數大於等於連接池的大小,則關閉當前使用的連接。

面向http短連接的連接池,服務端支持keepalive時才有效,如果服務端關閉keepalive,則效果等同於短連接,就沒有連接池的作用了。同理,如果連接池的大小設置為0,也等同於短連接的方式。服務端支持Keepalive的時候,可以減少CPU和內存的使用,允許請求和應答的HTTP管道化,減少了后續請求的延遲,報告錯誤也無需關閉TCP連接。

一般地,對於延遲敏感的業務,可以使用連接池機制。

數據庫連接池

開頭的例子是一個數據庫連接池。數據庫連接池也可以理解為維護數據庫連接的緩存, 以便在需要對數據庫的請求時可以重用連接。

這里寫圖片描述

為每個用戶打開和維護數據庫連接需要消耗大量的資源,而數據庫連接池用於提高數據庫中執行命令的性能,減少了用戶必須等待的時間。在數據庫連接池中, 創建連接后將其放入池中, 再次使用, 不必重新建立新的連接。如果所有的連接都被使用, 則創建新的連接並被添加到池中。

基於 web 的應用程序和企業應用程序一般都使用應用服務器來處理連接池。當頁面需要訪問數據庫時, 只需使用池中的現有連接, 並且只在池中沒有空閑連接的情況下建立新連接。這減少了連接到數據庫響應單個請求的開銷,需要頻繁訪問數據庫的本地應用程序也可以從數據庫連接池中受益。一些庫不僅實現了數據庫連接池還實現了相關的 SQL 查詢池, 簡化了數據庫操作密集型應中連接池的實現。Java中常用的數據庫連接池有:DBCP 、C3P0、BoneCP、Proxool、DBPool、XAPool、Primrose、SmartPool、MiniConnectionPoolManager及Druid等。

通過對連接池進行配置, 對最小連接、最大連接和空閑連接的數量加以限制, 可以優化在特定場景和特定環境中數據庫連接池的性能。

端上的連接池

由於互聯網尤其是廣域網中的速度非可控性,特別是移動互聯網(基於3G/4G)的速度的不確定性,在端上的應用也將連接池作為一種重要的技術手段。

以Chrome瀏覽器為例,其網絡庫采取連接池的方式管理連接的建立、分配以及釋放,當請求可以直接從連接池中獲取復用連接時,可以減少建立連接的時間消耗。除了websoket連接池之外,包含三種類型的連接池:

  • TransportClientSocketPool
  • SSLClientSocketPool
  • SOCKSClientSocketPool

其中TransportClientSocketPool為低層連接池,SSLClientSocketPool和SOCKSClientSocketPool為高層連接池,高層連接池包含低層連接池或其他高層連接池的對象,這三種連接池類可以組合出多種連接池對象。打開chrome://net-internals/#sockets 可以看到瀏覽器當前的連接狀態。

在app中,連接池同樣被廣泛采用主流的網絡通信庫都支持連接池,例如Okhttp。平台層也是如此,例如Android 平台中的binder 連接池。

這里寫圖片描述

線程池

在計算機編程中, 線程池是實現計算機程序中並發執行的軟件設計方式。線程池維護多個線程, 等待監督程序為並發執行分配任務。通過維護一個線程池, 可以提高性能, 避免執行延遲。可用線程的數量取決於程序可用的計算資源, 如並行處理器、核心、內存和網絡套接字。

一個常見的線程執行任務調度方法是同步隊列, 稱為任務隊列。池中的線程將等待任務從隊列中移除, 並在執行完成后將其放置到已完成的任務隊列中。線程池的大小是為執行任務而保留的線程數,通常是一個可調參數, 調整它可以以優化程序性能。

線程池對於為每個任務創建一個新線程的主要好處是線程創建和銷毀開銷僅限於初始創建池, 這可能導致更好的性能和更好的系統穩定性。通常情況下,創建和銷毀一個線程及其相關資源是一個費時的過程。然而, 池中的線程數量過多, 會浪費內存, 並且在可運行的線程之間切換上下文也可能會引發性能問題。一個socket連接到另一個網絡主機, 可能需要許多 CPU 周期, 可以將socket與在多個網絡事務中使用的線程聯系起來, 可以更有效地維護它。

根據等待任務的數量, 可以在應用程序的生存期間動態調整線程數。例如, 如果許多網頁同時發出請求的時候, web 服務器可以添加線程, 當請求逐漸減少時可以刪除線程。

線程池使用中需要注意的問題:

  • 創建太多的線程會浪費資源
  • 關注創建了但未使用的線程
  • 銷毀了大量線程后又花費較多的時間來重新創建它們
  • 創建線程過於緩慢可能導致客戶端性能變差
  • 銷毀線程過於緩慢可能會餓死其他的處理流程

內存池

內存池, 是使用池來進行內存管理, 使動態內存分配時達到 malloc 或者 new 的效果。由於內存碎片的存在,一個有效的方案是預先分配一些內存大小相同的內存塊,許多實時操作系統都適用了內存池。一種簡單的內存池實現如下圖所示: 
這里寫圖片描述

對於內存池的應用而言,可以通過以下方式分配、訪問和釋放內存:

  • 從池中分配內存時,函數將確定所需塊的池。如果該池的所有區塊已被保留,則該函數試圖在下一個較大的池中找到一個。分配的內存塊用句柄表示
  • 獲取分配內存的訪問指針
  • 釋放以前分配的內存塊

內存池將句柄划分為池索引、內存塊索引以及版本, 從而在內部解釋句柄。池和內存塊索引允許使用句柄快速訪問對應的塊, 而在每個新分配中增量的版本允許檢測已經釋放內存塊的句柄。

內存池允許使用恆定的執行時間來分配內存。數千個對象在池中的內存釋放只是一個操作, 而不是一個一個的Free。內存池也可以采用樹狀結構, 應用於特殊的編程行為, 如循環,遞歸等。固定大小的塊內存池不需要為每個塊分配元數據存儲, 不需要描述分配塊的大小等特性。

內存池還可用於對象, 在這種情況下,對象本身沒有外部資源, 只占用內存, 已經創建了的對象避免了對象創建時的內存分配。當對象創建成本較高時, 對象池是有用的, 但在某些情況下, 這種簡單的對象池可能並不有效, 實際上還可能會降低性能。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM