关于golang:服务注册与发现的原理和实现

2次阅读

共计 3186 个字符,预计需要花费 8 分钟才能阅读完成。

什么是服务注册发现?

对于搞微服务的同学来说,服务注册、服务发现的概念应该不会太生疏。

简略来说,当服务 A 须要依赖服务 B 时,咱们就须要通知服务 A,哪里能够调用到服务 B,这就是服务注册发现要解决的问题。

  • Service B 把本人注册到 Service Registry 叫做 服务注册
  • Service AService Registry 发现 Service B 的节点信息叫做 服务发现

服务注册

服务注册是针对服务端的,服务启动后须要注册,分为几个局部:

  • 启动注册
  • 定时续期
  • 退出撤销

启动注册

当一个服务节点起来之后,须要把本人注册到 Service Registry 上,便于其它节点来发现自己。注册须要在服务启动实现并能够承受申请时才会去注册本人,并且会设置有效期,避免过程异样退出后仍然被拜访。

定时续期

定时续期相当于 keep alive,定期通知 Service Registry 本人还在,可能持续服务。

退出撤销

当过程退出时,咱们应该被动去撤销注册信息,便于调用方及时将申请散发到别的节点。同时,go-zero 通过自适应的负载平衡来保障即便节点退出没有被动登记,也能及时摘除该节点。

服务发现

服务发现是针对调用端的,个别分为两类问题:

  • 存量获取
  • 增量侦听

还有一个常见的工程问题是

  • 应答服务发现故障

当服务发现服务(比方 etcd, consul, nacos 等)呈现问题的时候,咱们不要去批改曾经获取到的 endpoints 列表,从而能够更好的确保 etcd 等宕机后所依赖的服务仍然能够失常交互。

存量获取

Service A 启动时,须要从 Service Registry 获取 Service B 的已有节点列表:Service B1, Service B2, Service B3,而后依据本人的负载平衡算法来抉择适合的节点发送申请。

增量侦听

上图曾经有了 Service B1, Service B2, Service B3,如果此时又启动了 Service B4,那么咱们就须要告诉 Service A 有个新增的节点。如图:

应答服务发现故障

对于服务调用方来说,咱们都会在内存里缓存一个可用节点列表。不论是应用 etcdconsul 或者 nacos 等,咱们都可能面临服务发现集群故障,以 etcd 为例,当遇到 etcd 故障时,咱们就须要解冻 Service B 的节点信息而不去变更,此时肯定不能去清空节点信息,一旦清空就无奈获取了,而此时 Service B 的节点很可能都是失常的,并且 go-zero 会主动隔离和复原故障节点。

服务注册、服务发现的基本原理大抵如此,当然实现起来还是比较复杂的,接下来咱们一起看看 go-zero 里反对哪些服务发现的形式。

go-zero 之内置服务发现

go-zero 默认反对三种服务发现形式:

  • 直连
  • 基于 etcd 的服务发现
  • 基于 kubernetes endpoints 的服务发现

直连

直连是最简略的形式,当咱们的服务足够简略时,比方单机即可承载咱们的业务,咱们能够间接只用这种形式。

rpc 的配置文件里间接指定 endpoints 即可,比方:

Rpc:
  Endpoints:
  - 192.168.0.111:3456
  - 192.168.0.112:3456

zrpc 调用端就会调配负载到这两个节点上,其中一个节点有问题时 zrpc 会主动摘除,等节点复原时会再次调配负载。

这个办法的毛病是不能动静减少节点,每次新增节点都须要批改调用方配置并重启。

基于 etcd 的服务发现

当咱们的服务有肯定规模之后,因为一个服务可能会被很多个服务依赖,咱们就须要可能动静增减节点,而无需批改很多的调用方配置并重启。

常见的服务发现计划有 etcd, consul, nacos 等。

go-zero 内置集成了基于 etcd 的服务发现计划,具体应用办法如下:

Rpc:
  Etcd:
     Hosts:
     - 192.168.0.111:2379
     - 192.168.0.112:2379
     - 192.168.0.113:2379
     Key: user.rpc
  • Hostsetcd 集群地址
  • Key 是服务注册下来的 key

基于 Kubernetes Endpoints 的服务发现

如果咱们的服务都是部署在 Kubernetes 集群上的话,Kubernetes 自身是通过自带的 etcd 治理集群状态的,所有的服务都会把本人的节点信息注册到 Endpoints 对象,咱们能够间接给 deployment 权限去读取集群的 Endpoints 对象即可取得节点信息。

  • Service B 的每个 Pod 启动时,会将本人注册到集群的 Endpoints
  • Service A 的每个 Pod 启动时,能够从集群的 Endpoints 里获取 Service B 的节点信息
  • Service B 的节点产生扭转时,Service A 能够通过 watch 集群的 Endpoints 感知到

在这个机制工作之前,咱们须要配置好以后 namespacepod 对集群 Endpoints 拜访权限,这里有三个概念:

  • ClusterRole

    • 定义集群范畴的权限角色,不受 namespace 管制
  • ServiceAccount

    • 定义 namespace 范畴内的 service account
  • ClusterRoleBinding

    • 将定义好的 ClusterRole 和不同 namespaceServiceAccount 进行绑定

具体的 Kubernetes 配置文件能够参考 这里,其中 namespace 按需批改。

留神:当启动时报没有权限获取 Endpoints 时记得查看这些配置有没落实 :)

zrpc 的基于 Kubernetes Endpoints 的服务发现应用办法如下:

Rpc:
  Target: k8s://mynamespace/myservice:3456

其中:

  • mynamespace:被调用的 rpc 服务所在的 namespace
  • myservice:被调用的 rpc 服务的名字
  • 3456:被调用的 rpc 服务的端口

在创立 deployment 配置文件时肯定要加上 serviceAccountName 来指定应用哪个 ServiceAccount,示例如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: alpine-deployment
  labels:
    app: alpine
spec:
  replicas: 1
  selector:
    matchLabels:
      app: alpine
  template:
    metadata:
      labels:
        app: alpine
    spec:
      serviceAccountName: endpoints-reader
      containers:
      - name: alpine
        image: alpine
        command:
        - sleep
        - infinity

留神其中 serviceAccountName 指定该 deployment 创立进去的 pod 用哪个 ServiceAccount

serverclient 都部署到 Kubernetes 集群里之后能够通过以下命令滚动重启所有 server 节点

kubectl rollout restart deploy -n adhoc server-deployment

利用如下命令查看 client 节点日志:

kubectl -n adhoc logs -f deploy/client-deployment --all-containers=true

能够看到咱们的服务发现机制完满跟进了 server 节点的变动,并且在服务更新期间没有出现异常申请。

残缺代码示例见 https://github.com/zeromicro/zero-examples/tree/main/discovery/k8s

下一篇文章我将解说在 go-zero 里如何实现基于 consul, nacos 等的服务注册发现,敬请期待!

我的项目地址

https://github.com/tal-tech/go-zero

欢送应用 go-zerostar 反对咱们!

微信交换群

关注『微服务实际 』公众号并点击 交换群 获取社区群二维码。

正文完
 0