微服务的注册中心目前主流的有以下五种:Zookeeper
,Eureka
,Consul
,Nacos
,Kubernetes
随着单体应用拆分,首当面临的第一份挑战就是服务实例的数量较多,并且服务自身对外暴露的访问地址也具有动态性。可能因为服务扩容、服务的失败和更新等因素,导致服务实例的运行时状态经常变化,如下图:
商品详情需要调用营销、订单、库存三个服务,存在问题有:
解决第一个问题办法就是加一个中间,这个中间层就是我们的注册中心。
解决第二问题就是关于负载均衡的实现,这个需要结合中间层来实现。
对于如何实现注册中心这个问题,首先将服务之间是如何交互的模型抽象出来,我们结合实际的案例来说明这个问题,以商品服务为例:
由此我们需要引入的三个角色就是:中间层(注册中心)、生产者、消费者,如下图:
整体的执行流程如下:
上图还多一个设计缓存本地路由,缓存本地路由是为了提高服务路由的效率和容错性,服务消费者可以配备缓存机制以加速服务路由。更重要的是,当服务注册中心不可用时,服务消费者可以利用本地缓存路由实现对现有服务的可靠调用。
在整个执行的过程中,其中有点有一点是比较难的,就是服务消费者如何及时知道服务的生产者如何及时变更的,这个问题也是经典的生产者消费者的问题,解决的方式有两种:
发布-订阅模式
:服务消费者能够实时监控服务更新状态,通常采用监听器以及回调机制,经典的案例就是Zookeeper
;主动拉取策略
:服务的消费者定期调用注册中心提供的服务获取接口获取最新的服务列表并更新本地缓存,经典案例就是 Eureka
;对于如何选择这两种方式,其实还有一个数据一致性问题可以聊聊,比如选择定时器肯定就抛弃了强一致性,最后要求的是最终一致,这里就不深入展开了,另外你可能还会说服务的移除等等这些功能都没介绍,在我看来那只是一个附加功能,注册中心重点还是在于服务注册和发现,其他都是锦上添花罢了。
负载均衡的实现有两种方式:
对于实现的方案来说本质上是差不多的,只是说承接的载体不一样,一个是服务端,一个客户端,如下图:
服务端的负载均衡,给服务提供者更强的流量控制权,但是无法满足不同的消费者希望使用不同负载均衡策略的需求。
客户端的负载均衡则提供了这种灵活性,并对用户扩展提供更加友好的支持。但是客户端负载均衡策略如果配置不当,可能会导致服务提供者出现热点,或者压根就拿不到任何服务提供者。
服务端负载均衡典型的代表就是 Nginx
,客户端负载均衡典型代表是Ribbon
,每种方式都有经典的代表,我们都是可以深入学习的。
常见的负载均衡器的算法的实现,常见的算法有以下六种:
轮询法
随机法
哈希算法
IP地址
,通过哈希函数计算得到的一个数值,用该数值对服务器列表的大小进行取模运算
,得到的结果便是客服端要访问服务器的序号。采用源地址哈希法进行负载均衡,同一IP地址的客户端,当后端服务器列表不变时,它每次都会映射到同一台后端服务器进行访问。加权轮询法
加权随机法
在介绍这个之前大家有些需要了解的知识有CAP
、Paxos
、Raft
算法这里我就不进行过多介绍了。开始介绍以上5种实现注册中心的方式。
这个说起来有点意思的是官方并没有说他是一个注册中心,但是国内 Dubbo
场景下很多都是使用Zookeeper
来完成了注册中心的功能。
点击了解zookeeper深入理解其原理
点击了解SpringCloud之Eureka原理
点击了解Nacos原理
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
全家桶这套做负载
上图主要多出来两个组件,分别是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
重新载入配置以达到自动修改负载均衡的目的。
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