自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

談談從連接池到內存池

開發(fā) 開發(fā)工具
AI賦能萬物,老碼農的伙伴們也曾經開發(fā)了一個基于圖數據庫的知識問答系統(tǒng),在壓力測試的時候發(fā)現隨著并發(fā)數的增加,響應的時延明顯變長,看時延分布,是應用程序與圖數據庫之間的交互時延過長。結構不做調整,優(yōu)化圖數據庫后,發(fā)現在并發(fā)量上來之后,效果仍不明顯。

 如果將互聯網應用比喻成沖浪的話, 可能需要先學會在“池”中游泳。

[[219789]]

引子

AI賦能萬物,老碼農的伙伴們也曾經開發(fā)了一個基于圖數據庫的知識問答系統(tǒng),在壓力測試的時候發(fā)現隨著并發(fā)數的增加,響應的時延明顯變長,看時延分布,是應用程序與圖數據庫之間的交互時延過長。結構不做調整,優(yōu)化圖數據庫后,發(fā)現在并發(fā)量上來之后,效果仍不明顯。 

看代碼,觀察ELK中的日志,發(fā)現了問題所在————高并發(fā)時連接的創(chuàng)建時間較長。時間所限,替換為httpclient的連接池,post 和 get都采用池中的連接,性能問題迎刃而解。

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

[[219790]]

什么是池

池,一種資源抽象的形象化說法。編程世界中的池是一組資源, 可以隨時使用, 但不隨時地創(chuàng)建和釋放。

資源池(resource pool)被認為是一種設計模式,這里的資源主要是指系統(tǒng)資源, 這些資源不專屬于某個進程或內部資源??蛻舳讼虺卣埱筚Y源, 并使用返回的資源進行指定的操作。當客戶端使用完資源后, 會把資源放回池中而不是釋放或丟棄掉。

任何技術都有自己的應用邊界,池作為一種資源使用技術,典型的使用情形是:

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

池中的資源主要有兩類:需要系統(tǒng)調用(system call) 的系統(tǒng)資源,或主演需要網絡通信的遠程資源, 如數據庫連接、套接字連接、線程和內存分配等等。池中的資源一般不包括像字體庫或圖片等大的數據對象, 那些資源的存儲一般是通過是數據緩存或數據庫技術實現的。由于資源池的存在, 從池中獲取資源所需的時間變成了可預知的,從而在一定程度上解決性能的問題。

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

連接池

連接池是創(chuàng)建和管理一個網絡連接資源池的技術,這些連接一般預先準備好被任何需要它們的線程或者進程使用。

網絡連接根據連接的生命周期可以粗略的分為兩種:長鏈接和短鏈接。就web應用而言,短連接就是一般的http請求,長連接如websocket。

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

對于高并發(fā)或者高吞吐量的應用,網絡連接的創(chuàng)建消耗是很大的,對于這種應用應該使用長連接策略的連接池實現。

 

連接池中的幾個常用參數

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

連接數

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

連接的有效性

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

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

時間相關參數

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

網絡通信連接池

網絡通信的連接池主要節(jié)省創(chuàng)建TCP連接的時間,從而降低了請求的總處理時間??蛻舳藶槊總€服務端實例維護一個連接池。如果連接池中有空閑連接,則復用這個連接。如果連接池中沒有空閑連接,則會建立一個新的TCP連接或者等待池中出現空閑的連接。

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

面向http短連接的連接池,服務端支持keepalive時才有效,如果服務端關閉keepalive,則效果等同于短連接,就沒有連接池的作用了。

同理,如果連接池的大小設置為0,也等同于短連接的方式。服務端支持Keepalive的時候,可以減少CPU和內存的使用,允許請求和應答的HTTP管道化,減少了后續(xù)請求的延遲,報告錯誤也無需關閉TCP連接。

一般地,對于延遲敏感的業(yè)務,可以使用連接池機制。

數據庫連接池

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

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

基于 web 的應用程序和企業(yè)應用程序一般都使用應用服務器來處理連接池。當頁面需要訪問數據庫時, 只需使用池中的現有連接, 并且只在池中沒有空閑連接的情況下建立新連接。這減少了連接到數據庫響應單個請求的開銷,需要頻繁訪問數據庫的本地應用程序也可以從數據庫連接池中受益。

一些庫不僅實現了數據庫連接池還實現了相關的 SQL 查詢池, 簡化了數據庫操作密集型應中連接池的實現。Java中常用的數據庫連接池有:DBCP 、C3P0、BoneCP、Proxool、DBPool、XAPool、Primrose、SmartPool、MiniConnectionPoolManager及Druid等。

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

端上的連接池

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

[[219792]]

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

  • TransportClientSocketPool
  • SSLClientSocketPool
  • SOCKSClientSocketPool

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

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

線程池

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

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

線程池對于為每個任務創(chuàng)建一個新線程的主要好處是線程創(chuàng)建和銷毀開銷僅限于初始創(chuàng)建池, 這可能導致更好的性能和更好的系統(tǒng)穩(wěn)定性。通常情況下,創(chuàng)建和銷毀一個線程及其相關資源是一個費時的過程。

然而, 池中的線程數量過多, 會浪費內存, 并且在可運行的線程之間切換上下文也可能會引發(fā)性能問題。一個socket連接到另一個網絡主機, 可能需要許多 CPU 周期, 可以將socket與在多個網絡事務中使用的線程聯系起來, 可以更有效地維護它。

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

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

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

內存池

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

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

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

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

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

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

小結

池是一種資源共享和復用的技術,把管理的理念引入到編程世界中。從基礎的內存池,到線程池,再到各種連接池,根據應用場景還可以繼續(xù)細分,如句柄池,緩存池.....幾乎涵蓋了互聯網應用的大部分角落。如果將互聯網成沖浪的話, 可能需要先學會在池中游泳吧。

【本文來自51CTO專欄作者“老曹”的原創(chuàng)文章,作者微信公眾號:喔家ArchiSelf,id:wrieless-com】

戳這里,看該作者更多好文

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2019-12-30 15:30:13

連接池請求PHP

2011-06-01 13:54:10

MySQL

2020-06-04 12:15:37

Go內存池對象池

2009-09-22 16:04:50

Hibernate連接

2009-09-22 14:52:55

Hibernate p

2022-11-11 09:41:04

連接池微服務數據庫

2009-06-17 16:22:45

Hibernate連接

2009-11-12 08:59:18

ADO.NET數據庫連

2009-07-15 11:00:48

proxool連接池

2010-06-25 10:36:27

Java連接池

2015-04-27 09:50:45

Java Hibern連接池詳解

2009-06-17 09:59:46

Hibernate 連

2020-02-03 15:15:27

Druid連接池性能超出競品

2009-12-25 15:38:12

ADO連接池

2024-12-04 15:55:19

2009-06-24 07:53:47

Hibernate數據

2022-07-19 13:51:47

數據庫Hikari連接池

2009-08-24 15:48:53

Java連接池

2010-01-04 16:24:07

ADO連接池

2010-05-17 16:38:08

MySQL 連接池
點贊
收藏

51CTO技術棧公眾號