Redola.Rpc 集成 Consul 服務(wu)發(fa)現
Redola.Rpc 解決了什么問題?
Redola.Rpc 是一(yi)個使用 C# 開(kai)發的 RPC 框架,代碼開(kai)源在 上(shang)。目前版本(ben)僅支持 以(yi)上(shang)版本(ben),未來(lai)待系統穩健后再(zai)考慮(lv)移植 和 。
在 0.3.2 版本(ben)中,嘗試解決幾個 RPC 設計問題:
- 我是誰?(Local Actor)
- 如何告訴別人我是誰?(Actor Directory)
- 我提供什么服務?(Service Catalog Provider)
- 如何告訴別人我提供什么服務?(Service Directory)
- 我需要的服務在哪里?(Service Discovery)
- 如何調用該服務?(Service Dynamic Proxy)
- 如何找到該服務?(Actor Directory)
- 如何發消息給該服務?(Remote Actor)
Actor 是什么?
Redola 定義的(de) Actor 模型代表著一(yi)個通信節(jie)(jie)(jie)點(dian)(dian),使用 ActorIdentity 描(miao)述,包括(kuo)節(jie)(jie)(jie)點(dian)(dian)類(lei)型 Type、節(jie)(jie)(jie)點(dian)(dian)名稱 Name、節(jie)(jie)(jie)點(dian)(dian)地(di)址 Address、節(jie)(jie)(jie)點(dian)(dian)端口 Port。
Actor 與 Actor 之間是基于 TCP Socket 通信的(de),Actor 并不區分 TCP 的(de) Server/Client 端,它將 Server 和(he) Client 封裝在底(di)層,為上層應用(yong)提供更便捷的(de)傳輸定義和(he)調用(yong)接口。Actor 模型提供了面向通道 Channel 的(de)雙(shuang)工通道,可(ke)以接收來自對端的(de)消(xiao)息(xi),也可(ke)以發送消(xiao)息(xi)給對端。
Actor 收發(fa)的(de)消(xiao)息是面向二進制數(shu)組的(de),它不關(guan)心具體(ti)發(fa)送(song)的(de)是什(shen)么(me)消(xiao)息,也不關(guan)心序列化格式。Actor 使(shi)用(yong) ActorFrameHeader 定義(yi)傳輸消(xiao)息頭,Header 攜帶消(xiao)息體(ti)長度。
Actor 一旦建立連(lian)接,生成的(de) Channel 通(tong)道會(hui)自動進行 KeepAlive 雙(shuang)向保(bao)活機制。通(tong)過 Actor 服(fu)務(wu)發現,可(ke)(ke)以與任(ren)意的(de) Actor 進行通(tong)信,無(wu)需再配置對端節點地址和端口。并(bing)且,針對相同 Type 的(de) Actor,還可(ke)(ke)以實現消息分發的(de)負載均衡(heng)功(gong)能。
RPC 契約定義
是基于契約(yue)模型通(tong)信的(de),使用 格式(shi)定(ding)義 IDL,并通(tong)過自動生(sheng)成(cheng)(cheng)工具生(sheng)成(cheng)(cheng) Contract 契約(yue)定(ding)義。
例如,下(xia)面是(shi)定義 ICalcService 服務(wu)的(de) IDL 定義。
package Redola.Rpc.TestContracts; message AddRequest { required int32 X = 10; required int32 Y = 20; } message AddResponse { required int32 Result = 10; } service CalcService { rpc Add (AddRequest) returns (AddResponse); }
上述 IDL 生成的(de) ICalcService 接口定(ding)義為:
public interface ICalcService { AddResponse Add(AddRequest request); }
RPC 消息序列化
Redola.Rpc 選擇使用 Protobuf 2 進行消息序列化,默認集成 類庫,穩定使用 protobuf-net v2.0.0.668 版本。
RPC 消息信封
使用 ActorMessageEnvelope 封裝消息信(xin)封,攜帶(dai)如下信(xin)息:
RPC 消息定義
RPC 消(xiao)息(xi)分為(wei) 2 類(lei):
- InvokeMethodRequest / InvokeMethodResponse 用于定義請求回復模型的方法調用;
- InvokeMethodMessage 用于定義請求無回復模型的方法調用;
通常 RPC 消息(xi)會包含如(ru)下屬(shu)性信息(xi):
例如(ru),對于 ICalcService 中的 Add 方法:
- MethodLocator = "Rodola.Rpc.TestContracts.ICalcService/Add_AddRequest";
- MethodArguments = new object[] { new AddRequest(1, 2)};
鑒于 protobuf 本(ben)身是面向契(qi)(qi)約設計(ji)的,而 object[] 中的 object 是有不確定性的,并不能具體(ti)描述一個契(qi)(qi)約,則(ze)要求每一個 Argument 都需要支持 protobuf 的序(xu)列化,傳輸時系統會攜(xie)帶該 Argument 類型的 ,在對端(duan)通過反射(she)進行反序(xu)列化。
Actor Directory 節點目錄
Actor Directory 負責注冊本(ben)地 Local Actor 到注冊中心,Local Actor 也可以在 Shutdown 時(shi)將自己(ji)從(cong)注冊中心移除掉。
通(tong)過(guo) Actor Directory,Local Actor 可以使用 Type 和 Name 進(jin)行 Remote Actor 的檢索,進(jin)而進(jin)行 Channel 的建立和通(tong)信。
Actor Directory 通過 IActorDirectory 的(de)抽象定義,可以(yi)與不(bu)同(tong)的(de)目(mu)錄方案進(jin)行集成。例如,自實(shi)現基于 Actor 的(de) CenterActorDirectory,使用(yong)(yong) XML 配置文(wen)件的(de) LocalXmlFileActorDirectory,使用(yong)(yong) Consul 進(jin)行中(zhong)心注冊(ce)的(de) ConsulActorDirectory。
使用 Consul 時,實際上是(shi)調用了 中(zhong)的 Agent Register Service 接口 '/v1/agent/service/register',通過(guo)指定 ServiceID 和 ServiceName 進行注冊。
通(tong)過(guo)如下 cmd 啟動 Consul Server 和 Consul Agent。
consul.exe agent -config-dir "C:\Consul\config\server-01" -bootstrap -ui consul.exe agent -config-dir "C:\Consul\config\client-01" -join 192.168.1.133:7774 -ui
下面為啟動本地 Consul 進行測試的配(pei)置文件(jian)。
server-01.json
{ "datacenter": "dc1", "data_dir": "C:\\Consul\\data\\server-01", "log_level": "INFO", "node_name": "server-01", "server": true, "ports": { "http": 7771, "rpc": 7772, "dns": 7773, "serf_lan": 7774, "serf_wan": 7775, "server": 7776 } }
client-01.json
{ "datacenter": "dc1", "data_dir": "C:\\Consul\\data\\client-01", "log_level": "INFO", "node_name": "client-01", "ports": { "http": 8881, "rpc": 8882, "dns": 8883, "serf_lan": 8884, "serf_wan": 8885, "server": 8886 } }
Service Catalog Provider 服務提供者
作為 RPC Service 的 Provider 提(ti)供方,需要顯式定義指定 Contract 的服(fu)務實例(li)。例(li)如,下面將(jiang)不(bu)同的服(fu)務契約與(yu)服(fu)務實例(li)進行(xing)了注(zhu)冊(ce)。
var serviceCatalog = new ServiceCatalogProvider(); serviceCatalog.RegisterService<IHelloService>(new HelloService()); serviceCatalog.RegisterService<ICalcService>(new CalcService()); serviceCatalog.RegisterService<IOrderService>(new OrderService());
實際上,可以(yi)通過(guo)對于 IServiceCatalogProvider 接口的不(bu)(bu)同實現(xian),進(jin)行(xing)不(bu)(bu)同方式的本地服務(wu)發現(xian)和注冊。例如(ru),可以(yi)使用 Attribute 標記(ji)服務(wu),通過(guo)對 Assembly 進(jin)行(xing)反(fan)射(she)進(jin)行(xing)服務(wu)的實例化。
Service Directory 服務目錄
本地(di)服(fu)(fu)務(wu)(wu)聚集(ji)到(dao) Catalog 中后,系統(tong)會將服(fu)(fu)務(wu)(wu)逐個注冊到(dao) Service Directory 服(fu)(fu)務(wu)(wu)目錄中,使得其他節點(dian)可以檢索服(fu)(fu)務(wu)(wu)進行使用(yong)。
通過 IServiceDirectory 的抽象(xiang)定(ding)義,可以(yi)與不(bu)同的目(mu)錄(lu)方(fang)案進行(xing)(xing)集成(cheng)。例如,使(shi)用(yong) XML 配置文(wen)件的 LocalXmlFileServiceDirectory,使(shi)用(yong) Consul 進行(xing)(xing)中心注冊的 ConsulServiceDirectory。
使用 Consul 時,注冊(ce)服(fu)務的 log 如下所(suo)示。

