歡迎光臨
每天分享高質量文章

【剖析 | SOFARPC 框架】系列之 SOFARPC 路由實現剖析

SOFA

Scalable Open Financial Architecture

是螞蟻金服自主研發的金融級分佈式中間件,包含了構建金融級雲原生架構所需的各個組件,是在金融場景里錘煉出來的最佳實踐。


本文為《剖析 | SOFARPC 框架》第十篇,作者明不二,就職於華為

《剖析 | SOFARPC 框架》系列由 SOFA 團隊和原始碼愛好者們出品,

專案代號:,官方目錄目前已經全部認領完畢,文末提供了已完成的文章目錄。


  前言

RPC 框架需要創造一種呼叫遠程服務如同呼叫本地般的體驗,因此在實現一個基於 RPC 框架的微服務架構的系統時,服務消費者(客戶端)往往只需要知道服務端提供了哪些接口和方法,並不需要知道服務具體由哪些 IP 在提供。RPC 框架本身的服務發現和路由尋址功能解決瞭如何知道標的地址的問題,該過程對於 RPC 客戶端呼叫方來說應該是完全透明的。

在這個過程中,RPC 框架需要接入註冊中心來完成服務發現和路由尋址的功能。同時,在應用大規模請求時,微服務系統還需要對請求服務集群化,同時通過負載均衡來達到降低訪問壓力的效果。


本文我們會先介紹一下註冊中心,然後介紹一下 SOFRPC 中的幾種路由,最後會進行負載均衡的幾種比較。

  註冊中心支持

首先我們簡要介紹一下註冊中心的原理。


服務提供者將地址信息註冊到註冊中心,註冊中心儲存著所有服務的地址信息,服務呼叫者可以從註冊中心訂閱到服務提供者的地址串列,也包括地址變化事件。


其中,註冊中心的場景依賴於各類註冊中心的實現。在這裡,SOFARPC 提供了註冊中心的抽象類 Registry,該抽象類提供了註冊中心的配置、啟動、註冊、反註冊、訂閱等方法。客戶端在接入過程中,可以通過配置來激活 Zookeeper、Consul、local 等註冊中心註冊進啟動類中,當請求到來時,可以通過註冊中心進行相應的路由。

註冊中心的抽象類如下:



目前在 SOFARPC 里內置了多種註冊中心實現,還有部分註冊中心實現CodeReview中。


1、Local註冊中心(Local)

Local 註冊中心是 SOFARPC 自己實現的一個本地註冊中心,該註冊中心的實現主要由類 LocalRegistry提供,可以呼叫其 register(ProviderConfig config) 方法實現服務的註冊,主要是檔案的讀寫。

實現原理很簡單,通過在本地註冊檔案來儲存服務的發佈和訂閱信息,主要用於本地研發測試使用

2、Zookeeper 註冊中心(Zookeeper)

Zookeeper 接入 SOFARPC 的實現類為 ZookeeperRegistry。目前是 SOFARPC 中預設的註冊中心實現。也是大多數情況下,可以方便使用的。

Zookeeper 是一個分佈式協調服務,用於維護配置信息、命名、提供分佈式同步功能以及提供組服務等。Zookeeper 提供了服務註冊與發現的解決方案,提供了簡單的 API,可以讓集成者簡潔呼叫。


當要發佈一個 SOFARPC 服務時,首先需要在 Zookeeper 中註冊服務提供者的相關信息,包括:該服務接口隸屬於哪個系統、服務的 IP 以及端口號、服務的請求 URL 和服務的權重等等。Zookeeper 在這個過程中,註意負責對 SOFARPC 中的服務信息進行中心儲存,同時負責把服務註冊信息的更新及時通知到服務消費者。


作為服務呼叫者,SOFARPC 呼叫端在呼叫時,若走的路由鏈路中有註冊中心,則會從註冊中心中獲取到服務註冊的相關信息,然後在呼叫時會根據負載均衡策略來發送請求。

3、Consul註冊中心(Consul)

Consul 註冊中心與 SOFARPC 之間的對接主要依賴於 ConsulRegistry類。

