微服务管理 | 服务注册与发现

127 阅读3分钟

一句话

分布式系统中,服务往往是独立运行的,他们之间如何交流也是有很多可以挖掘的点。让服务之间自动“找到彼此”,并建立连接,且在服务增删变化时,连接关系能自动调整,这就是服务注册和发现要做的事情

为什么需要服务发现

例子 1:网关找登录服

  • 登录服可能多台,地址也可能变。
  • 如果靠配置文件写死,运维一改地址就会出错。
  • 服务发现就像“自动通讯录”,登录服上线就自动加入,掉线就自动移除。

服务发现要做到什么

简单理解就是三件事:

  1. 注册:服务实例将自身节点信息写入注册中心(例如 Zookeeper),也就是服务自己把“我是谁、我的网络地址是什么” 写进去
  2. 发现:订阅并获取自己关心的服务节点,即能拿到“我发现了哪些服务以及需要连接哪些服务”
  3. 更新:服务变化时自动通知,变更不仅有“来/走”,还有“节点属性更新”(比如权重/版本变化)

通俗地说,对于一个服务:

  • 启动时先给我一张其他服务的完整名单(快照)
  • 运行中有服务加入或离开就通知我(增量订阅)

这里其实有一个数据的一致性需求 :启动时需要“全量快照”,运行时需要“增量变更”,避免漏连或重复。

实现方案

1) 注册:服务自己告诉系统“我是谁”,我的地址是多少

每个服务启动后把信息写进注册中心,通常就是 key-value 的形式,比如:

login.tcp.3 => 10.1.2.3:8001

这里,login 是服务类型,tcp 是地址的类型(也可以是http),3 是服务的编号,这对于有状态服务的区分比较重要。

如果要更多信息,也可以带上权重、版本、元数据:

10.1.2.3|8001|20|v1|{"region":"cn"}

2) 发现:获得别的服务的地址,关注地址变更

服务启动后订阅自己关心的目标,例如:

  • Gate 关心 Login、Router
  • Game 关心 Battle、Router

当 Gate 启动时,需要先拿到 全量快照

snapshot = [login-1, login-2, login-3, router-1, router-2]

这些服务的地址如果发生了变更,如权重从 20 变成 0,就需要关注。

3) 增量:有变化就通知

如果登录服新增了一台:

新增: login-tcp-4

订阅者收到事件后,只需要做一件事: 建立和 login-tcp-4 的连接

如果 login-tcp-2 下线:

删除: login-2

订阅者自动断开即可。

简化流程图(Mermaid)

我们把上面的几个过程串联起来,得到一个流程图:

image.png

更深入的点

  1. 在现代 kubernetes 云部署盛行的当下,服务注册和发现往往已经支持,但是如果需要自己来更细粒度更深度的定制和控制路由,自己实现一套服务注册和发现是很有必要的;
  2. 如果是 kubernetes 部署,服务注册的地址一般是 DNS 域名,因为服务本身的地址是会动态变化的;
  3. 在很多异构的系统中,往往由不同的语言来实现不同的服务,为了避免实现多套服务注册和发现,增加维护成本,可以将其抽象成agent 服务(以sidecar的形式部署),使用方用 gRPC 这种解耦的协议形式,和 agent 通信。

总结

  • 服务注册和发现做的是一套“自动通讯录 + 实时变更提醒”
  • 快照解决“启动时看到全量”
  • 增量解决“运行中看到变化”
  • 可以挖掘更适合k8s及异构系统的实现方式