Redola.Rpc 集成 Consul 服务发现
Redola.Rpc 解決了什么問題?
Redola.Rpc 是一個使用 C# 開發的 RPC 框架,代碼開源在?GitHub?上。目前版本僅支持?.NET Framework 4.6?以上版本,未來待系統穩健后再考慮移植?.NET Standard?和?.NET Core。
Redola.Rpc?在 0.3.2 版本中,嘗試解決幾個 RPC 設計問題:
我是誰?(Local Actor)
如何告訴別人我是誰?(Actor Directory)
我提供什么服務?(Service Catalog Provider)
如何告訴別人我提供什么服務?(Service Directory)
我需要的服務在哪里?(Service Discovery)
如何調用該服務?(Service Dynamic Proxy)
如何找到該服務?(Actor Directory)
如何發消息給該服務?(Remote Actor)
Actor 是什么?
Redola 定義的 Actor 模型代表著一個通信節點,使用 ActorIdentity 描述,包括節點類型 Type、節點名稱 Name、節點地址 Address、節點端口 Port。
Actor 與 Actor 之間是基于 TCP Socket 通信的,Actor 并不區分 TCP 的 Server/Client 端,它將 Server 和 Client 封裝在底層,為上層應用提供更便捷的傳輸定義和調用接口。Actor 模型提供了面向通道 Channel 的雙工通道,可以接收來自對端的消息,也可以發送消息給對端。
Actor 收發的消息是面向二進制數組的,它不關心具體發送的是什么消息,也不關心序列化格式。Actor 使用 ActorFrameHeader 定義傳輸消息頭,Header 攜帶消息體長度。
Actor 一旦建立連接,生成的?Channel 通道會自動進行 KeepAlive 雙向保活機制。通過 Actor 服務發現,可以與任意的 Actor 進行通信,無需再配置對端節點地址和端口。并且,針對相同 Type 的 Actor,還可以實現消息分發的負載均衡功能。
RPC 契約定義
Redola.Rpc?是基于契約模型通信的,使用?Protobuf 2?格式定義 IDL,并通過自動生成工具生成 Contract 契約定義。
例如,下面是定義 ICalcService 服務的 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 生成的 ICalcService 接口定義為:
public interface ICalcService {AddResponse Add(AddRequest request); }RPC 消息序列化
Redola.Rpc 選擇使用 Protobuf 2 進行消息序列化,默認集成?protobuf-net?類庫,穩定使用 protobuf-net?v2.0.0.668?版本。
RPC 消息信封
使用 ActorMessageEnvelope 封裝消息信封,攜帶如下信息:
| ? 屬性名稱 | ?屬性類型? | ?屬性描述? |
?MessageID | string | ?消息 ID,唯一 ID,通常使用 GUID。 |
?MessageTime | DateTime | ?消息產生時間 |
?CorrelationID | string | ?如果是 Response 則回填 Request 的 MessageID。? |
?CorrelationTime? | DateTime? | ?如果是 Response 則回填 Request 的 MessageTime。 |
?SourceEndpoint? | ?ActorEndpoint? | ?發送端節點描述,消息路由使用,默認不需要填寫。 |
?TargetEndpoint | ActorEndpoint | ?目的端節點描述,消息路由使用,默認不需要填寫。? |
?MessageType | string | ?消息類型,使用字符串描述。 |
?MessageData | byte[] | ?消息體,消息序列化后的二進制數組。 |
RPC 消息定義
RPC 消息分為 2 類:
InvokeMethodRequest / InvokeMethodResponse?用于定義請求回復模型的方法調用;
InvokeMethodMessage?用于定義請求無回復模型的方法調用;
通常 RPC 消息會包含如下屬性信息:
| ? 屬性名稱 | ?屬性類型? | ?屬性描述? |
?MethodLocator | string | ?RPC 方法描述,使用字符串描述。 |
?MethodArguments? | object[] | ?RPC 方法的入參,object 對象數組。 |
例如,對于 ICalcService 中的 Add 方法:
MethodLocator = "Rodola.Rpc.TestContracts.ICalcService/Add_AddRequest";
MethodArguments = new object[] { new AddRequest(1, 2)};
鑒于 protobuf 本身是面向契約設計的,而 object[] 中的 object 是有不確定性的,并不能具體描述一個契約,則要求每一個 Argument 都需要支持 protobuf 的序列化,傳輸時系統會攜帶該 Argument 類型的?AssemblyQualifiedName,在對端通過反射進行反序列化。
Actor Directory 節點目錄
Actor Directory 負責注冊本地 Local Actor 到注冊中心,Local Actor 也可以在 Shutdown 時將自己從注冊中心移除掉。
通過 Actor Directory,Local Actor 可以使用?Type 和 Name 進行 Remote Actor 的檢索,進而進行 Channel 的建立和通信。
Actor Directory 通過 IActorDirectory 的抽象定義,可以與不同的目錄方案進行集成。例如,自實現基于 Actor 的 CenterActorDirectory,使用 XML 配置文件的 LocalXmlFileActorDirectory,使用 Consul 進行中心注冊的 ConsulActorDirectory。
使用 Consul 時,實際上是調用了?Consul HTTP API?中的 Agent Register Service 接口 '/v1/agent/service/register',通過指定 ServiceID 和 ServiceName 進行注冊。
通過如下 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 進行測試的配置文件。
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 提供方,需要顯式定義指定 Contract 的服務實例。例如,下面將不同的服務契約與服務實例進行了注冊。
var serviceCatalog = new ServiceCatalogProvider(); serviceCatalog.RegisterService<IHelloService>(new HelloService()); serviceCatalog.RegisterService<ICalcService>(new CalcService()); serviceCatalog.RegisterService<IOrderService>(new OrderService());實際上,可以通過對于 IServiceCatalogProvider 接口的不同實現,進行不同方式的本地服務發現和注冊。例如,可以使用?Attribute 標記服務,通過對 Assembly 進行反射進行服務的實例化。
Service Directory 服務目錄
本地服務聚集到 Catalog 中后,系統會將服務逐個注冊到 Service Directory 服務目錄中,使得其他節點可以檢索服務進行使用。
通過 IServiceDirectory 的抽象定義,可以與不同的目錄方案進行集成。例如,使用 XML 配置文件的 LocalXmlFileServiceDirectory,使用 Consul 進行中心注冊的 ConsulServiceDirectory。
使用 Consul 時,注冊服務的 log 如下所示。
當 Redola 將服務注冊至 Consul 中后,可通過 Consul 內置的 UI 進行查看。
http://localhost:8881/ui/#/dc1/servicesService Discovery 服務發現
通過 ConsulServiceDiscovery 實現 IServiceDiscovery 服務發現接口,從?Consul?檢索指定服務類型的服務。
通過 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,得到如下 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} ]
服務檢索方,可通過指定?IServiceLoadBalancingStrategy 的具體實現實施不同的負載均衡策略,默認指定的是?IServiceLoadBalancingStrategy 隨機選擇。
Service Dynamic Proxy 動態代理
為簡化?RPC 調用發起方的封裝,通常會使用 Dynamic Proxy 動態代理技術來動態生成給定契約的服務實例,將整體 RPC 的過程透明化。
例如,通過下面的代碼來動態生成 ICalcService 的動態代理。
var calcClient = rpcNode.Resolve<ICalcService>();目前 Redola.Rpc 默認集成了?Castle.Core?中的?Dynamic Proxy?模塊,通過對實例方法的 Intercept 攔截進行 RPC 消息的收發處理。
當然,如需集成其他 Dynamic Proxy 類庫,可通過 ISeviceProxyGenerator 接口進行方案實現。
Redola.Rpc 類庫依賴
Redola.Rpc 當前實現依賴了如下開源類庫。
<?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.Rpc 集成 Consul 服务发现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DDD理论学习系列(13)-- 模块
- 下一篇: asp.net core 1.1 项目升