該註冊中心在功能表現上與 Zookeeper 看起來一致。對比起 Zookeeper 來,Consul 支持多資料中心,同時支持 http 和 dns 等接口,有著多語言的能力。

4、其他註冊中心

目前已經在開發中的有 Nacos,SOFAMesh 等。也可以根據自己的場景,進行方便的擴展。

  路由設計

1、路由原理和設計

在閱讀本部分之前,請大家註意:路由是為了選中一組地址。


SOFARPC 通過對各類註冊中心的支持,實現了服務發現、路由尋址的功能。訪問客戶端時,請求的路由可以由以下一些實現類實現:DirectUrlRouter、RegistryRouter、CustomRouter,上述三個路由實現類分別對應了直接地址路由(不需要經過註冊中心直接路由直連到某個地址)、註冊中心路由、以及客戶自定義路由等。路由從 AddressHolder 獲取到地址,同時通過各種負載均衡演算法進行負載均衡,請求到相應的系統接口。


首先我們看一下整個路由尋址過程的階段。



這 SOFARPC 中,路由可以分為地址直連路由、註冊中心路由以及客戶定製化路由。這以上三個路由均擴展了 Router 抽象類。服務路由的抽象類代碼如下:



這裡的核心代碼是 route 這個方法,將本次請求的信息,和服務串列進行計算。當客戶端請求到達 Router 時,會根據請求的引數信息從 Router 和連接管理器中獲取請求地址,通過呼叫 route(SofaRequest request, List providerInfos) 方法達到路由尋址的目的。


其中,路由並不是一個非此即彼的過程,這些可選的路由是由用戶和系統的配置,被構造成一個路由鏈來執行的。這樣。就可以有一些兜底的邏輯,如指定了 IP 地址,那我們就直接路由到這個地址,如果沒有,就進行註冊中心的路由等等。

2、直連(DirectUrlRouter)

直接路由是比較簡單的,因為有專門的配置,所以地址串列這些都是可以很方便地進行識別,在客戶端配置時,可通過如下方式配置:


ConsumerConfig<HelloService> consumer = new ConsumerConfig<HelloService>()        
            .setInterfaceId(HelloService.class.getName())        
            .setRegistry(registryConfig)        
            .setDirectUrl("bolt://127.0.0.1:12201");

直接地址路由擴展了 Router 抽象類的實現,在重寫的 route 方法中,直接獲取配置好的直接路由地址。當請求到來時,直接從地址管理串列中,拿到對應的地址,就實現了直接地址路由的功能。

3、註冊中心(RegistryRouter)

註冊中心路由同樣擴展了 Router 抽象方法,這個 Router是大多數情況下使用最多的路由,主要是從本應用使用的註冊中心中獲取對應的地址,併進行路由尋址等。後面我們會介紹目前註冊中心的幾個內置實現。

4、自定義(CustomRouter)

客戶定製化路由可以配置客戶自己所定製的路由實現,可以參考直接地址路由或者註冊中心路由的實現,擴展 Router 類即可。


這裡的使用場景:

一種是對於某些用戶來說,在註冊中心的場景下,用戶認為所有的地址並不是等價的。會對地址進行人為拆分,使用方儲存了自己的的所有服務提供方地址(或者是通過某種方法查詢),然後重寫路由定製邏輯,通過方法級別進行地址的選擇。


另一種是,用戶可以通過這個接口實現一些功能,例如切流、灰度、同機房優先等等。

  負載均衡實現

經過前面兩個部分的介紹,我們知道,通過不同的註冊中心和直連指定的方式,經過路由鏈的選擇,我們已經拿到了一組地址,這一組地址如果選出一個地址進行本次的呼叫。就涉及到負載均衡的選擇。下麵我們會給大家介紹下每種負載均衡的比較和優勢。


現在,SOFARPC 提供如下一些負載均衡器。下麵是各個負載均衡器的類名稱以及演算法原理,以下各個類名可以直接在代碼中進行搜索閱讀。

註意:負載均衡的計算全部是在客戶端實現的。

負載均衡器的抽象類下:


