微服务设计学习(三)服务治理之服务注册与发现

3,175 阅读12分钟

前言

欢迎阅读往期系列:

在微服务大行其道的今天,服务的粒度被拆分得非常细,随之而来的是服务数量的迅速增长。在云原生的浪潮中,服务治理更多情况下与容器调度平台结合,共同形成一站式的自动化调度治理平台。

当然无论是否使用基于容器的调度系统,服务治理的原理和范畴都不会发生改变,只是实现方式不同而已。

服务治理主要包括服务发现、负载均衡、限流、熔断、超时、重试、服务追踪等。我们今天要讲的,就是服务发现的内容

本章概要

本章主要介绍以下内容:

  1. 什么是服务发现?(what)
  2. 微服务框架下为什么需要服务发现呢?(why)
  3. 服务发现是怎么运作的呢?(how)
  4. CAP定理
  5. 现有的几种解决方案介绍 (implementations)

现在,让我们开始本次的旅程吧。

什么是服务发现(what)

服务发现指的是寻找一个service provider的 网络位置信息。

具体指的是,使用一个注册中心来记录分布式系统中全部服务的信息,以便让其他服务能够快速找到这些已经注册的服务。

服务发现是支撑大规模SOA和微服务架构的核心模块,需要具有服务注册、服务查找、服务健康检查和服务变更通知等关键功能。

为什么需要服务发现?(why)

因为没有服务发现模块的话,服务网络位置信息的配置会耦合在具体服务消费者的配置当中,从而导致系统难以维护。

想想这么一个基本的问题:服务消费者们是如何知道服务提供者的IP和端口的呢?

在简单的体系架构中,静态配置(比如DNS、Nignx负载均衡配置等)的方法可以很好的解决问题。每个服务都部署在同一个位置,并且很少更改。没有弹性伸缩的需求。传统的单体式应用的网络地址发生变化的概率较小,在发生变化的时候,运维人员手动更新、加载配置文件即可。

但是在微服务架构中并非如此,微服务更新、发布频繁,并且经常会根据负载情况进行弹性伸缩,因为微服务应用实例的网络地址变化是一个很常态的事情,而我们前面提到的静态配置的解决方案,显然不适合这么一个高度动态的场景。所以,我们需要提供一种机制(模块),让服务消费者在服务提供者的IP地址发生变化的时候能够快速及时地获取到最新的服务信息

服务发现是怎么运作的呢?(how)

前面说过,使用一个注册中心来记录分布式系统中全部服务的信息,以便让其他服务能够快速找到这些已经注册的服务。

让我们用两个例子来说明服务发现运作的机制(简单版本):

image.png

  1. biz service启动,告诉服务中心它的服务信息,服务中心完成写入
  2. admin service启动,向服务中心请求biz service的服务信息
  3. 服务中心查找对应服务的位置信息,返回给admin service
  4. admin service获取到实际的地址之后,向biz service发起请求

biz service采用集群架构,有更多的节点上线时,整个工作流是怎么样的呢?

image.png

  1. 新启动的节点告诉服务注册发现中心自己的服务信息,服务中心完成写入

  2. admin service发起请求更新 biz service的服务地址列表

    这里举的是client端主动请求去更新信息,是“pull”的方式;还有一种是client端注册回调,等待服务中心通知,是"push"的方式)

CAP 定理

虽然“服务发现”的整个运行机制理解起来很简单,但是在实际的分布式场景下,作为微服务架构体系的一个核心,我们肯定需要采用搭建集群的方式,保证其高可用性。这时候,就需要考虑一个分布式系统可能会遇到的一些问题。

在一个分布式的计算机系统中,只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三个基本特性中的两个,这就是著名的CAP定理。

  • 一致性:指的是所有节点都能够在同一时间返回同一份最新的数据副本;

  • 可用性:指的是每次请求都能够返回非错误的响应;

  • 分区容错性:指的是服务器间的通信即使在一定时间内无法保持畅通也不会影响系统继续运行。

undefined