當 Redola 將服務注冊(ce)至 Consul 中后,可通過 Consul 內(nei)置的 UI 進(jin)行(xing)查看。
http://localhost:8881/ui/#/dc1/services

Service Discovery 服務發現
通過 ConsulServiceDiscovery 實(shi)現 IServiceDiscovery 服務(wu)(wu)發現接口,從 檢索指定服務(wu)(wu)類型的服務(wu)(wu)。
通過 Postman 測試 GET /v1/catalog/services,得到如下 JSON 數據。
http://localhost:8881/v1/catalog/services
{ "Redola.Rpc.TestContracts.ICalcService": [], "Redola.Rpc.TestContracts.IHelloService": [], "Redola.Rpc.TestContracts.IOrderService": [], "consul": [], "server": [] }
通過 Postman 測試 GET /v1/catalog/service,得(de)到如(ru)下 JSON 數據。
http://localhost:8881/v1/catalog/service/Redola.Rpc.TestContracts.ICalcService
[ { "ID": "359e8dfe-262d-6eb7-260c-e6e3ad208a14", "Node": "client-01", "Address": "192.168.1.133", "Datacenter": "dc1", "TaggedAddresses": { "lan": "192.168.1.133", "wan": "192.168.1.133" }, "NodeMeta": {}, "ServiceID": "redola/server/server-33333/Redola.Rpc.TestContracts.ICalcService", "ServiceName": "Redola.Rpc.TestContracts.ICalcService", "ServiceTags": [], "ServiceAddress": "localhost", "ServicePort": 33333, "ServiceEnableTagOverride": true, "CreateIndex": 2147, "ModifyIndex": 2151 } ]
服務檢索方,可通(tong)過指(zhi)定 IServiceLoadBalancingStrategy 的具(ju)體實(shi)現(xian)實(shi)施不同的負載均衡策略(lve),默認指(zhi)定的是(shi) IServiceLoadBalancingStrategy 隨機選擇。
Service Dynamic Proxy 動態代理
為(wei)簡(jian)化 RPC 調用(yong)發(fa)起方的封裝,通常(chang)會使(shi)用(yong) Dynamic Proxy 動(dong)(dong)態(tai)代理(li)技術來動(dong)(dong)態(tai)生成給定契(qi)約的服(fu)務實例,將整體 RPC 的過程透明化。
例如,通過下面的代碼來動(dong)態生(sheng)成 ICalcService 的動(dong)態代理(li)。
var calcClient = rpcNode.Resolve<ICalcService>();
目(mu)前 Redola.Rpc 默(mo)認集(ji)成了 中的 模塊,通過對實(shi)例方法的 Intercept 攔截進行 RPC 消息的收發處理。
當(dang)然,如需集成其他 Dynamic Proxy 類庫,可通(tong)過 ISeviceProxyGenerator 接口進行方案實現。
Redola.Rpc 類庫依賴
Redola.Rpc 當前實現依賴了如下開源(yuan)類(lei)庫。
<?xml version="1.0" encoding="utf-8"?> <packages> <package id="Consul" version="0.7.2.3" targetFramework="net46" /> <package id="Cowboy.Sockets" version="1.3.14.0" targetFramework="net46" /> <package id="protobuf-net" version="2.0.0.668" targetFramework="net46" /> <package id="Castle.Core" version="4.1.0" targetFramework="net46" /> <package id="Logrila.Logging" version="1.0.3.0" targetFramework="net46" /> <package id="Logrila.Logging.NLogIntegration" version="1.0.3.0" targetFramework="net46" /> <package id="NLog" version="4.2.3" targetFramework="net46" /> </packages>
版權聲明:本篇文章《Redola 集成 Consul 服務發現》由作者 Dennis Gao 發表自博客園個人技術博客,未經作者本人同意禁止以任何的形式轉載,任何自動的或人為的爬蟲轉載行為均為耍流氓。