1、權重隨機(RandomLoadBalancer)

帶權重的隨機負載均衡演算法是 SOFARPC 目前預設開啟的負載均衡演算法。在演算法在進行負載均衡時,全部串列按照權重進行隨機選擇。


權重隨機的思路很簡單,每個服務地址,在發佈的時候,帶上了一個 weight 的標簽,SOFARPC 在路由的時候,彙總所有的權重值,然後產生一個0到這個總權重值的隨機數,看這個數是落在哪個範圍內,就知道要選哪個服務端作為本次呼叫的地址,預設為100,當然,用戶也可以指定或者通過某些操作 API 進行修改。在 SOFARPC,預熱權重功能會在啟動期間,使得某個剛剛啟動的服務端地址的權重為一個較小的值。


對於所有權重一樣的情況下。權重隨機也就退化成了完全隨機。

而對於權重有差異的情況下,就能實現,權重小的呼叫少,權重多的呼叫量大。


這個直觀理解就是一個線段擲骰子 的問題,相信大家配合代碼一看就明白了。

權重隨機負載均衡演算法,可以結合預熱權重配置來實現啟動期的預熱功能,也可以通過配置改寫動態修改某些服務提供方的權重信息來實現流量分配,也可以通過權重實現單機故障摘除等能力,當然這些功能可能需要依賴於註冊中心的實現。

2、順序輪詢(RoundRobinLoadBalancer)

進行依次輪詢來進行負載均衡。主要用來呼叫量比較少的情況下。

該負載均衡演算法在實現時,不關心權重,按照方法級進行輪詢,相互不會影響。這個非常簡單。就是一個環狀,輪詢完了就再次重新開始。


3、本地優先(LocalPreferenceLoadBalancer)

該負載均衡演算法提升了本機的呼叫性能。在負載均衡時使用保持本機優先。這個相信大家也比較好理解。在所有的可選地址中,找到本機發佈的地址,然後進行呼叫。

4、一致性 Hash(ConsistentHashLoadBalancer)

一致性 Hash 演算法,保障了客戶端和服務器之間比較穩定的連接關係。

該演算法通過一致性 hash,保證了第一引數同樣的請求能夠負載均衡到同樣的節點上。一致性 Hash 大家都瞭解比較多了,這裡 SOFARPC 是通過方法入參的第一個引數來做負載均衡的 Hash 的。

5、權重一致性 Hash(WeightConsistentHashLoadBalancer)

帶權重的一致性 hash 演算法。在一致性 Hash的基礎上,設置虛擬節點的時候,權重大的 ProviderInfo 會生成更多的節點。這樣被選中的概率就更高。這裡不再做詳細說明。大家有興趣可以從代碼中進行閱讀。

6、負載均衡比較

負載均衡演算法

優點

缺點

場景

權重隨機

快速方便

呼叫量小的情況下不完全均衡

大多數場景

順序輪詢

呼叫完全均衡

沒有權重

TPS小的場景

本地優先

本地優先

有場景限制。

本地有服務發佈的場景。

一致性 Hash

呼叫機器相對固定

性能相對一般

對呼叫機器需要相對固定的場景。

權重一致性 Hash

呼叫機器相對固定,有權重

性能相對一般

對呼叫機器需要相對固定的場景。

  總結

在本文中,我們剖析了 SOFARPC 的路由實現,詳細解釋了 SOFARPC 在對路由的實現方式及相應的擴展方式。除此之外,介紹了不同註冊中心的接入方法,及接入的實現。


最後,本文介紹了一些負載均衡演算法,並對這些演算法進行了相應的對比,希望讀者有所收穫,也歡迎留言討論。


相關鏈接

SOFA 文件: http://www.sofastack.tech/

SOFA: https://github.com/alipay

SOFARPC: https://github.com/alipay/sofa-rpc

SOFABolt: https://github.com/alipay/sofa-bolt

  《剖析 | SOFARPC 框架》系列歷史文章

長按關註,獲取分佈式架構乾貨

歡迎大家共同打造 SOFAStack https://github.com/alipay

赞(0)

分享創造快樂