什么是服务发现?
服务发现
是指服务启动后将服务注册信息定时同步刷新到本地或实时获取Consul
的服务信息。
为什么要使用服务注册与发现?
-
屏蔽、解耦服务之间相互依赖的细节
我们知道服务之间的远程调用必须要知道对方的IP、端口信息。我们可以在调用方直接配置被调用方的IP、端口,这种调用方直接依赖IP、端口的方式存在明显的问题,如被调用的IP、端口变化后,调用方法也要同步修改。通过服务发现,将服务之间IP与端口的依赖转化为服务名的依赖,服务名可以根据具微服务业务来做标识,因此,屏蔽、解耦服务之间的依赖细节是服务发现与注册解决的第一个问题。
- 对服务进行动态管理
在微服务架构中,服务众多,服务之间的相互依赖也错综复杂,无论是服务主动停止,意外挂掉,还是因为流量增加对服务实现进行扩容,这些服务数据或状态上的动态变化,都需要尽快的通知到被调用方,被调用方再采取相应的措施。因此,对于服务注册与发现要实时管理着服务的数据与状态,包括服务的注册上线、服务主动下线,异常服务的剔除。服务发现将服务IP、端口等细节通过一个服务名抽象给调用者,并动态管理着各个微服务的状态检测、状态更新,服务上线,下线等,这些都是微服务治理的基础,包括负载均衡,链路跟踪。
创建一个Grpc Service项目
-
提前准备:安装并启动Consul
-
打开 Visual Studio 2022 并创建Grpc Service项目(点击查看完整示例代码1.4open in new window)
安装依赖包
dotnet add package Wing.Consul
Grpc健康检查
protobuf文件
syntax = "proto3";
package grpc.health.v1;
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
enum ServingStatus {
UNKNOWN = 0;
SERVING = 1;
NOT_SERVING = 2;
}
ServingStatus status = 1;
}
service Health {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}
HealthCheck代码
public class HealthCheck : Health.HealthBase
{
public override Task<HealthCheckResponse> Check(HealthCheckRequest request, ServerCallContext context)
{
return Task.FromResult(new HealthCheckResponse() { Status = HealthCheckResponse.Types.ServingStatus.Serving });
}
public override async Task Watch(HealthCheckRequest request, IServerStreamWriter<HealthCheckResponse> responseStream, ServerCallContext context)
{
await responseStream.WriteAsync(new HealthCheckResponse()
{ Status = HealthCheckResponse.Types.ServingStatus.Serving });
}
}
Program代码
using Wing;
var builder = WebApplication.CreateBuilder(args);
builder.Host.AddWing(builder => builder.AddConsul());
// Add services to the container.
builder.Services.AddGrpc();
builder.Services.AddWing();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.MapGrpcService<GreeterService>();
app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
app.Run();
添加配置
{
// 是否启用配置中心,默认启用
"ConfigCenterEnabled": false,
"Consul": {
"Url": "http://localhost:8500",
"Service": {
//Http Grpc
"Option": "Grpc",
"HealthCheck": {
"Url": "localhost:1410",
//单位:秒
"Timeout": 10,
//单位:秒
"Interval": 10,
"GRPCUseTLS": false
},
"Name": "Wing.Demo_1.4",
"Host": "localhost",
"Port": 1410,
"Tag": "",
"LoadBalancer": {
//RoundRobin WeightRoundRobin LeastConnection
"Option": "WeightRoundRobin",
//权重
"Weight": 4
},
"Scheme": "http",
"Developer": "linguicheng"
},
//定时同步数据时间间隔,单位:秒 小于等于0表示立即响应
"Interval": 10,
//数据中心
"DataCenter": "dc1",
//等待时间,单位:分钟
"WaitTime": 3
}
}
查看运行效果
- 运行当前程序并启动示例 1.3,浏览器访问 http://localhost:1310/wingopen in new window ,可以看到注入的Grpc服务
Wing.Demo_1.4
,运行效果如下图:
- 在示例 1.2 中调用当前Grpc服务中
SayHello
方法,代码如下:
[HttpGet("hello")]
public Task<string> SayHello()
{
return _serviceFactory.InvokeAsync("Wing.Demo_1.4", async serviceAddr =>
{
var channel = GrpcChannel.ForAddress(serviceAddr.ToString());
var greeterClient = new Greeter.GreeterClient(channel);
var result = await greeterClient.SayHelloAsync(new HelloRequest { Name = "Wing" });
return result.Message;
});
}
- 运行示例 1.2,浏览器访问 http://localhost:1210/weatherforecast/helloopen in new window ,运行效果如下图:
本教程基于.NET微服务框架Wing, 项目地址:https://gitee.com/linguicheng/Wing