.NET Core 使用 grpc 实现微服务
GRPC 是Google發布的一個開源、高性能、通用RPC(Remote Procedure Call)框架。提供跨語言、跨平臺支持。以下以一個.NET Core Console項目演示如何使用GRPC框架。
一、定義服務
通過proto定義一個數學計算服務,其中包括兩個服務方法(Add, Multipy)以及4個請求響應對象(AddRequest, AddReply, MultiplyRequest, MultiplyReply)。
// 文件名:mathservice.protosyntax = "proto3"; option java_multiple_files = false; option java_package = "MathServices"; option java_outer_classname = "MathServicesProto"; option objc_class_prefix = "MathServices";package MathServices;// 數學運算服務service MathService { ?
? ? rpc Add (AddRequest) returns (AddReply) {} ?rpc Multiply (MultiplyRequest)
? ?returns (MultiplyReply) {} } message AddRequest { ?double First = 1; ?double Second = 2; } message AddReply { ?double Sum = 1; } message MultiplyRequest { ?double First = 1; ?double Second = 2; } message MultiplyReply { ?double Result = 1; }
二、將服務編譯成存根(stub)
通過以下批處理命令generate_protos.bat將服務定義生成多種語言和平臺版本的客戶端和服務端存根。
@rem 生成客戶端和服務器端存根setlocal@rem 進入當前目錄 cd /d %~dp0set TOOLS_PATH=C:\Users\Freeman\.nuget\packages\Grpc.Tools\1.0.0\tools\windows_x86 %TOOLS_PATH%\protoc.exe ^--proto_path protos ^--cpp_out=Interfaces/cpp ^--csharp_out=Interfaces/csharp ^--java_out=Interfaces/java ^--js_out=Interfaces/javascript ^--grpc_out=Interfaces/csharp ^--plugin=protoc-gen-grpc=%TOOLS_PATH%\grpc_csharp_plugin.exe ^protos/mathservice.proto endlocaltimeout 5針對CSHARP語言,protoc.exe編譯器生成了如下圖幾個類,其中左邊4個類用于構造請求和響應對象,MathService類用于下一步構造服務和消費服務。
CSHARP STUBS
三、實現并運行服務
通過上一步的編譯,自動生成了MathService類,下面通過該類構造并啟動grpc服務。
通過繼承基類實現服務接口
? ?/// <summary>/// 實現RPC服務端接口。/// </summary>public class MathServiceImpl : MathService.MathServiceBase{public override Task<AddReply> Add(AddRequest request, ServerCallContext context){ ? ? ? ?? ? ? ? ? ? return Task.FromResult(new AddReply { Sum = request.First + request.Second });}public override Task<MultiplyReply> Multiply(MultiplyRequest request, ServerCallContext context){ ? ? ? ?
? ? ? ? ? ? ?return Task.FromResult(new MultiplyReply { Result = request.First * request.Second });}}
啟動服務
const string ip = "0.0.0.0";const int port = 50051; Server server = new Server(); server.Ports.Add(new ServerPort(ip, port, ServerCredentials.Insecure)); server.Services.Add(MathService.BindService(new MathServiceImpl())); server.Start(); server.Ports.ToList().ForEach(a => Console.WriteLine($"Server listening on port {a.Port}...")); Console.ReadLine();四、客戶端調用服務
客戶端通過創建一個Channel和一個服務客戶端來使用服務。
var channel = new Channel($"{"127.0.0.1"}:{port}", SslCredentials.Insecure);var client = new MathService.MathServiceClient(channel);
var random = new Random();while (true) { ? ?var first = random.NextDouble(); ? ?
? ? ? var second = random.NextDouble(); ?
? ? ?var reply = client.Add(new AddRequest { First = first, Second = second }); ?
? ? ?Console.WriteLine($"RPC call Add service: {first:F4} + {second:F4} = {reply.Sum:F4}"); ? ?Thread.Sleep(500); }
RPC調用
五、使用SSL實現加密通訊
grpc默認實現了基于證書的SSL加密通訊,使用中需要注意以下事項。
在Windows上開發請安裝 OpenSSL對應版本并將openssl.exe所在路徑添加到環境變量中。
通過以下樣例腳本生成通訊中所需要的服務端和客戶端證書,其中需要特別注意的是,Generate server signing request:中的CN=KEKYK字段如果是本機測試,請一定使用本機名稱,如果是真實環境請使用域名,因為客戶端必須通過機器名(本地測試)或域名訪問該服務。如果此處CN字段不使用機器名或域名,將導致以下錯誤:
CN字段不使用主機名或域名時產生的錯誤
生成服務端和客戶端證書腳本generate_ssl.bat
基于SSL的服務端啟動如下,創建服務的時候請使用主機名(開發環境)或域名(生產環境),不要使用IP地址。
public static void RpcServerSsl() { ?
? ?var cacert = File.ReadAllText(CombinePath("ca.crt"));
??var servercert = File.ReadAllText(CombinePath("server.crt")); ?
?? ? ?var serverkey = File.ReadAllText(CombinePath("server.key"));
?var keypair = new KeyCertificatePair(servercert, serverkey);
? ?var sslCredentials = new SslServerCredentials(new List<KeyCertificatePair>()
? ? ? { keypair }, cacert, false); ?
? ? ? var server = new Server{Services = { MathService.BindService(new MathServiceImpl()) },Ports = { new ServerPort("KEKYK", sslPort, sslCredentials) }};server.Start();server.Ports.ToList().ForEach(a => Console.WriteLine($"Server (SSL) listening on port {a.Port}..."));Console.ReadLine(); }基于SSL的客戶端使用如下,注意測試環境中使用主機名,生產環境中使用域名來,不要使用任何形式的IP地址。
public static void RpcClientSsl(){ ?
? var cacert = File.ReadAllText(CombinePath("ca.crt"));
? var clientcert = File.ReadAllText(CombinePath("client.crt"));
? ?var clientkey = File.ReadAllText(CombinePath("client.key")); ?
? ? var ssl = new SslCredentials(cacert, new KeyCertificatePair(clientcert, clientkey));
? var channel = new Channel("KEKYK", sslPort, ssl); ?
? ? var client = new MathService.MathServiceClient(channel); ?
? var random = new Random(); ?while (true){ ? ? ?
? ? ? ? var first = random.NextDouble(); ?
? ?? ?var second = random.NextDouble(); ? ? ?
? ?? ? ? ? ? ? var reply = client.AddAsync(new AddRequest { First = first, Second = second },
? ? ? ? ? new CallOptions()).ResponseAsync.Result;Console.WriteLine($"RPC call Add service: {first:F4} + {second:F4} = {reply.Sum:F4}");Thread.Sleep(1000);} }
原文地址:http://www.jianshu.com/p/f5e1c002047a
.NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注
總結
以上是生活随笔為你收集整理的.NET Core 使用 grpc 实现微服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 dotnet watch 开发 A
- 下一篇: IdentityServer4 ASP.