.net core 用grpc實現微服務


GRPC 是Google發布的一個開源、高性能、通用RPC(Remote Procedure Call)框架。提供跨語言、跨平台支持。以下以.NET Core 使用控制台、docker中演示如何使用GRPC框架。

   

軟件版本

.net core :1.0.1

GRPC:1.0.1-pre1

   

   

1.定義服務

使用proto3語法定義一個服務,主要測試package、import、常用類型的測試,

proto3語法: https://developers.google.com/protocol-buffers/docs/proto3

   

定義一個result.proto

   

syntax = "proto3";

package App.RPC.Model;

message Response{

bool sucess=1;

string message=2;

}

   

定義RPCDemoService.proto文件如下:

syntax = "proto3";

package App.RPC.Service;

import "result.proto";

   

service RPCDemoService{

rpc Add(DemoRequest) returns (App.RPC.Model.Response){}

rpc GetById(DemoId) returns (DemoRequest){}

rpc Get(Search) returns (DemoList){}

}

message DemoId{

int32 Id=1;

}

   

message Search{

int32 page=1;

int32 size=2;

string query=3;

}

   

message DemoRequest{

string Id=1;

int32 CommentId=2;

bool IsDeleted=3;

}

   

message DemoList{

repeated DemoRequest details = 1;

}

   

2.將服務生成類文件:

項目引用nuget包Grpc.Tools 1.0.0 或通過命令安裝這個程序包,然后找到文件路徑

先配置packages\Grpc.Tools\1.0.0\tools\windows_x64\protoc.exe環境變量

protoc.exe --csharp_out=d:\grpcdemo\code\ --grpc_out=d:\grpcdemo\code\ --plugin=protoc-gen-grpc=yourpath\.nuget\packages\Grpc.Tools\1.0.0\tools\windows_x64\grpc_csharp_plugin.exe result.proto

protoc.exe --csharp_out=d:\grpcdemo\code\ --grpc_out=d:\grpcdemo\code\ --plugin=protoc-gen-grpc=yourpath\.nuget\packages\Grpc.Tools\1.0.0\tools\windows_x64\grpc_csharp_plugin.exe RPCDemoService.proto

   

3.創建.net core 類型項目App.RPCDemo

Project.json文件內容如下:

{

"version": "1.0.0-*",

"dependencies": {

"Grpc.Tools": "1.0.0"

},

"frameworks": {

"netstandard1.6": {

"imports": "dnxcore50",

"dependencies": {

"NETStandard.Library": "1.6.0",

"Grpc": "1.0.1-pre1",

"Grpc.Core": "1.0.1-pre1",

"Google.Protobuf": "3.1.0",

"System.Interactive.Async": "3.0.0"

}

}

}

}

   

4.創建服務端App.RPCDemoServer

因為要在docker 中進行測試,官方網站並沒有docker 下的例子,也沒有說這個rpc在生產環境中如何hosting; 通過查看.net core的host源碼在Microsoft.AspNetCore.Hosting.Internal.ApplicationLifetime這個類文件有實現,把這個文件的內容直接copy過來

類的部分內容如下:

private readonly CancellationTokenSource _startedSource = new CancellationTokenSource();

private readonly CancellationTokenSource _stoppingSource = new CancellationTokenSource();

private readonly CancellationTokenSource _stoppedSource = new CancellationTokenSource();

   

/// <summary>

/// Triggered when the application host has fully started and is about to wait

/// for a graceful shutdown.

/// </summary>

public CancellationToken ApplicationStarted => _startedSource.Token;

   

/// <summary>

/// Triggered when the application host is performing a graceful shutdown.

/// Request may still be in flight. Shutdown will block until this event completes.

/// </summary>

public CancellationToken ApplicationStopping => _stoppingSource.Token;

   

/// <summary>

/// Triggered when the application host is performing a graceful shutdown.

/// All requests should be complete at this point. Shutdown will block

/// until this event completes.

/// </summary>

public CancellationToken ApplicationStopped => _stoppedSource.Token;

   

google Grpc中的server類型沒有接口,定義一個接口Iserver

namespace App.RPC.Core

{

public interface IServer

{

void Start();

   

void Stop();

   

Status State { get; set; }

}

   

public enum Status

{

None,

Stop,

Running

   

}

}

   

在創建一個hosting 文件內容如下:

   

public static class RpcHostExtensions

