当前位置: 首页 > 科技观察

微服务架构中常用的解决方案总结了传统的服务发现方案

时间:2023-03-19 01:47:09 科技观察

一般情况下我们要访问服务的时候,需要知道服务实例的地址和端口。如果服务实例的地址和端口是固定的,我们可以直接在文件中使用配置,但是在大多数在线生产环境中,服务实例的地址是动态分配的,尤其是在容器部署的情况下。地址只能在服务实例实际部署后才能获取,服务调用者根本无法提取服务实例地址和端口,服务实例的地址和端口只能在运行时通过服务发现组件解析服务名称来获取。简单来说,服务发现就是通过服务名称找到提供服务的实例的地址和端口,主要用来解决如何获取服务实例地址的问题。近年来,随着容器技术的兴起,大量的服务分散在整个系统中,服务之间的调用需要通过服务发现来实现。服务发现是分布式系统中不可或缺的关键组件。Zookeeper、Etcd和Consul等开源框架通常用于构建服务发现解决方案。本文主要介绍如何构建基于Zookeeper、Etcd、Consul的服务发现方案,并讨论其可能存在的问题。一个标准的服务发现架构主要由三部分组成:服务注册中心、服务调用者和服务提供者。架构图如下:服务注册中心是服务发现的核心组件,本质上是一个服务名称和服务实例地址映射集除了提供基本的服务名称解析功能外,还需要具备以下能力:故障Tolerance:服务注册中心存储了分布式系统中所有服务名称和服务实例地址之间的映射关系。一旦发生故障,整个系统将被破坏。不可用,这是整个分布式系统的核心,必须具备高可用性;服务健康检查:服务注册中心必须能够及时发现故障实例并注销,以防止错误访问;监控器(Watcher):服务注册中心必须具备及时通知服务调用方服务实例注册或注销的能力,以便服务调用方及时采取措施。服务实例的注册和注销一般有两种选择:服务实例自注册即Self-Registration模式。服务实例启动成功后,主动将自己注册到服务注册中心。这种方法的优点是结构简单,但需要为服务使用。每种编程语言都实现了注册码;通过其他组件注册服务实例就是Third-partyRegistration方式,比如使用一个独立的Agent通过轮询或者监听事件来跟踪运行服务实例的变化,进行注册或者注销。优点是服务实例和服务注册中心解耦但是第三方组件的引入增加了架构的复杂性。服务发现方案DNSDNS(DomainNameSystem)是一种通过解析域名来获取IP和端口的机制。将SRV记录注册到DNS服务器,通过DNS解析过程进行解析。但是DNS存在两个问题:一是服务实例启动后很难将SRV记录注册到DNS服务器,需要人工维护;二是DNS严重依赖缓存,服务使用者无法及时知道一个服务实例是否已经停止。mDNSmDNS(multicastDNS即多播DNS)是一种零配置的服务发现机制,常用于内部网络。每个服务都内置了mDNS响应程序,所以不需要单独的服务注册中心。mDNS最大的问题在于它需要网络基础设施支持IP组播(IPmulticast),这对于云环境来说显然不能令人满意,而且mDNS也无法解决DNS缓存问题。DNS和mDNS都具有良好的容错能力,但缺乏服务健康检查和变更通知机制。ZookeeperZookeeper提供分布式协调服务。它常用于分布式系统中,用于配置管理、名称服务、分布式锁和组管理。它通常运行在一组节点上以实现容错(当运行在n个节点上时,它可以容忍n/2个节点同时失效)。如何通过Zookeeper实现服务发现?Zookeeper使用临时节点来实现服务注册和基本的健康检查功能。每当一个服务实例启动时,都会在Zookeeper中注册一个临时节点,当服务实例出现故障或下线时,这个临时节点会被Zookeeper自动删除。如果其他服务依赖该服务,可以设置监控服务实例对应的临时节点。当一个临时节点被删除时,依赖它的其他服务会收到通知。依靠Zookeeper自身的高可用和临时节点提供的健康检查和监控机制,实现容错的服务发现机制。在实际开发过程中,推荐使用ApacheCurator来替代Zookeeper的原生客户端库。ApacheCurator封装了Zookeeper的原生API,并提供了更高抽象级别的API,使Zookeeper使用起来更简单、更可靠。它还提供了专门用于实现服务发现的API。EtcdEtcd是一个基于Raft共识算法的可线性化的Key-Value存储系统。可以为每个键设置TTL(生存时间)。当TTL过期时,对应的Key会自动过期。基于Etcd的服务发现方案,使用Etcd作为服务注册中心。服务实例注册就是在Etcd中建立Key-Value记录。服务实例本身或代理负责设置并定期更新其关联Key的TTL。如果服务实例出现故障,其他对应的Key会在TTL后过期,相当于注销故障服务实例,通过定时心跳监控健康状态。此外,Etcd提供了一种监控机制,允许为Key设置监听器。当Key发生变化时,监听者可以及时得到通知。Etcd自身的高可用特性提供了基于TTL的基础服务健康检查,并基于监控机制及时发现服务实例的变化,使Etcd成为微服务架构中常用的服务发现解决方案。ConsulConsul是一个成熟的服务发现解决方案。其核心是基于线性强一致性的Raft共识算法的Key-Value存储系统作为服务注册中心,并提供代理(Agent)机制,一方面协调服务注册,另一方面提供服务健康检查手。代理(Agent)会在每个运行服务的节点上启动,获取节点地址并将服务实例注册到服务注册中心。在架构上,Consul包括两类组件:Server和Agent。服务注册信息保存在Server上。采用Raft共识算法,保证多个Server之间的数据线性一致,服务注册中心高可用。所有Agent都作为集群节点,使用Gossip协议进行组关系管理和故障检测。当一个Agent加入(启动)或离开(故障)集群时,会通知其他Agent实现服务健康检查和监控功能。Gossip协议常用于集群组关系管理和故障检测。每个节点通过一个或多个引导节点加入集群。引导节点有一个集群中所有节点的列表。每个节点从已知节点列表中随机选择一个节点。组节点定期发送多播消息,最终集群中的所有节点都知道其他节点。这个过程看起来很神奇。事实上,Gossip协议可以在几秒钟内将消息传播到具有数百个节点的集群中。Akka、Riak和Cassandra都使用Gossip协议来维护集群成员列表和故障检测。另外,Consul和Etcd都非常适合容器环境,因为Docker容器在启动和停止时都会发送事件(Event)。基于事件通知机制,可以非常方便的在Consul或Etcd上注册和注销服务实例。总结本文总结了DNS、mDNS等传统的服务发现方案,以及微服务架构中常用的方案。基于Zookeeper、Etcd、Consul的框架解决方案的核心思想是通过一组实例(3个或5个)提供线性强一致性(Linearizable)的分布式高可用Key-Value存储服务,使用Key-值存储作为服务注册中心,当相关Key发生变化时,监听器可以及时通知客户端,通知机制配合服务实例启动或失败时的服务健康检查,客户端可以及时感知服务拓扑变化实现智能路由的方式。从实现的角度来看,它们可以看作是一个中心化的服务发现方案。事实上,线性强一致性并不是服务发现的唯一要求。当数据传播足够快时,最终一致性可以满足要求。在实践中,即使在大型集群中,Gossip协议也可以快速传播数据并收敛到最终一致性,将服务实例作为Gossip集群节点,使用CRDT(无冲突复制数据类型)存储服务注册信息,通过Gossip快速传播,实现集群所有节点的最终一致性。每个节点都存储了所有的服务注册信息,因此不需要单独的服务注册中心,这样实现的方案称为去中心化方案,去中心化的服务发现方案留待下一次分享。