RPC中間件解決方案
RPC中的服務(wù)治理
RPC的基礎(chǔ)是網(wǎng)絡(luò)通信+序列化,只是基本的實現(xiàn),其上還有更多其他治理問題,也是分布式中的普遍問題。
序列化
序列化框架的性能、內(nèi)存、數(shù)據(jù)大小以及兼容性
服務(wù)發(fā)現(xiàn)
zookeeper
管理端創(chuàng)建服務(wù)根目錄
服務(wù)提供方在provider目錄下創(chuàng)建臨時節(jié)點,儲存生產(chǎn)者的信息
服務(wù)消費方在consumer目錄下創(chuàng)建臨時節(jié)點,儲存消費方的信息
消費方watch生產(chǎn)者目錄,當(dāng)生產(chǎn)者節(jié)點發(fā)生變化時得到通知
最終一致性
zk的cp特性會帶來性能問題,在大規(guī)模的服務(wù)發(fā)現(xiàn)中,AP才是王道。
如使用注冊中心收到注冊消息后,將消息投入到消息總線中來同步到其他注冊中心,或如erureka中的通過定時任務(wù)來進(jìn)行同步。
這種方式要注意消息的去重,同步消息要附帶單調(diào)遞增的版本號,其他注冊中心只接受版本號更高的更新消息。
推拉模式結(jié)合,推主要是callback,拉是客戶端輪訓(xùn)
健康監(jiān)測
服務(wù)發(fā)現(xiàn)拿到的實例有可能是不可用的。
需要加入健康監(jiān)測機(jī)制如心跳機(jī)制,來評估節(jié)點的健康狀態(tài),如健康、亞健康(連續(xù)幾次心跳失?。?、不可用狀態(tài)(連接失?。7?wù)調(diào)用時優(yōu)先使用健康節(jié)點。
同時為了防止成功失敗間斷出現(xiàn)且連續(xù)次數(shù)不達(dá)到閾值,從而出現(xiàn)誤判情況,需要使用其他維度的方式進(jìn)行計算健康度,如eureka中的30秒內(nèi)失敗次數(shù)這種在一段時間窗口范圍內(nèi)的失敗次數(shù)作為可用率來衡量。
同時健康監(jiān)測可能也要監(jiān)控服務(wù)自己的其他依賴是否可用,如服務(wù)雖然可用,但其redis可能掛了。目前sc中是使用actuator的health端點來監(jiān)控總體的健康水平
路由策略
調(diào)用者在挑選服務(wù)提供方時,加入篩選邏輯。如流量切換和灰度發(fā)布的場景,使用路由策略將舊應(yīng)用的流量緩慢平滑的切入到新應(yīng)用,完成后下線舊應(yīng)用。
將選擇做成配置進(jìn)行動態(tài)下發(fā)。
負(fù)載均衡
配置權(quán)重來控制不同機(jī)器的流入流量,如果在發(fā)現(xiàn)可用性降低后再去調(diào),已經(jīng)影響到了業(yè)務(wù),最好提前智能的控制權(quán)重。
如果使用負(fù)載均衡設(shè)備,會有以下問題:
負(fù)載均衡設(shè)備的單點問題,如果是集群則大規(guī)模的上下線和擴(kuò)容帶來運維復(fù)雜
額外的負(fù)載均衡設(shè)備成本
額外的網(wǎng)絡(luò)代理訪問
負(fù)載均衡策略統(tǒng)一,無法根據(jù)不同場景靈活配置不同策略
所以RPC需要自己來實現(xiàn)負(fù)載均衡
常用的算法如輪訓(xùn)、隨機(jī)、哈希、權(quán)重等。
自適應(yīng):設(shè)置指標(biāo)收集器實時收集提供方的負(fù)載信息(可以通過心跳收集)以及服務(wù)調(diào)用的各種如延時等指標(biāo),綜合打分,來智能負(fù)載均衡。
路由和均衡的區(qū)別一般是根據(jù)路由設(shè)定的規(guī)則篩選出一批提供者,然后使用均衡算法進(jìn)行均衡調(diào)用。
異常重試
RPC走網(wǎng)絡(luò),所以必定需要異常重試,但時間和次數(shù)必須把握好。太長會hang住業(yè)務(wù),太短會誤判導(dǎo)致數(shù)據(jù)不一致。同時注意重試一般要剔除上次異常的節(jié)點,且重試時要重置超時時間。
但是要注意由于網(wǎng)絡(luò)抖動,rpc接口一般要求冪等,此時異常重試才是有意義的,否則反而可能造成重大問題。同時并不是所有的異常都可以重試,有些異常是業(yè)務(wù)拋出來的具有特定意義的,不能重試。可以配置白名單,特定的異常才允許重試。
優(yōu)雅啟停
提供方要下線時,調(diào)用方不知道,可能造成影響。
提供方下線時像注冊中心進(jìn)行下線操作,然后注冊中心下發(fā)到各消費方,從而剔除下線節(jié)點,但由于最終一致性的問題,消費方可能無法及時的拿到提供方的下線消息。
一種方法時提供方主動通知所有調(diào)用方,因為服務(wù)費持有調(diào)用方的長鏈接,遍歷調(diào)用告知下線即可,但可能存在問題,如調(diào)用和關(guān)閉通知在很小的時間差同時發(fā)生,由于網(wǎng)絡(luò)抖動,會發(fā)生提供方通知關(guān)閉完成,進(jìn)行關(guān)閉過程中,調(diào)用的請求打過來了,由于在關(guān)閉過程中,部分對象被銷毀,繼續(xù)處理業(yè)務(wù)可能產(chǎn)生錯誤,因此應(yīng)該繼續(xù)調(diào)用。
此時可以設(shè)置一個關(guān)閉標(biāo)志位,當(dāng)調(diào)用過來時發(fā)現(xiàn)正在關(guān)閉,不進(jìn)行處理,直接失敗讓調(diào)用方去重試其他節(jié)點。同時為了不影響正在進(jìn)行的任務(wù),設(shè)置任務(wù)進(jìn)行計數(shù)器,打開關(guān)閉標(biāo)志位后,等待計數(shù)器歸零或延遲一定時間后再進(jìn)行關(guān)閉操作。
在應(yīng)用啟動時,主線程進(jìn)行順序加載時,向注冊中心注冊后還有其他bean需要加載,即應(yīng)用來沒有完全啟動,如果此時有流量流入,可能出錯。需要延遲接入。此時可以延遲注冊的動作,在應(yīng)用啟動完成后再進(jìn)行注冊,同時提供注冊前置動作,模擬請求,進(jìn)行應(yīng)用預(yù)熱,完成后再進(jìn)行注冊。
或者剛啟動的應(yīng)用沒有緩存、編譯的提升,速度較慢,一旦大規(guī)模流量涌入可能造成大面積超時,因此有時需要讓應(yīng)用先接入小部分流量進(jìn)行預(yù)熱后才接入大規(guī)模流量。這種可以在負(fù)載均衡算法中通過服務(wù)提供方的啟動時間(或注冊時間)作為權(quán)重來進(jìn)行流量分配。
對于大批節(jié)點需要重啟的,由于延遲接入和預(yù)熱可能造成可用性降低,最好的解決方案是分批次重啟。
熔斷限流
當(dāng)某個提供方負(fù)載太高,需要使用限流來限制訪問,降低壓力。
限流可用分單機(jī)限流和限流服務(wù),前者是調(diào)用者根據(jù)配置的限流信息自己決定自己的限流程度,如10臺機(jī)器每臺機(jī)器都是相同的限流幅度,后者是統(tǒng)一接入限流服務(wù)來判斷是否要啟動限流。兩者各有優(yōu)劣。
對于依賴于下層服務(wù)的上層服務(wù),由于下層服務(wù)導(dǎo)致的上層服務(wù)不可用,可能會導(dǎo)致整個調(diào)用鏈的崩潰,此時要啟動熔斷策略,保護(hù)調(diào)用鏈上的上層調(diào)用方。
流量隔離
服務(wù)提供方以一個整體的方式,為所有不同的接口調(diào)用提供服務(wù),如果某個接口的流量激增,可能打爆所有服務(wù)提供方,造成其他業(yè)務(wù)接口也無法使用,因此需要進(jìn)行流量隔離,對服務(wù)提供方進(jìn)行分組,不同消費者拿到的服務(wù)方實例不同,進(jìn)行調(diào)用。
可以在服務(wù)發(fā)現(xiàn)的時候進(jìn)行改造,服務(wù)發(fā)現(xiàn)要附帶業(yè)務(wù)分組屬性來進(jìn)行發(fā)現(xiàn)。
由于分組,對于某個特定接口提供方可用節(jié)點變少了,為了保證高可用,可以設(shè)置主次分組,當(dāng)主分組節(jié)點全部不可用時,可以暫時借用次分組的節(jié)點進(jìn)行服務(wù),同時為了不過分影響次分組的節(jié)點,可以只分配一小部分節(jié)點作為次分組節(jié)點。
隔離也可以用于環(huán)境隔離,對開發(fā)測試灰度等不同環(huán)境互不影響。
異步
RPC的性能大多浪費在業(yè)務(wù)的同步耗時,使用異步提升吞吐量能夠顯著提升性能。
對于RPC的請求和響應(yīng),屬于兩個獨立操作,一般是請求時會附帶消息id,并創(chuàng)建future返回,同時維持id和future的映射,拿到響應(yīng)時根據(jù)映射找到future并將結(jié)果進(jìn)行set。同步的RPC會主動get來阻塞等待結(jié)果。
服務(wù)端的異步在收到消息時消息的序列化拆包等動作是在io線程,但是對于業(yè)務(wù)邏輯一般會使用單獨的線程池跑。業(yè)務(wù)線程池把任務(wù)跑完后又要交給IO去響應(yīng),可以使用completefuture來更進(jìn)一步的異步,提升吞吐量。調(diào)用方同樣也可以使用回調(diào)的方式來進(jìn)一步的異步。
安全
為了防止任何人都能調(diào)用接口,需要提供安全身份認(rèn)證,調(diào)用方獲取密鑰來進(jìn)行身份認(rèn)證。
或者其他方法,限定接口調(diào)用權(quán)限
時鐘輪
在批量定時任務(wù)執(zhí)行的過程中(如定時掃描超時任務(wù)),如果大量任務(wù)比較延后,會造成掃描線程重復(fù)掃描大量不會被執(zhí)行的任務(wù),浪費CPU。
設(shè)置時鐘輪,將不同延遲時間執(zhí)行的任務(wù)放在不同的時間槽中,掃描線程固定頻率按照時鐘輪掃描,僅掃描對應(yīng)時鐘輪槽中的任務(wù),大大減少掃描任務(wù)數(shù)量。其時間復(fù)雜度相比優(yōu)先隊列更低,netty中提供了TimeWheel。
流量回放
類似tcpcopy和nginx的流量回放,進(jìn)行回歸測試、壓測等
只要記錄所有請求,在重新發(fā)一遍即可
動態(tài)分組
對于流量隔離,在分組的時候需要支持動態(tài)分組,以靈活應(yīng)對流量變化。
可以通過修改注冊中心的形式實現(xiàn),或者動態(tài)配置
無接口調(diào)用
沒有服務(wù)方提供的接口,或者調(diào)用者只需要很少的接口,沒必要去依賴全部的提供方的接口,提供方可以提供一個泛華的接口,調(diào)用方發(fā)送消息中提供方法名等必要的RPC調(diào)用的相關(guān)信息,由服務(wù)方進(jìn)行解析調(diào)用并返回結(jié)果即可。
下一篇:消息中間件解決方案JMS