对于分布式系统来说,分区容错性是必须满足的。因此,必须要在一致性和可用性之间进行取舍,这就是所谓的“选择AP还是选择CP”。

对CAP定理不熟悉的童鞋,可以延伸阅读 - CAP定理

对于服务发现和注册中心集群来说,如果选择一致性而牺牲可用性(选择CP)的话,那么为了保证多点服务中心上的数据一致,一旦某个点的服务中心宕机,服务中心集群都需要暂停对外提供数据写入服务。在保证服务中心集群的数据一致的同时,牺牲了写入服务的可用性。 如果选择可用性而牺牲一致性(选择AP)的话,那么为了保证服务不中断,当某个点的服务中心宕机时,仍然存活的服务中心节点可以选择先将数据写入本地存储然后直接返回客户端,但这样又将导致多个节点之间的数据不一致。

业界提供的用于服务发现注册的系统,本质上都是满足APCP的系统。

现有的解决方案 (implementations)

在分布式服务体系中,所有的服务提供者和消费者都依赖于【服务中心】,如果服务中心出现问题,将会出现服务状态感知不敏感等现象,且波及整个系统。因此,保证用于服务发现的注册中心的可用性至关重要。 为保证注册中心的可用性,要保证多节点部署,如果是大型网站后台通常还要跨多机房进行部署,以确保注册中心在单一机房不可用的情况下仍然可以提供服务。 具有高可用特性的服务中心需要具备以下几个能力:

  1. 具有多节点部署的能力
  2. 在分布式场景下具备自我治愈和调整的能力
  3. 节点健康检查的能力,可以将访问超时的节点从当前集群中移除,也可以将恢复访问能力后的节点再度加入当前集群

在下面的章节中,我们将介绍几个常见的可直接作为注册中心的产品。

Zookeeper

Zookeeper 致力于提供一个高可用且具有严格顺序访问控制能力的分布式协调系统,它是一个分布式数据一致性的解决方案。

ZooKeeper 提供了分布式通知和协调、配置管理、命名服务、主节点选举、分布式锁、分布式队列等完善的解决方案。其中分布式通知和协调被广泛用于服务发现。至今为止,它是服务发现领域历史最为悠久、使用最为广泛的产品。

undefined

本文不具体介绍Zookeeper的一致性协议、数据结构等知识,有兴趣的可以阅读作者之前的Zookeeper文章

Zookeeper学习系列【一】 教会你Zookeeper的一些基础概念 Zookeeper学习系列【三】Zookeeper 集群架构、读写机制以及一致性原理(ZAB协议)

Zookeeper的读写机制和一致性协议决定了它是一个CP系统。

优势与不足

ZooKeeper 作为使用最为广泛的分布式协调组件,优点非常多。使用广泛就是它最大的优点,这也使得ZooKeeper很容易在架构师进行技术选型时占据优势。但是,需要明确说明的是,Zookeeper并不是服务发现领域的最佳选择了,它的优势主要体现在选举和分布式锁等分布式强一致性的场景中。 当ZooKeeper的主节点因为网络故障与其他节点失去联系而触发整个系统选举时,集群是不可用的,这将导致注册服务体系在选举期间瘫痪。

延伸阅读 阿里巴巴为什么不用 ZooKeeper 做服务发现?

服务中心对数据一致性的要求并不是非常苛刻的,也难于做到实时感知宕机(会有时延),它更看重的是自愈能力。通过Zookeeper的客户端Curator的缓存能力能够让ZooKeeper在服务发现领域的适配度更高,但这并非ZooKeeper的原生能力和设计初衷。

etcd

随着CoreOS和Kubernetes等项目在开源社区日益火热,它们项目中都用到的etcd组件作为一个高可用、强一致性的服务发现存储仓库,渐渐走进开发人员的视野。

image.png

