<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          GRPC連接池的設(shè)計與實現(xiàn)

          共 3677字,需瀏覽 8分鐘

           ·

          2022-04-10 11:59

          本文介紹了Grpc連接池的設(shè)計,介紹了應(yīng)該如何配置連接池調(diào)優(yōu)。

          前言

          在分布式高并發(fā)服務(wù)器中,client到server以及server中的多個節(jié)點之間的連接往往使用連接池來管理。簡單來說就是將提前創(chuàng)建好的連接保存在池中,當(dāng)有請求到來時,直接使用連接池中的連接對server端訪問,省去了創(chuàng)建連接和銷毀連接的開銷(TCP建立連接時的三次握手和釋放連接時的四次揮手),從而提高了性能。

          目錄

          • 設(shè)計原則
          • 基本原理
          • GRPC特性
          • GRPC調(diào)優(yōu)
          • 實現(xiàn)細(xì)則
          • 延伸閱讀

          設(shè)計原則

          • 連接池的擴縮容
          • 空閑連接的超時與保活
          • 池滿的處理機制

          連接池的擴縮容

          通常連接池屬性包含最大空閑連接數(shù)和最大活躍連接數(shù)。

          最大空閑連接數(shù):連接池一直保持的連接數(shù),無論這些連接被使用與否都會被保持。如果客戶端對連接池的使用量不大,便會造成服務(wù)端連接資源的浪費。

          最大活躍連接數(shù):連接池最多保持的連接數(shù),如果客戶端請求超過次數(shù),便要根據(jù)池滿的處理機制來處理沒有得到連接的請求。

          擴容:當(dāng)請求到來時,如果連接池中沒有空閑的連接,同時連接數(shù)也沒有達(dá)到最大活躍連接數(shù),便會按照特定的增長策略創(chuàng)建新的連接服務(wù)該請求,同時用完之后歸還到池中,而不是關(guān)閉連接。

          縮容:當(dāng)連接池一段時間沒有被使用,同時池中的連接數(shù)超過了最大空閑連接數(shù),那么便會關(guān)閉一部分連接,使池中的連接數(shù)始終維持在最大空閑連接數(shù)。

          空閑連接的超時與保活

          超時?如果連接沒有被客戶端使用的話,便會成為空閑連接,在一段時間后,服務(wù)端可能會根據(jù)自己的超時策略關(guān)閉空閑連接,此時空閑連接已經(jīng)失效,如果客戶端再使用失效的連接,便會通信失敗。為了避免這種情況發(fā)生,通常連接池中的連接設(shè)有最大空閑超時時間(最好略小于服務(wù)器的空閑連接超時時間),在從池中獲取連接時,判斷是否空閑超時,如果超時則關(guān)閉,沒有超時則可以繼續(xù)使用。

          保活?如果服務(wù)器發(fā)生重啟,那么連接池中的連接便會全部失效,如果此時再從池中獲取連接,不論獲取到哪一個,都將通信失敗。因此,連接池必須考慮連接的保活問題,有兩種解決方法:

          1、連接池設(shè)置一個Ping函數(shù),專門用來做連接的保活。在從池中獲取連接的時候,Ping一下服務(wù)器,如果得到響應(yīng),則連接依然有效,便可繼續(xù)使用,如果超時無響應(yīng),則關(guān)閉該連接,生成新的連接,由于每次都要Ping一下,必然會增加延遲。也可以后臺用一個線程或者協(xié)程定期的執(zhí)行Ping函數(shù),進行連接的保活,缺點是感知連接的失效會有一定的延遲,從池中仍然有可能獲取到失效的連接。

          2、客戶端加入相應(yīng)的重試機制。比如重試3次,前兩次從池中獲取連接執(zhí)行,如果報的錯是失效的連接等有關(guān)連接問題的錯誤,那么第3次從池中獲取的時候帶上參數(shù),指定獲取新建的連接,同時連接池移除前兩次獲取的失效的連接。

          池滿的處理機制

          連接池不可能無限的容納連接,當(dāng)池滿時,有兩種處理機制:

          1、池新建連接,并返回給客戶端,當(dāng)客戶端用完時,如果池滿則關(guān)閉連接,否則放入池中。

          2、設(shè)置一定的超時時間來等待空閑連接。需要客戶端加入重試機制,避免因超時之后獲取不到空閑連接產(chǎn)生的錯誤。

          基本原理

          1. 服務(wù)啟動時建立連接池。
          2. 初始化連接池,建立最大空閑連接數(shù)個連接。
          3. 請求到來時,從池中獲取一個連接。如果沒有空閑連接且連接數(shù)沒有達(dá)到最大活躍連接數(shù),則新建連接;如果達(dá)到最大活躍連接數(shù),設(shè)置一定的超時時間,等待獲取空閑連接。
          4. 獲取到連接后進行通信服務(wù)。
          5. 釋放連接,此時是將連接放回連接池,如果池滿則關(guān)閉連接。
          6. 釋放連接池,關(guān)閉所有連接。

          GRPC特性

          關(guān)于GRPC的介紹,不在這里闡述,可閱讀深入了解GRPC協(xié)議,也可自行Google。這里主要簡要說明GRPC的兩個特性:多路復(fù)用、超時重連。

          多路復(fù)用GRPC使用HTTP/2作為應(yīng)用層的傳輸協(xié)議,HTTP/2會復(fù)用底層的TCP連接。每一次RPC調(diào)用會產(chǎn)生一個新的Stream,每個Stream包含多個Frame,F(xiàn)rame是HTTP/2里面最小的數(shù)據(jù)傳輸單位。同時每個Stream有唯一的ID標(biāo)識,如果是客戶端創(chuàng)建的則ID是奇數(shù),服務(wù)端創(chuàng)建的ID則是偶數(shù)。如果一條連接上的ID使用完了,Client會新建一條連接,Server也會給Client發(fā)送一個GOAWAY Frame強制讓Client新建一條連接。一條GRPC連接允許并發(fā)的發(fā)送和接收多個Stream,而控制的參數(shù)便是MaxConcurrentStreams,Golang的服務(wù)端默認(rèn)是100。

          超時重連我們在通過調(diào)用Dial或者DialContext函數(shù)創(chuàng)建連接時,默認(rèn)只是返回ClientConn結(jié)構(gòu)體指針,同時會啟動一個Goroutine異步的去建立連接。如果想要等連接建立完再返回,可以指定grpc.WithBlock()傳入Options來實現(xiàn)。超時機制很簡單,在調(diào)用的時候傳入一個timeout的context就可以了。重連機制通過啟動一個Goroutine異步的去建立連接實現(xiàn)的,可以避免服務(wù)器因為連接空閑時間過長關(guān)閉連接、服務(wù)器重啟等造成的客戶端連接失效問題。也就是說通過GRPC的重連機制可以完美的解決連接池設(shè)計原則中的空閑連接的超時與保活問題。

          以Golang的GRPC客戶端為例:

          GRPC調(diào)優(yōu)

          GRPC默認(rèn)的參數(shù)對于傳輸大數(shù)據(jù)塊來說不夠友好,我們需要進行特定參數(shù)的調(diào)優(yōu)。

          MaxSendMsgSizeGRPC最大允許發(fā)送的字節(jié)數(shù),默認(rèn)4MiB,如果超過了GRPC會報錯。Client和Server我們都調(diào)到4GiB。

          MaxRecvMsgSizeGRPC最大允許接收的字節(jié)數(shù),默認(rèn)4MiB,如果超過了GRPC會報錯。Client和Server我們都調(diào)到4GiB。

          InitialWindowSize基于Stream的滑動窗口,類似于TCP的滑動窗口,用來做流控,默認(rèn)64KiB,吞吐量上不去,Client和Server我們調(diào)到1GiB。

          InitialConnWindowSize基于Connection的滑動窗口,默認(rèn)16 * 64KiB,吞吐量上不去,Client和Server我們也都調(diào)到1GiB。

          KeepAliveTime每隔KeepAliveTime時間,發(fā)送PING幀測量最小往返時間,確定空閑連接是否仍然有效,我們設(shè)置為10S。

          KeepAliveTimeout超過KeepAliveTimeout,關(guān)閉連接,我們設(shè)置為3S。

          PermitWithoutStream如果為true,當(dāng)連接空閑時仍然發(fā)送PING幀監(jiān)測,如果為false,則不發(fā)送忽略。我們設(shè)置為true。

          實現(xiàn)細(xì)則

          代碼:https://github.com/shimingyah/pool

          基于GRPC的多路復(fù)用、超時重連特性,我們很容易實現(xiàn)GRPC連接池。

          接口設(shè)計

          提供簡潔的Pool和Conn的接口設(shè)計。

          連接復(fù)用

          GRPC是支持多路復(fù)用的,所以在設(shè)計GRPC池的時候和其他連接池區(qū)別之一是支持連接復(fù)用,通過MaxConcurrentStreams控制,默認(rèn)64。我們稱單個的GRPC為物理連接,復(fù)用的連接為邏輯連接。池的實際有效連接邏輯連接=物理連接?*?MaxConcurrentStreams

          擴縮容

          擴容初始化池的有效連接數(shù)(邏輯連接)為:最大空閑連接數(shù)?*?MaxConcurrentStreams,每一次請求都會對池的引用計數(shù)原子++,同時hash求取選取連接,當(dāng)引用計數(shù)超過邏輯連接數(shù)時,就需要進行擴容了,如果最大空閑連接沒有達(dá)到最大活躍連接數(shù),則按照double的方式擴容,如果達(dá)到了最大活躍連接數(shù),我們會根據(jù)Reuse參數(shù)的值來做進一步操作:如果為true,則繼續(xù)使用池中的連接,即使用的是物理連接的邏輯連接,關(guān)閉連接時,對引用計數(shù)原子--即可,如果為false,則新建連接,關(guān)閉連接時還需要對連接進行真正的Close。

          縮容如果池的引用計數(shù)為0時,便會觸發(fā)縮容操作,是連接維持到最大空閑連接數(shù)。

          超時保活

          基于GRPC的Keepalived特性,我們不需要自己實現(xiàn)保活機制,也無需關(guān)注連接池中的連接是否有效,因為就算失效,GRPC會自動重連的,此時只不過耗時會略微增加,即認(rèn)為除了服務(wù)器一直處于down狀態(tài)等原因,連接池中的連接是始終有效的。

          Tips

          • 由于使用hash求余,每個GRPC上并發(fā)的Stream可能會超過MaxConcurrentStreams。
          • 不同場景對應(yīng)的連接池配置也不一樣,需要根據(jù)自己的場景壓測得出連接池的最佳參數(shù)配置。
          • 該連接池適用于客戶端對消息順序沒有要求的場景;如果客戶端對消息順序要求嚴(yán)格,即同一個客戶端發(fā)送消息的順序必須和服務(wù)端接收消息的順序一致,那么便需要做消息的保序處理了,因為單個GRPC的消息是有序的,但是多個GRPC的消息就不一定有序了。可能需要引入一個會話層Session,可以對應(yīng)一條鏈接,也可以對應(yīng)一個連接池的多條鏈接,并且在該層實現(xiàn)消息的有序處理。

          轉(zhuǎn)自:zhuanlan.zhihu.com/p/104887882

          文章轉(zhuǎn)載:Go開發(fā)大全

          (版權(quán)歸原作者所有,侵刪)


          點擊下方“閱讀原文”查看更多

          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久精品国产青青草 | 精品欧美日韩视频在线 | 毛片88| 中国操逼免费看 | 内射视频福利 |