1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-28 23:42:21 +00:00
advanced-go-programming-book/ch6-web/ch6-11-service-discovery.md
2018-06-01 17:16:02 +08:00

3.5 KiB
Raw Blame History

6.11. Service Discovery 服务发现

在微服务架构中,服务之间是存在依赖的。例如在订单系统中创建订单时,需要对用户信息做快照,这时候也就意味着这个流程要依赖: 订单、用户两个系统。当前大型网站的语境下,多服务分布式共存,单个服务也可能会跑在多台物理/虚拟机上。所以即使你知道你需要依赖的是“订单服务”这个具体的服务,实际面对的仍然是多个 ip+port 组成的集群。因此你需要: 1. 通过“订单服务”这个名字找到它对应的 ip+port 列表2. 决定把这个请求发到哪一个 ip+port 上的订单服务。

ip+port 的组合往往被称为 endpoint。通过“订单服务”去找到这些 endpoint 的过程,叫做服务发现。选择把请求发送给哪一台机器,以最大化利用下游机器的过程,叫做负载均衡。本节主要讨论服务发现。

为什么不用 ip+port 直接连依赖服务?

在大多数公司发展初期,物理机器比较少,内网 ip 也很少。一些创业公司虽然开发人员众多,但因为业务限制,每一个服务的 QPS 都不高。因此确实有很多公司服务之间是通过 ip+port 来进行相互调用的。再原始一些的话,甚至可能所有服务都在一个工程下,那也就没有什么依赖问题了。

随着公司业务规模的发展,可能慢慢会衍生出流量较大的接口,早期我们也没有那么多设计上的讲究,所以就按流量先进行接口拆分。一旦进行了拆分,那就会涉及到模块/服务之间的依赖问题。而流量大的服务往往一台机器还不够,所以你面临的是多个 ip+port 的组合的依赖。随着业务越来越复杂,这种类型的服务越来越多。我们还是需要把这一大堆 ip+port 按照服务名来进行划分,并能够通过名字找到对应的 ip+port 数组。

拆分后,如果依赖服务所在的机器挂掉了,也就意味着那个 ip+port 不可用了。这时候上游需要有某种反馈机制能够及时知晓,并且能够在知晓之后,不经过上线就能将已经失效的 ip+port 自动从依赖中摘除。

我们先来看看怎么通过服务名字找到这些 ip+port 列表。

怎么通过服务名字找到 endpoints

把一个名字映射到多个 ip+port 这件事情,大多数人脑子里冒出的第一个想法应该是 "dns服务"。确实 dns 就是干这件事情的,有一些公司会提供内网 dns 服务,服务彼此之间通过 dns 来查找服务节点,这种情况下,你使用的下游服务的名字可能是类似 api.order.service_endpoints 的字符串,当然,如果这个 dns 服务是你来开发的话,这种字符串你可以随意定义。只要能用 namespace 按业务部门和相应的服务区分开就可以。实现内网 dns 服务的话,你还可以使用更激进的刷新策略(例如:一分钟刷新一次),不像公网的 dns 那样需要很长时间甚至一整天才能生效。

不过使用公共的 dns 服务也存在问题,我们的 dns 服务会变成整个服务的集中的那个中心点,这样会给整个分布式系统带来一定的风险。一旦 dns 服务挂了,那么我们也就找不到自己的依赖了。我们可以使用自己本地的缓存来缓解这个问题。比如某个服务最近访问过下游服务,那么可以将下游的 ip+port 缓存在本地,如果 dns 服务挂掉了,那我至少可以用本地的缓存做个兜底,不至于什么都找不到。

TODOTODO这里应该有图

故障节点摘除