分布式架构-服务发现
服务发现
解决的核心问题: 怎么确定方法的精确位置
发现一个服务的流程
通过三元组来定位一个服务: 全限定名(IP), port, 服务标识
- 全限定名(IP): 标识是网络中的哪一台主机
- port: 标识是主机中的哪个应用进程
- 服务标识: 标识是应用进程中的哪个方法
服务发现流程
- 消费方的服务发现框架向注册中心请求获取服务坐标
- 注册中心返回某个具体的应用实例的服务坐标(全限定名 + port)
- 消费方的服务发现框架通过RPC协议向应用实例的服务坐标发送序列化后的方法名+参数列表
- 应用实例侧的RPC框架将序列化后的方法名+参数列表反序列化, 执行方法, 并返回结果给消费方.
服务发现可以分成三个子步骤
服务的注册: 在某个服务启动的时候, 将这个服务注册到注册中心, 有两种注册形式
- 自注册: 自己将自己注册到注册中心
- 第三方注册: 通过第三方的应用或者容器编排服务来将服务注册到注册中心
服务的维护: 维护可用服务列表, 以避免出现注册中心返回服务实例, 实际上不可用的情况.
- 通过长连接, 心跳, 探针等方式来保活
服务的发现: 调用方从服务发现框架中, 将一个符号转化成一个具体的可访问的服务坐标的过程
- 一般通过DNS Lookup或者HTTP API来实现
这三者只是服务发现框架提供的最基本的功能, 实际上在现代的服务发现框架中往往还提供了服务发现时的负载均衡, 流量管控, 键值存储等拓展功能.
可用性和可靠性
服务发现是分布式系统的基础设施, 不依赖其他服务,同时被其他服务共同依赖. 依赖特性决定了服务发现既要高可用又要高可靠(当然因为CAP定理, 这是不可能实现的事情).
这里的含义是我们在保证高可用(高可靠)的前提下, 尽可能提供高可靠(高可用), 在生产环境中服务发现服务往往是通过集群的形式部署的.
服务发现的CP和AP详细指的是维护服务的可用服务列表我们要保证AP还是CP.
Eureka
Eureka: 保证高可用, 采用异步复制, 一个新的服务已经注册就宣布可用, 在有节点下线或断网的时候, 会有超时机制来控制什么时候将这个服务从可用列表中移除. 这样TTL超时机制导致每个节点都有一份自己的可用服务列表缓存
- 能这么做的前提是Eureka有Netflix OSS那样完整的微服务全家桶来兜底, 有着其他的组件来保证在访问了不可用的服务的时候能进行故障转移或快速失败
Consul
Consul: 优先保证高可靠, 添加新节点的时候, 通过Raft算法只有在多数派都成功复制的时候才会成功返回. 通过Gossip算法来完成多数据中心之间的服务同步
什么时候选择高可用, 什么时候选择高可靠
假设系统形成了A, B两个分区, A区域的服务只能从区域内的服务发现节点中获取A区的服务坐标. B区的服务只能取到B区的服务坐标. 衡量这个结果能不能承受.
- 如果能够承受, 甚至是有利的, 就应该选择AP服. 比如A区和B区均部署了全量的服务, 也就是他们都各自能提供完整且正确的服务, 这个时候网络分区在事实上避免了跨机房访问, 反而提供了服务调用链路优化的效果
- 如果不能够承受, 错误的服务带来的影响很大, 这个时候就应该选择CP服务. 比如系统中大量依赖了集中式缓存, 消息总线等组件, 这个时候出现网络分区导致这些服务组件全被隔离到某个区域里了, 对整个系统的操作的正确性产生了影响, 还不如直接停机.
服务发现框架
在分布式K/V存储框架上自己开发的服务发现: Zookeeper, Doozerd, Etcd
- 这些分布式存储框架往往提供了分布式环境下读写操作的共识算法, 所以自然是CP的, Zookeeper是ZAB协议, Etcd是Raft协议
- 这些框架往往只提供了及其简单的CRUD的API, 想在它们的基础上开发实现服务发现基础的能力, 都需要自己去实现
以基础设施(主要指DNS服务器)来实现服务发现的: SkyDNS, CoreDNS
- SkyDNS: API Server中监听集群服务的变化, 然后根据服务生成DNS记录存放到Etcd中. 调用时只需要查询DNS把域名转化成IP列表来实现分布式的服务发现.
- CoreDNS可以选择是否使用Etcd来存储
- 这种模式下是CP还是AP取决于使用的存储. 基于Etcd实现的, 自然是CP方案, 如果是基于异步复制同步实现的, 自然是AP方案
专门用于服务发现的框架: Eureka, Consul, Nacos
- 这类的服务发现框架, 你自己决定是CP还是AP, Eureka是AP, Consul是CP, Nacos两种都提供(Raft做的CP, 自研的Distro做的AP)
总结
服务发现解决的是在分布式系统中怎么获取一个服务的精确坐标的问题.
通过(全限定名, port, 服务标识)三元组我们能够精确定义一个服务. 在现代的服务发现框架中, 服务标识这一步的处理, 也就是怎么在一个服务中找到我们要调用的方法是交给RPC框架处理的, 服务发现框架实际上提供的是, 通过服务逻辑名获取一个服务的全限定名+port的服务.
服务发现可以分成: 服务的注册, 服务的维护, 服务的发现三个环节.
因为服务发现的基础设施被所有服务共同依赖的特性, 会导致服务发现既要保证可靠性, 也要保证可用性, 因为CAP理论这是不可能的, 我们能做的就是优先保证其中一个, 尽力保证另一个.
我们优先保证CP还是AP, 主要取决于我们能不能忍受分区后的结果, 能忍受就AP, 不能就CP.
服务发现的CP和AP详细指的是维护服务的可用服务列表我们要保证AP还是CP
在现代服务框架主要有三类:
- 基于分布式K/V存储二次开发, 常见的有Etcd, Zookeeper, 这两个都是CP方案, 这个方案的二次开发任务量大.
- 通过基础设施提供, 也就是DNS服务器来提供, 常见的有SkyDNS和CoreDNS. 前者使用Etcd存储DNS信息, 是CP方案, 后者可选Etcd还是异步复制同步, 可选CP或AP.
- 专门用于服务发现的框架: Nacos, Eureka, Consul. 前者可选CP, AP. Eureka是AP, Consul是CP.
