gRPC服务发现与服务治理,目前常见解决方案有以下两种
- Nginx + consul + consul-template
- Envoy
本文粗略讲解一下两种方案的优缺点
一. nginx + consul + consul-template实现步骤
- grpc微服务注册到consul, consul会定时发送心跳到grcp微服务
- 当consul节点有更新时, consul-template生成nginx-consul.conf文件
- nginx reload完成服务更新, 当有请求时upstream转发到grpc微服务
nginx-consul.conf大致如下
# nginx需要安装grpc模块
upstream User {
server 127.0.0.1:17000;
server 127.0.0.1:18000;
}
server {
listen 19000 http2;
server_name _;
location /protobuf.User {
default_type application/grpc;
grpc_pass grpc://User;
}
}
复制代码
优点
- 简单易用,文档丰富
缺点
- consul心跳只是以ping tcp端口为标准, 无法确定服务是否正常响应
- 当有节点上线或下线时, 需要nginx reload. 有一定风险 (微服务在运行时难免会触发隐藏Bug或者panic, 如果每次都要nginx reload来确保健康的路由,我认为代价太大)
大家都发现这个图里面少了consul注册中心, 是不是意味使用Envoy就不需要注册中心? 答案是看情况而定Envoy 是专为大型现代 SOA(面向服务架构)架构设计的 L7 代理和通信总线。是istio重要组件之一
因为Envoy支持动态配置,所以Istio中是搭配pilot使用, pilot可以通过consul,etcd等注册中心获取在线节点, 然后动态注册到Envoy.
envoy.yaml
node:
id: id_1
cluster: test_cluster
watchdog:
miss_timeout: 0.2s
megamiss_timeout: 1s
kill_timeout: 0s
multikill_timeout: 0s
admin:
access_log_path: /var/log/admin_access.log
address:
socket_address: { address: 127.0.0.1, port_value: 10000 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 127.0.0.1, port_value: 19000 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
stat_prefix: ingress_http
codec_type: HTTP2
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/protobuf.User" }
route: { cluster: xds_cluster }
http_filters:
- name: envoy.router
clusters:
- name: xds_cluster
connect_timeout: { seconds: 1 }
type: STATIC
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
hosts:
- socket_address: { address: 127.0.0.1, port_value: 18000 }
- socket_address: { address: 127.0.0.1, port_value: 17000 }
health_checks:
- grpc_health_check: {service_name: YourServiceName}
unhealthy_threshold : 1
healthy_threshold: 1
timeout: 0.5s
interval: 0.5s
interval_jitter: 0.5s
复制代码
这是一个静态的路由配置,带grpc健康检查, 有四个关键点
- listeners : 监听127.0.0.1:19000
- filters : 过滤grpc请求,路由到xds_cluster
- clusters : 由hosts组成的集群
- health_checks: grpc健康检查
如何实现grpc健康检查
# 引入protobuf包google.golang.org/grpc/health/grpc_health_v1并实现里面的Check和Watch方法
package health
import(
"log"
"context"
pb "google.golang.org/grpc/health/grpc_health_v1"
)
type Health struct{}
func New() *Health {
return &Health{}
}
func (h *Health) Check(ctx context.Context, in *pb.HealthCheckRequest) (*pb.HealthCheckResponse, error){
log.Printf("checking............%s", in.Service)
var s pb.HealthCheckResponse_ServingStatus = 1
return &pb.HealthCheckResponse{
Status : s,
}, nil
}
func (h *Health) Watch(in *pb.HealthCheckRequest, w pb.Health_WatchServer) (error){
log.Printf("watching............%s", in.Service)
var s pb.HealthCheckResponse_ServingStatus = 1
r := &pb.HealthCheckResponse{
Status : s,
}
for {
w.Send(r)
}
return nil
}
复制代码
# 服务注册
pb.RegisterHealthServer(grpcServer, health.New())
复制代码
启动envoy和grpc服务后, grpc就会收心跳(默认的心跳是60秒,yaml的心跳设置是0.5秒)
YourServiceName就是yaml中grpc_health_check的service_name参数,这里你可以自定义你想监听的方法
优点
- 轻量级,无侵入式.服务发现由envoy主动发现,grpc不需要特定配置,
- 自带grpc健康检查
- 动态配置
缺点
- 相关中文文档比较少
相对于nginx, 我更倾向于envoy,首先envoy就是为微服务而生的负载匀衡工具. grpc健康检查是微服务中重要的一环. 但是nginx拥有活跃的社区,说不定不久将来也会有支持grpc健康检查的插件.