文章目录
- 1 微服务注册中心
- 1.1 注册中心概念
- 1.1.1 为什么需要注册中心
- 1.1.2 如何实现一个注册中心
- 1.1.3 如何解决负载均衡的问题
- 1.2 注册中心如何选型
- 1.2.1 Zookeeper
- 1.2.2 Eureka
- 1.2.3 Nacos
- 1.2.4 Consul
- 1.2.5 Kubernetes
1 微服务注册中心
微服务的注册中心目前主流的有以下五种:Zookeeper
,Eureka
,Consul
,Nacos
,Kubernetes
1.1 注册中心概念
1.1.1 为什么需要注册中心
随着单体应用拆分,首当面临的第一份挑战就是服务实例的数量较多,并且服务自身对外暴露的访问地址也具有动态性。可能因为服务扩容、服务的失败和更新等因素,导致服务实例的运行时状态经常变化,如下图:
商品详情需要调用营销、订单、库存三个服务,存在问题有:
- 营销、订单、库存这三个服务的地址都可能动态的发生改变,单存只使用配置的形式需要频繁的变更,如果是写到配置文件里面还需要重启系统,这对生产来说太不友好了;
- 服务是集群部署的形式调用方负载均衡如何去实现;
解决第一个问题办法就是加一个中间,这个中间层就是我们的注册中心。
解决第二问题就是关于负载均衡的实现,这个需要结合中间层来实现。
1.1.2 如何实现一个注册中心
对于如何实现注册中心这个问题,首先将服务之间是如何交互的模型抽象出来,我们结合实际的案例来说明这个问题,以商品服务为例:
- 当我们搜索商品的时候商品服务就是提供者;
- 当我们查询商品详情的时候即服务的提供者又是服务的消费者,消费是订单、库存等服务;
由此我们需要引入的三个角色就是:中间层(注册中心)、生产者、消费者,如下图:
整体的执行流程如下:
- 在服务启动时,服务提供者通过内部的注册中心客户端应用自动将自身服务注册到注册中心,包含主机地址、服务名称等等信息;
- 在服务启动或者发生变更的时候,服务消费者的注册中心客户端程序则可以从注册中心中获取那些已经注册的服务实例信息或者移除已下线的服务;
上图还多一个设计缓存本地路由,缓存本地路由是为了提高服务路由的效率和容错性,服务消费者可以配备缓存机制以加速服务路由。更重要的是,当服务注册中心不可用时,服务消费者可以利用本地缓存路由实现对现有服务的可靠调用。
在整个执行的过程中,其中有点有一点是比较难的,就是服务消费者如何及时知道服务的生产者如何及时变更的,这个问题也是经典的生产者消费者的问题,解决的方式有两种:
发布-订阅模式
:服务消费者能够实时监控服务更新状态,通常采用监听器以及回调机制,经典的案例就是Zookeeper
;
主动拉取策略
:服务的消费者定期调用注册中心提供的服务获取接口获取最新的服务列表并更新本地缓存,经典案例就是Eureka
;
对于如何选择这两种方式,其实还有一个数据一致性问题可以聊聊,比如选择定时器肯定就抛弃了强一致性,最后要求的是最终一致,这里就不深入展开了,另外你可能还会说服务的移除等等这些功能都没介绍,在我看来那只是一个附加功能,注册中心重点还是在于服务注册和发现,其他都是锦上添花罢了。
1.1.3 如何解决负载均衡的问题
负载均衡的实现有两种方式:
- 服务端的负载均衡;
- 客户端的负载均衡;
对于实现的方案来说本质上是差不多的,只是说承接的载体不一样,一个是服务端,一个客户端,如下图:
服务端的负载均衡,给服务提供者更强的流量控制权,但是无法满足不同的消费者希望使用不同负载均衡策略的需求。
客户端的负载均衡则提供了这种灵活性,并对用户扩展提供更加友好的支持。但是客户端负载均衡策略如果配置不当,可能会导致服务提供者出现热点,或者压根就拿不到任何服务提供者。
服务端负载均衡典型的代表就是 Nginx
,客户端负载均衡典型代表是Ribbon
,每种方式都有经典的代表,我们都是可以深入学习的。
常见的负载均衡器的算法的实现,常见的算法有以下六种:
轮询法
将请求按顺序轮流地分配到后端服务器上,它均衡地对待后端的每一台服务器,而不关心服务器实际的连接数和当前的系统负载。随机法
通过系统的随机算法,根据后端服务器的列表大小值来随机选取其中的一台服务器进行访问。由概率统计理论可以得知,随着客户端调用服务端的次数增多;其实际效果越来越接近于平均分配调用量到后端的每一台服务器,也就是轮询的结果。哈希算法
哈希的思想是根据获取客户端的IP地址
,通过哈希函数计算得到的一个数值,用该数值对服务器列表的大小进行取模运算
,得到的结果便是客服端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。加权轮询法
不同的后端服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。给配置高、负载低的机器配置更高的权重,让其处理更多的请求,而配置低、负载高的机器,给其分配较低的权重,降低其系统负载,加权轮询能很好地处理这一问题,并将请求顺序且按照权重分配到后端。加权随机法
与加权轮询法一样,加权随机法也根据后端机器的配置,系统的负载分配不同的权重。不同的是,它是按照权重随机请求后端服务器,而非顺序。- 最小连接数法
最小连接数算法比较灵活和智能,由于后端服务器的配置不尽相同,对于请求的处理有快有慢,它是根据后端服务器当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前的请求,尽可能地提高后端服务的利用效率,将负责合理地分流到每一台服务器。
1.2 注册中心如何选型
现在注册中心的选择也是五花八门,现阶段比较流行有以下几种:
在介绍这个之前大家有些需要了解的知识有CAP
、Paxos
、Raft
算法这里我就不进行过多介绍了。开始介绍以上5种实现注册中心的方式。
1.2.1 Zookeeper
这个说起来有点意思的是官方并没有说他是一个注册中心,但是国内 Dubbo
场景下很多都是使用Zookeeper
来完成了注册中心的功能。
点击了解zookeeper深入理解其原理
1.2.2 Eureka
点击了解SpringCloud之Eureka原理
1.2.3 Nacos
点击了解Nacos原理
1.2.4 Consul
Consul
是 HashiCorp
公司推出的开源工具,Consul
由 Go
语言开发,部署起来非常容易,只需要极少的可执行程序和配置文件,具有绿色、轻量级的特点。Consul
是分布式的、高可用的、 可横向扩展的用于实现分布式系统的服务发现与配置。
Consul
的特点:
- 服务发现(
Service Discovery
)
Consul
提供了通过DNS
或者HTTP
接口的方式来注册服务和发现服务。一些外部的服务通过Consul
很容易的找到它所依赖的服务。 - 健康检查(
Health Checking
)
Consul
的Client
可以提供任意数量的健康检查,既可以与给定的服务相关联(webserver是否返回200 OK
),也可以与本地节点相关联(内存利用率是否低于90%
)。操作员可以使用这些信息来监视集群的健康状况,服务发现组件可以使用这些信息将流量从不健康的主机路由出去。 Key/Value
存储
应用程序可以根据自己的需要使用Consul
提供的Key/Value
存储。Consul
提供了简单易用的HTTP
接口,结合其他工具可以实现动态配置、功能标记、领袖选举等等功能。- 安全服务通信
Consul
可以为服务生成和分发TLS
证书,以建立相互的TLS
连接。意图可用于定义允许哪些服务通信。服务分割可以很容易地进行管理,其目的是可以实时更改的,而不是使用复杂的网络拓扑和静态防火墙规则。 - 多数据中心
Consul
支持开箱即用的多数据中心,这意味着用户不需要担心需要建立额外的抽象层让业务扩展到多个区域
Consul
支持多数据中心,在上图中有两个DataCenter
,他们通过Internet
互联,同时请注意为了提高通信效率,只有Server
节点才加入跨数据中心的通信。
在单个数据中心中,Consul
分为Client
和Server
两种节点(所有的节点也被称为Agent
),Server
节点保存数据,Client
负责健康检查及转发数据请求到Server
;Server
节点有一个Leader
和多个Follower
,Leader
节点会将数据同步到 Follower
,Server
的数量推荐是3个或者5个,在Leader
挂掉的时候会启动选举机制产生一个新的Leader
。
集群内的Consul
节点通过gossip
协议(流言协议)维护成员关系,也就是说某个节点了解集群内现在还有哪些节点,这些节点是Client
还是Server
。单个数据中心的流言协议同时使用TCP
和UDP
通信,并且都使用8301
端口。跨数据中心的流言协议也同时使用TCP
和UDP
通信,端口使用8302。
集群内数据的读写请求既可以直接发到Server
,也可以通过Client
使用RPC
转发到Server
,请求最终会到达Leader
节点,在允许数据延时的情况下,读请求也可以在普通的Server
节点完成,集群内数据的读写和复制都是通过TCP的8300端口完成。
Consul
其实也可以在应用内进行注册,后续采用Spring Cloud
全家桶这套做负载
我们这里聊聊关于Consul的应用外的注册:
上图主要多出来两个组件,分别是Registrator
和Consul Template
,接下来我们介绍下这两个组件如何结合可以实现在应用发进行服务发现和注册。
Registrator
:一个开源的第三方服务管理器项目,它通过监听服务部署的Docker
实例是否存活,来负责服务提供者的注册和销毁。Consul Template
:定时从注册中心服务端获取最新的服务提供者节点列表并刷新 LB 配置(比如Nginx
的upstream
),这样服务消费者就通过访问Nginx
就可以获取最新的服务提供者信息,达到动态调节负载均衡的目的。
整体架构图可能是这样
我们用 Registrator
来监控每个Server
的状态。当有新的Server
启动的时候,Registrator
会把它注册到Consul
这个注册中心上。
由于Consul Template
已经订阅了该注册中心上的服务消息,此时Consul
注册中心会将新的Server
信息推送给Consul Template
,Consul Template
则会去修改nginx.conf
的配置文件,然后让Nginx
重新载入配置以达到自动修改负载均衡的目的。
1.2.5 Kubernetes
Kubernetes
是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务。通过Kubernetes
能够进行应用的自动化部署和扩缩容。
在Kubernetes
中,会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes
积累了作为Google
生产环境运行工作负载15年的经验,并吸收了来自于社区的最佳想法和实践。
Kubernetes
经过这几年的快速发展,形成了一个大的生态环境,Google在2014年将Kubernetes
作为开源项目。
Kubernetes
的关键特性包括:
自动化装箱
:在不牺牲可用性的条件下,基于容器对资源的要求和约束自动部署容器。同时,为了提高利用率和节省更多资源,将关键和最佳工作量结合在一起。自愈能力
:当容器失败时,会对容器进行重启;当所部署的Node
节点有问题时,会对容器进行重新部署和重新调度;当容器未通过监控检查时,会关闭此容器;直到容器正常运行时,才会对外提供服务。水平扩容
:通过简单的命令、用户界面或基于CPU
的使用情况,能够对应用进行扩容和缩容。服务发现和负载均衡
:开发者不需要使用额外的服务发现机制,就能够基于Kubernetes
进行服务发现和负载均衡。自动发布和回滚
:Kubernetes
能够程序化的发布应用和相关的配置。如果发布有问题,Kubernetes
将能够回归发生的变更。保密和配置管理
:在不需要重新构建镜像的情况下,可以部署和更新保密和应用配置。存储编排
:自动挂接存储系统,这些存储系统可以来自于本地、公共云提供商(例如:GCP和AWS)、网络存储(例如:NFS、iSCSI、Gluster、Ceph、Cinder和Floker等)。
图片
Kubernetes
属于主从分布式架构,主要由Master Node
和Worker Node
组成,以及包括客户端命令行工具Kubectl
和其它附加项。
Master Node
:作为控制节点,对集群进行调度管理,Master
主要由三部分构成:
Api Server
相当于K8S
的网关,所有的指令请求都必须经过Api Server
;Kubernetes 调度器
,使用调度算法,把请求资源调度到某个Node
节点;Controller 控制器
,维护 K8S 资源对象(CRUD:添加、删除、更新、修改);ETCD 存储资源对象
(可以服务注册、发现等等);
Worker Node
:作为真正的工作节点,运行业务应用的容器;Worker Node
主要包含五部分:
Docker
是运行容器的基础环境,容器引擎;Kuberlet
执行在Node
节点上的资源操作,Scheduler
把请求交给Api
,然后Api Sever
再把信息指令数据存储在ETCD
里,于是Kuberlet
会扫描 ETCD 并获取指令请求,然后去执行;Kube-proxy是
代理服务,起到负载均衡作用;Fluentd
采集日志;Pod
:Kubernetes
管理的基本单元(最小单元),Pod
内部是容器。Kubernetes
不直接管理容器,而是管理Pod