{

public static void Run(this IServer server)

{

var done = new ManualResetEventSlim(false);

using (var cts = new CancellationTokenSource())

{

Action shutdown = () =>

{

if (!cts.IsCancellationRequested)

{

server.Stop();

Console.WriteLine("Rpc Service is shutting down...");

cts.Cancel();

}

done.Wait();

};

   

#if NETSTANDARD1_5

var assemblyLoadContext = AssemblyLoadContext.GetLoadContext(typeof(WebHostExtensions).GetTypeInfo().Assembly);

assemblyLoadContext.Unloading += context => shutdown();

#endif

Console.CancelKeyPress += (sender, eventArgs) =>

{

shutdown();

// Don't terminate the process immediately, wait for the Main thread to exit gracefully.

eventArgs.Cancel = true;

};

   

server.Run(cts.Token, "Rpc Service started. Press Ctrl+C to shut down.");

done.Set();

}

}

   

/// <summary>

/// Runs a web application and block the calling thread until token is triggered or shutdown is triggered.

/// </summary>

/// <param name="host">The <see cref="IWebHost"/> to run.</param>

/// <param name="token">The token to trigger shutdown.</param>

public static void Run(this IServer server, CancellationToken token)

{

server.Run(token, shutdownMessage: null);

}

   

private static void Run(this IServer server, CancellationToken token, string shutdownMessage)

{

if (server.State != Status.Running)

{

server.Start();

}

   

var applicationLifetime = new ApplicationLifetime();

if (!string.IsNullOrEmpty(shutdownMessage))

{

Console.WriteLine(shutdownMessage);

}

   

token.Register(state =>

{

((ApplicationLifetime)state).StopApplication();

},

applicationLifetime);

   

applicationLifetime.ApplicationStopping.WaitHandle.WaitOne();

   

}

}

   

實現服務RPCDemoImpl

public class RPCDemoImpl : RPCDemoService.RPCDemoServiceBase

{

public override Task<Response> Add(DemoRequest request, ServerCallContext context)

{

 

return Task.FromResult(new Response { Message = "成功" + context.Host + DateTime.Now.Ticks.ToString(), Sucess = true });

}

   

public override Task<DemoList> Get(Search request, ServerCallContext context)

{

var result = new DemoList();

result.Details.Add(new DemoRequest()

{

CommentId = 1,

Id = DateTime.Now.Ticks.ToString(),

IsDeleted = false

});

return Task.FromResult(result);

   

}

   

public override Task<DemoRequest> GetById(DemoId request, ServerCallContext context)

{

return Task.FromResult(new DemoRequest()

{

CommentId = request.Id,

Id = DateTime.Now.Ticks.ToString(),

IsDeleted = false

});

}

}

   

program文件如下:

public class Program

{

public static void Main(string[] args)

{

string host = "0.0.0.0";

int port = 9007;

var dic = Common.GetArgs(args);

if (dic != null && dic.Count > 0)

{

string tempHost;

string tempPort;

if (dic.TryGetValue("host", out tempHost))

{

host = tempHost;

}

if (dic.TryGetValue("port", out tempPort))

{

port = Convert.ToInt32(tempPort);

}

}

   

GrpcServer server = new GrpcServer

{

Services = { RPCDemoService.BindService(new RPCDemoImpl()) },

Ports = { new ServerPort(host, port, ServerCredentials.Insecure) }

};

Console.WriteLine("Google Grpc Starting");

foreach (var item in server.Ports)

{

Console.WriteLine(string.Format("RPC server {0} listening on port {1}", item.Host, item.Port));

}

server.Run();

   

}

}

   

編譯發布后運行如下:

   

客戶端程序

public static void Main(string[] args)

{

string host = "127.0.0.1";

string port = "9007";

long length = 10;

var dic = Common.GetArgs(args);

if (dic != null && dic.Count > 0)

{

string tempHost;

string tempPort, tempLength;

   

if (dic.TryGetValue("host", out tempHost))

{

host = tempHost;

}

if (dic.TryGetValue("port", out tempPort))

{

port = tempPort;

}

   

if (dic.TryGetValue("repeat", out tempLength))

{

length = Convert.ToInt64(tempLength);

}

}

   

Channel channel = new Channel(string.Format("{0}:{1}", host, port), ChannelCredentials.Insecure);

var client = new RPCDemoService.RPCDemoServiceClient(channel);

   

var stopwatch = Stopwatch.StartNew();

for (var i = 0; i < length; i++)

{

   

var reply = client.GetById(new DemoId() { Id = i });

Console.WriteLine("receive" + JsonConvert.SerializeObject(reply));

}

stopwatch.Stop();

   

Console.WriteLine(string.Format("repeat={0}, time={1} Milliseconds, time/repeat={2}", length, stopwatch.ElapsedMilliseconds, stopwatch.ElapsedMilliseconds / (float)length));

Console.ReadKey();

   

channel.ShutdownAsync().Wait();

   

}

   

編譯發布運行如下:

   

   

   

Centos 7測試如下:

服務端

[demo@node139 App.RPCDemoServer]$ docker run --name rcpdemo -d -p 9007:9007 grpcemoserver

966b44acb2e0757c45b7dcf2d865e424dc764e50844e312ef2ea374999992a55

客戶端

[demo@node139 App.RPCDemoClient]$ dotnet App.RPCDemoClient.dll host=192.168.190.139 port=9007 repeat=1

receive{"Id":"636138810040717530","CommentId":0,"IsDeleted":false}

   

docker中演示和源碼地址:https://github.com/yjpgfwxf/App.GRPCDemo.NetCore

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM