使用RSocket進行服務通訊的反應性服務 - 負載平衡和可恢復性 | Rafał Kowalski
RSocket可以徹底改變分散式系統中的機器到機器通訊。在以下段落中,我們將討論雲中的負載平衡問題以及我們將介紹有助於處理網路問題的可恢復性功能,尤其是在物聯網系統中。
高可用性和負載平衡是企業級系統的關鍵部分
應用程式可用性和可靠性是銀行和保險等許多業務領域的重要組成部分。在這些要求苛刻的行業中,即使在高流量,網路延遲增加或自然災害期間,服務也必須全天候運營。為確保終端使用者始終可以使用該軟體,通常會在多個可用區域中以冗餘方式部署該軟體。
在這種情況下,每個微服務的至少兩個例項部署在至少兩個可用區中。這種技術有助於我們的系統恢復彈性並增加其容量 - 微服務的多個例項能夠處理明顯更高的負載。那麼訣竅在哪裡?冗餘引入了額外的複雜性。作為工程師,我們必須確保傳入流量分佈在所有可用例項中。解決此問題有兩種主要技術:伺服器負載平衡和客戶端負載平衡。
第一種方法基於請求者不知道響應者的IP地址的假設。取而代之的是,請求者與負載均衡器進行通訊,負載均衡器負責將請求分佈在與其連線的微服務上。這種設計在雲時代相當容易採用。IaaS提供商通常擁有內建的可靠解決方案,例如Amazon Web Services中提供的Elastic Load Balancer。這種技術的主要缺點是我們必須配置和部署額外的資源,如果我們的系統由數百個微服務組成,這可能會很痛苦。此外,它可能會影響延遲 - 每個請求在負載均衡器上都有額外的“網路跳躍”。
第二種技術顛倒了這種關係。請求者不知道用於連線到響應者的中心點,而是知道給定微服務的每個例項的IP地址。擁有這些知識後,客戶端可以選擇傳送請求的響應者例項或開啟連線。此策略不需要任何額外資源,但我們必須確保請求者具有響應者的所有例項的IP地址,客戶端負載平衡模式的主要好處是它的效能 - 透過減少一個額外的“網路跳躍”,我們可以顯著減少延遲。這是RSocket實現客戶端負載平衡模式的關鍵原因之一。
RSocket中的客戶端負載平衡
在程式碼級別上,在RSocket中實現客戶端負載平衡非常簡單。該機制依賴於LoadBalancedRSocketMono作為一包可用RSocket例項的物件,由RSocket供應商提供。要訪問RSockets,我們必須訂閱LoadBalancedRSocketMono哪個onNext訊號發出完全成熟的RSocket例項。此外,它計算每個RSocket的統計資料,以便能夠估計每個例項的負載,並在此基礎上選擇在給定時間點具有最佳效能的例項。
該演算法考慮了多個引數,如延遲,維護連線數以及許多待處理請求。每個RSocket的執行狀況由可用性引數反映 - 該值從0到1取值,其中0表示給定例項無法處理任何請求,1表示分配給完全執行的套接字。下面的程式碼片段顯示了負載均衡的RSocket的基本示例,它連線到響應者的三個不同例項並執行100個請求。每次它從LoadBalancedRSocketMono物件中獲取RSocket 。
@Slf4j public class LoadBalancedClient { static final int[] PORTS = new int[]{7000, 7001, 7002}; public static void main(String[] args) { List<RSocketSupplier> rsocketSuppliers = Arrays.stream(PORTS) .mapToObj(port -> new RSocketSupplier(() -> RSocketFactory.connect() .transport(TcpClientTransport.create(HOST, port)) .start())) .collect(Collectors.toList()); LoadBalancedRSocketMono balancer = LoadBalancedRSocketMono.create((Publisher<Collection<RSocketSupplier>>) s -> { s.onNext(rsocketSuppliers); s.onComplete(); }); Flux.range(0, 100) .flatMap(i -> balancer) .doOnNext(rSocket -> rSocket.requestResponse(DefaultPayload.create("test-request")).block()) .blockLast(); } } |
如果雲中的機器到機器通訊,實時流資料並不是什麼大問題,但如果我們考慮位於無法訪問穩定、可靠的網際網路連線的區域的物聯網裝置,問題就會變得更多複雜。我們可以輕鬆確定在這樣的系統中可能遇到的兩個主要問題:網路延遲和連線穩定性。從軟體的角度來看,我們可以用第一個做很多事情,但我們可以嘗試處理後者。讓我們用RSocket來解決這個問題,從選擇合適的互動模型開始。在這種情況下最合適的是request stream方法,其中部署在雲中的微服務是請求者,溫度感測器是響應者。在選擇互動模型後,我們應用了可恢復性機制。在RSocket中,我們透過resume()呼叫的方法來實現RSocketFactory,如下例所示:
@Slf4j public class ResumableRequester { private static final int CLIENT_PORT = 7001; public static void main(String[] args) { RSocket socket = RSocketFactory.connect() .resume() .resumeSessionDuration(RESUME_SESSION_DURATION) .transport(TcpClientTransport.create(HOST, CLIENT_PORT)) .start() .block(); socket.requestStream(DefaultPayload.create("dummy")) .map(payload -> { log.info("Received data: [{}]", payload.getDataUtf8()); return payload; }) .blockLast(); } } |
@Slf4j public class ResumableResponder { private static final int SERVER_PORT = 7000; static final String HOST = "localhost"; static final Duration RESUME_SESSION_DURATION = Duration.ofSeconds(60); public static void main(String[] args) throws InterruptedException { RSocketFactory.receive() .resume() .resumeSessionDuration(RESUME_SESSION_DURATION) .acceptor((setup, sendingSocket) -> Mono.just(new AbstractRSocket() { @Override public Flux<Payload> requestStream(Payload payload) { log.info("Received 'requestStream' request with payload: [{}]", payload.getDataUtf8()); return Flux.interval(Duration.ofMillis(1000)) .map(t -> DefaultPayload.create(t.toString())); } })) .transport(TcpServerTransport.create(HOST, SERVER_PORT)) .start() .subscribe(); log.info("Server running"); Thread.currentThread().join(); } } |
請注意,要執行提供的示例,您需要在計算機上安裝“socat”,請參閱自述檔案以獲取更多詳細資訊
請求者和響應者端的機制類似,它基於一些元件。首先,有一個ResumableFramesStore作為幀的緩衝區。預設情況下,它將它們儲存在記憶體中,但我們可以透過實現ResumableFramesStore介面輕鬆調整它以滿足我們的需求(例如,將幀儲存在分散式快取中,如Redis)。儲存儲存在保持活動幀之間發出的資料,這些幀是定期來回傳送的,並指示對等體之間的連線是否穩定。
此外,保持活動幀包含令牌,該令牌確定請求者和響應者的最後接收位置。當對等方想要恢復連線時,它會傳送具有隱含位置的恢復幀。隱含位置是根據上次接收的位置(與我們在保持活動幀中看到的值相同)加上從該時刻收到的幀的長度計算得出的。該演算法適用於通訊雙方,在恢復幀中,它由最後接收的伺服器位置和第一個客戶端可用位置令牌反映。(恢復操作的整個流程點選標題見原文配圖)
透過採用RSocket協議中內建的可恢復性機制,我們可以相對較低的努力減少網路問題的影響。如上例所示,可恢復性在資料流應用程式中可能非常有用,尤其是在裝置進行雲通訊的情況下。
總結
在本文中,我們討論了RSocket協議的更高階功能,這些功能有助於減少網路對系統操作性的影響。我們介紹了客戶端負載均衡模式和可恢復性機制的實現。這些功能與強大的互動模型相結合構成了協議的核心。
(banq注:重試 冪等這些機制在Rsocket實現是否需要考慮?)
相關文章
- 使用RSocket進行服務通訊的反應性服務簡介 - Rafał Kowalski
- Spring RSocket:基於服務註冊發現的 RSocket 負載均衡Spring負載
- SpringCloud微服務系列- 服務間通訊之負載均衡SpringGCCloud微服務負載
- 微服務的服務間通訊與服務治理微服務
- Eureka是服務定位與負載平衡開源軟體負載
- 可執行資訊和傳送訊息的服務?
- 2.8 使用資料庫服務管理應用負載資料庫負載
- Ofcom報告:負擔通訊服務的能力
- SAP 應用服務負載均衡的實現負載
- Nginx服務系列——負載均衡Nginx負載
- 服務的擴充套件性套件
- Traefik是微服務的負載平衡微服務負載
- 負載均衡-構建CDN服務負載
- OpenFeign 服務呼叫與負載負載
- .1.7.2 應用程式高可用性與服務和FAN
- 阿里雲IoT物模型-屬性,服務,事件通訊的topic和payload詳解阿里模型事件
- 領域服務和應用服務的差別?
- API服務平臺,可進行分散式執行API分散式
- 微服務之服務註冊和發現的可行性方案微服務
- Kubernetes:服務與負載均衡負載
- 微服務 - 叢集化 · 服務註冊 · 健康檢測 · 服務發現 · 負載均衡微服務負載
- IoT雲服務連線性的方式
- 使用JavaScript和網路資訊API進行自適應網路服務JavaScriptAPI
- 如何管理企業通訊服務?
- 內部通訊服務Factory(WCF)
- 服務設計的原則:服務模式與反模式模式
- 2.8.2 全域性資料服務GDS
- 負載均衡技術(二)———常用負載均衡服務介紹負載
- Notification使用詳解之三:通過服務更新進度通知&在Activity中監聽服務進度
- java socket 通訊socketServer 服務端多執行緒JavaServer服務端執行緒
- SpringCloud 服務負載均衡和呼叫 Ribbon、OpenFeignSpringGCCloud負載
- 實現微服務的唯一方法是:在系統全域性和本地兩個級別平衡每個服務的複雜性微服務
- SpringCloud系列使用Eureka進行服務治理SpringGCCloud
- SpringCloud(二):服務呼叫與負載均衡SpringGCCloud負載
- nginx實現兩臺服務負載均衡Nginx負載
- 《搭建DNS負載均衡服務》RHEL6DNS負載
- nginx配置web服務|反向代理|負載均衡NginxWeb負載
- SpringCloud-服務間通訊方式SpringGCCloud