衝浪?在池中游泳
如果將互聯網應用比喻成衝浪的話, 可能需要先學會在池中游泳吧。
引子
AI賦能萬物,老碼農的夥伴們也曾經開發了一個基於圖資料庫的知識問答系統,在壓力測試的時候發現隨著並發數的增加,響應的時延明顯變長,看時延分布,是應用程序與圖資料庫之間的交互時延過長。結構不做調整,優化圖資料庫後,發現在並發量上來之後,效果仍不明顯。 看代碼,觀察ELK中的日誌,發現了問題所在————高並發時連接的創建時間較長。時間所限,替換為httpclient的連接池,post 和 get都採用池中的連接,性能問題迎刃而解。
在編程的世界裡,經常會遇到連接池,那連接池到底是什麼呢?
什麼是池
池,一種資源抽象的形象化說法。編程世界中的池是一組資源, 可以隨時使用, 但不隨時地創建和釋放。資源池(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為高層連接池,高層連接池包含低層連接池或其他高層連接池的對象,這三種連接池類可以組合出多種連接池對象。打開chrome://net-internals/#sockets 可以看到瀏覽器當前的連接狀態。
在app中,連接池同樣被廣泛採用,主流的網路通信庫都支持連接池,例如Okhttp。平台層也是如此,例如Android 平台中的binder 連接池。
線程池
在計算機編程中, 線程池是實現計算機程序中並發執行的軟體設計方式。線程池維護多個線程, 等待監督程序為並發執行分配任務。通過維護一個線程池, 可以提高性能, 避免執行延遲。可用線程的數量取決於程序可用的計算資源, 如並行處理器、核心、內存和網路套接字。
一個常見的線程執行任務調度方法是同步隊列, 稱為任務隊列。池中的線程將等待任務從隊列中移除, 並在執行完成後將其放置到已完成的任務隊列中。線程池的大小是為執行任務而保留的線程數,通常是一個可調參數, 調整它可以以優化程序性能。
線程池對於為每個任務創建一個新線程的主要好處是線程創建和銷毀開銷僅限於初始創建池, 這可能導致更好的性能和更好的系統穩定性。通常情況下,創建和銷毀一個線程及其相關資源是一個費時的過程。然而, 池中的線程數量過多, 會浪費內存, 並且在可運行的線程之間切換上下文也可能會引發性能問題。一個socket連接到另一個網路主機, 可能需要許多 CPU 周期, 可以將socket與在多個網路事務中使用的線程聯繫起來, 可以更有效地維護它。
根據等待任務的數量, 可以在應用程序的生存期間動態調整線程數。例如, 如果許多網頁同時發出請求的時候, web 伺服器可以添加線程, 當請求逐漸減少時可以刪除線程。
線程池使用中需要注意的問題:
內存池
內存池, 是使用池來進行內存管理, 使動態內存分配時達到 malloc 或者 new 的效果。由於內存碎片的存在,一個有效的方案是預先分配一些內存大小相同的內存塊,許多實時操作系統都適用了內存池。一種簡單的內存池實現如下圖所示:
對於內存池的應用而言,可以通過以下方式分配、訪問和釋放內存:
內存池將句柄劃分為池索引、內存塊索引以及版本, 從而在內部解釋句柄。池和內存塊索引允許使用句柄快速訪問對應的塊, 而在每個新分配中增量的版本允許檢測已經釋放內存塊的句柄。
內存池允許使用恆定的執行時間來分配內存。數千個對象在池中的內存釋放只是一個操作, 而不是一個一個的Free。內存池也可以採用樹狀結構, 應用於特殊的編程行為, 如循環,遞歸等。固定大小的塊內存池不需要為每個塊分配元數據存儲, 不需要描述分配塊的大小等特性。
內存池還可用於對象, 在這種情況下,對象本身沒有外部資源, 只佔用內存, 已經創建了的對象避免了對象創建時的內存分配。當對象創建成本較高時, 對象池是有用的, 但在某些情況下, 這種簡單的對象池可能並不有效, 實際上還可能會降低性能。
小結
池是一種資源共享和復用的技術,把管理的理念引入到編程世界中。從基礎的內存池,到線程池,再到各種連接池,根據應用場景還可以繼續細分,如句柄池,緩存池.....幾乎涵蓋了互聯網應用的大部分角落。如果將互聯網成衝浪的話, 可能需要先學會在池中游泳吧。
附記:
1)文中圖片來自網路,如若侵權,告知刪除
2)《深入分散式緩存》一書在京東斷貨後,現已第三次印刷,已有現貨,謝謝友人們的支持!


TAG:衝浪 |