etcd 是一个受到Zookeeper启发的项目,和其具有类似的架构和功能,基于更为简单易懂的Raft协议和go语言实现。etcd也是一个CP的系统,对一致性的要求强于可用性的要求。etcd通过TTL(Time To Live,存活时间)来实现类似于Zookeeper临时节点的功能,需要etcd客户端不断地定时续租节点来判断服务的运行状态。

具体可以阅读下面的延伸文章。

延伸阅读 etcd:从应用场景到实现原理的全方位解读

官网:etcd.io/

再介绍一篇高质量的etcd实现原理解读的文章:高可用分布式存储 etcd 的实现原理

相比Zookeeper,etcd还具有以下优点:

  1. 简单。使用 Go 语言编写部署简单;使用 HTTP 作为接口使用简单;使用 Raft 算法保证强一致性让用户易于理解
  2. 数据持久化。etcd 默认数据一更新就进行持久化。
  3. 安全。etcd 支持 SSL 客户端安全认证。

Eureka

Eureka由Netflix公司开源,主要用于定位AWS域的中间层服务。由于Eureka被用作Spring Cloud的注册中心,因此受到了广泛的关注。Eureka由服务器和客户端这两个组件组成。Eureka服务器一般用作服务注册服务器,Eureka客户端用来简化与服务器的交互,作为轮询负载均衡器提供对服务故障切换的支持。

Eureka比ZooKeeper这类的CP系统更加适合作为服务发现体系中的注册中心。Eureka优先保证了可用性,它采用了去中心化的设计理念,整个服务集群由对等节点组成,无须像ZooKeeper那样选举主节点。集群中失效的节点不会影响正常节点对外提供服务注册和服务查询能力。 Eureka客户端有失效转移的能力,如果在向某个Eureka服务器注册服务时发现连接失败,则会自动切换至其他节点。因此,只要有一台Eureka服务器节点还能够正常工作,就无须担心注册中心的可用性。但是,保证可用性必然造成数据一致性的缺失,客户端查询到的信息不一定是最新的

undefined

Eureka 2.X 虽然已经宣布不再维护,但是其目前的功能已经非常稳定,就算不升级,服务注册/发现这些功能已经够用

Consul

Consul 来源于HashiCorp的产品,提供了一些列特性,包括服务发现、更丰富的健康检查(内存、磁盘使用情况等细粒度服务状态检测功能)、键值对存储功能以及多数据中心(官网描述的四个主要特色)。和其他方案比较起来,具有“一站式”的特点。

image.png

Consul 使用 Go 语言编写,因此具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。

和etcd一样, Consul基于 raft 协议,要求必须过半数的节点都写入成功才认为注册成功 Leader 挂掉时,重新选举期间整个 Consul 不可用。保证了强一致性但牺牲了可用性。

作者本人对Consul研究并不多,感兴趣的读者可以自行查阅相关的文档进行学习。

官网:www.consul.io/

Nacos

Nacos 是我们国内阿里巴巴的新开源项目,其核心定位是 “一个更易于帮助构建云原生应用的动态服务发现、配置和服务管理平台”。(通俗的理解就是,注册中心 + 配置中心)

image.png

服务(Service)是 Nacos 世界的一等公民。Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理:

  • Kubernetes Service

  • gRPC & Dubbo RPC Service

  • Spring Cloud RESTful Service

Nacos 的关键特性包括:

  • 服务发现和服务健康监测
  • 动态配置服务
  • 动态 DNS 服务
  • 服务及其元数据管理

更多的内容,请延伸阅读Nacos的官方文档:

延伸阅读 nacos.io/zh-cn/docs/…

小结

本章介绍了服务发现相关的一些知识,和目前市面上比较流行的服务注册中心的相关特性,希望能对你有所启发。

我们下期再会。

参考文章

  1. Service Discovery in a Microservices Architecture
  2. Microservices: Service Registration and Discovery
  3. Service Discovery
  4. nacos.io/zh-cn/
  5. etcd:从应用场景到实现原理的全方位解读
  6. 《从服务化到云原生》
  7. 《微服务设计》

如果本文有帮助到你,希望能点个赞,这是对我的最大动力。