MediatRPC - 基於MediatR和Quic通訊實現的RPC框架,比GRPC更簡潔更低耦合,開源發佈第一版

大家好,我是失業在家,正在找工作的博主Jerry。作爲一個.Net架構師,就要研究編程藝術,例如SOLID原則和各種設計模式。根據這些原則和實踐,實現了一個更簡潔更低耦合的RPC(Remote Procedure Calls)框架,名叫MediatRPC。

一、MediatR 編程思想

SOLID的總原則是開閉原則(Open Closed Principle): 一個軟件實體,如類、模塊和函數應該對擴展開放,對修改關閉。其它原則和設計模式都是爲了實現和體現這個總原則。例如我們熟悉的工廠模式就很好的實現了開閉原則(Open Closed Principle)。

但是我認爲,MediatR對這個總原則的實現更完美。在MediatR中,任何新增功能都可以通過新增Resquest消息和Handler處理器的方式實現,甚至可以在不改變原有Notification消息的基礎上,新增Handler處理來實現功能擴展。新版本還增加了對StreamRequest的支持,使其可以通過相同的方式對請求數據流進行處理,實現和GRPC類似的流式數據處理。

MediatR對這個總原則的實現之所以更好,是因爲它沒有讓程序員採用傳統的面向接口的編程方式來對功能進行抽象,也就是通過接口方法來代表功能。而是另闢蹊徑,採用消息來代表功能,把功能抽象爲對消息的處理過程。很巧妙的避免了接口類粒度難以定義和接口方法簽名耦合的問題。 MediatR讓程序員從面向接口編程轉變爲面向消息編程。化繁爲簡,我認爲這是一個很大的編程思想的進步。

二、MediatR 和 Grpc對比

MediatR還提供各種自定義AOP功能和異常處理功能,是個很優秀的過程/功能調用(Procedure Calls)框架。從過程/功能調用的角度來講,它比GRPC更簡潔,更低耦合。因爲GRPC本質上還是傳統的對服務器端功能的接口抽象,也就是Proto文件的作用。這導致了客戶端不但要知道服務端方法的接口參數,也要知道方法所在接口和方法名稱才能調用該功能。此外,如果客戶端只想調用服務端的一個方法,也必須要引用整個Proto文件,或者對Proto文件進行刪減(增加風險)。

而這些高耦合的問題在MediatR中都不存在,因爲在MediatR中,消息就代表功能,服務端只要接收到消息就執行對應處理過程來實現功能。客戶端想調用那個功能只要發送相應的消息即可。除了MediatR不能遠程(Remote)以外。

三、如何實現MediatRPC

那麼,我們就給MediatR加上遠程通訊的功能。這就涉及到遠程通訊的問題,目前最先進最時髦的遠程通訊協議莫過於QUIC了。它是HTTP3的通訊實現基礎,基於UDP協議,比TCP協議減少了握手次數,提高了傳輸效率,提高了傳輸安全性等,總之就是兩個字:先進。

而.Net 中的System.Net.Quic,是微軟實現的跨平臺QUIC的.Net封裝程序集。微軟其實是用C++實現的QUIC,據說其性能受到了業界好評。本文就使用System.Net.Quic爲MediatR增加遠程發送和接收消息的功能。從而實現真正的RPC,起名叫MediatRPC。

四、MediatRPC實現效果

 我們先來看一下實現結果,首先啓動服務端:

客戶端遠程調用代碼如下:

Console.WriteLine("MediatRPC Client Running...");
Console.WriteLine();

MediatRpcClient mediatRpcClient = await MediatRpcClient.Build();

var responseMessage1 = await mediatRpcClient.Send(new TestRequestMessage() { Message = "Hello MediatRPC 1" });
Console.WriteLine(JsonSerializer.Serialize(responseMessage1));

Console.WriteLine();

var responseMessage2 = await mediatRpcClient.Publish(new TestNotificationMessage() { Message = "Hello MediatRPC 2" });
Console.WriteLine(responseMessage2);


Console.ReadKey();

MediatRpcClient是我實現的客戶端對象,它分別向服務端發送了兩個消息,一個是用Send發送了IRequest消息,並打印返回消息。另一個是用Publish發送了INotification消息,打印是否執行成功。消息發送和接收方式和MediatR一摸一樣, 因爲方法簽名直接抄襲了MediatR。宗旨就是,怎麼使用MediatR就怎麼使用MediatRPC。

服務端處理Request消息的Handler代碼如下:

 public class TestRequestMessageHandler : IRequestHandler<TestRequestMessage, TestResponseMessage>
    {

        public TestRequestMessageHandler()
        {
        }

        public async Task<TestResponseMessage> Handle(TestRequestMessage request, CancellationToken cancellationToken)
        {
            TestResponseMessage testResponseMessage = new TestResponseMessage();
            testResponseMessage.Message = $"ACK:{request.Message},{DateTime.Now.ToString("HH:mm:ss")}";
            return testResponseMessage;
        }
    }

啓動客戶端:

Request 和 Response Package是我封裝的消息包,參考了Http包的實現,也分爲Headers和Body。Request 包將原來Http包的請求路徑改爲MediaRMethod,讓服務端知道如何處理這個消息。調用日誌每一步都打印的很清楚,不再贅述。

因篇幅關係,具體的服務端和客戶端通訊實現方式將在下一篇展開,明天就會發布,也會發布源代碼。

五、找工作

▪ 博主有15年以上的軟件技術實施經驗(Technical Leader),專注於微服務(Dapr)和雲原生(K8s)軟件架構設計、.Net Core、Java開發和Devops構建發佈。
▪ 博主10年以上的軟件交付管理經驗(Project Manager & Product Ower),致力於敏捷(Scrum)項目管理、軟件產品業務需求分析和原型設計。
▪ 博主熟練配置和使用 Microsoft Azure雲。
▪ 博主爲人誠懇,積極樂觀,工作認真負責。 

我家在廣州,也可以去深圳工作。做架構師、產品經理、項目經理都可以。有工作機會推薦的朋友可以加我微信 15920128707,微信名字叫Jerry。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章