微服务架构演进 和 Nacos高可用架构

微服务 分布式系统的架构12次演进

微服务 分布式系统的几个基础概念

1)什么是分布式?

系统中的多个模块在不同服务器上部署,即可称为分布式系统,如Tomcat和数据库分别部署在不同的服务器上,或两个相同功能的Tomcat分别部署在不同服务器上。

2)什么是高可用?

系统中部分节点失效时,其他节点能够接替它继续提供服务,则可认为系统具有高可用性。

3)什么是集群?

一个特定领域的软件部署在多台服务器上并作为一个整体提供一类服务,这个整体称为集群。如Zookeeper中的Master和Slave分别部署在多台服务器上,共同组成一个整体提供集中配置服务。

在常见的集群中,客户端往往能够连接任意一个节点获得服务,并且当集群中一个节点掉线时,其他节点往往能够自动的接替它继续提供服务,这时候说明集群具有高可用性。

4)什么是负载均衡?

请求发送到系统时,通过某些方式把请求均匀分发到多个节点上,使系统中每个节点能够均匀的处理请求负载,则可认为系统是负载均衡的。

5)什么是正向代理和反向代理?

系统内部要访问外部网络时,统一通过一个代理服务器把请求转发出去,在外部网络看来就是代理服务器发起的访问,此时代理服务器实现的是正向代理;

当外部请求进入系统时,代理服务器把该请求转发到系统中的某台服务器上,对外部请求来说,与之交互的只有代理服务器,此时代理服务器实现的是反向代理。

简单来说,正向代理是代理服务器代替系统内部来访问外部网络的过程,反向代理是外部请求访问系统时通过代理服务器转发到内部服务器的过程。

架构演进1:单机架构

在网站最初时,应用数量与用户数都较少,可以把Java应用(主要是Tomcat承载)和数据库部署在同一台服务器上。浏览器往发起请求时,首先经过DNS服务器(域名系统)把域名转换为实际IP地址10.102.4.1,浏览器转而访问该IP对应的Tomcat。

具体的架构图,如下:

图片

架构瓶颈:

随着用户数的增长,Tomcat和数据库之间竞争资源,单机性能不足以支撑业务。

架构演进2:引入缓存架构

随着 吞吐量的提升, 不得不引入引入缓存架构。通过缓存能把绝大多数请求在读写数据库前拦截掉,大大降低数据库压力。

含:  本地缓存和分布式缓存

图片

在Tomcat同服务器上或同JVM中增加本地缓存,并在外部增加分布式缓存,缓存热门商品信息或热门商品的html页面等。

涉及的技术包括:

使用caffeine 作为本地缓存,使用Redis作为分布式缓存

架构瓶颈:

(1)这里会涉及缓存穿透/击穿、缓存雪崩、热点数据集中失效等问题

(2)这里会涉及缓存一致性的问题

(3)这里会涉及 hotkey的问题

架构演进3:接入层引入反向代理实现负载均衡

接下来,缓存抗住了大部分的访问请求,服务层Tomcat上还是吞吐量低,响应逐渐变慢,需要进行架构演进。在多台服务器上分别部署Tomcat,使用反向代理软件(Nginx)把请求均匀分发到每个Tomcat中。

图片

此处假设Tomcat最多支持100个并发,Nginx最多支持50000个并发,那么理论上Nginx把请求分发到500个Tomcat上,就能抗住50000个并发。

其中涉及的技术包括:Nginx、HAProxy,两者都是工作在网络第七层的反向代理软件,主要支持http协议,还会涉及session共享、文件上传下载的问题。

架构演进4:数据库读写分离

反向代理使服务层的并发量大大增加,但并发量的增长也意味着:更多请求会穿透到数据库,数据库最终成为瓶颈。

数据库如何高并发?

简单的方案:把数据库划分为读库和写库,读库可以有多个。

读库和写库之间,如何实现数据一致性?

简单的方案:可以通过DB的同步机制,把写库的数据同步到读库,对于需要查询最新写入数据场景,可通过在缓存中多写一份,通过缓存获得最新数据。

数据库读写分离的架构如下:

图片

其中涉及的技术包括:shardingjdbc ,它是数据库中间件,可通过它来组织数据库的分离读写和分库分表,客户端通过它来访问下层数据库,还会涉及数据同步,数据一致性的问题。

架构演进5:数据库按业务分库

业务逐渐变多,不同业务之间的访问量差距较大,不同业务直接竞争数据库,相互影响性能。随着用户数的增长,单机的写库会逐渐会达到性能瓶颈。把不同业务的数据保存到不同的数据库中,使业务之间的资源竞争降低,对于访问量大的业务,可以部署更多的服务器来支撑。

图片

架构演进6:使用LVS或F5接入层负载均衡

随着吞吐量大于5W,接入层Nginx扛不住了。由于瓶颈在Nginx,因此无法LVS或F5来实现多个Nginx的负载均衡。

图片

图中的LVS和F5是工作在网络第四层的负载均衡解决方案,区别是:

(1 )  LVS是软件,运行在操作系统内核态,可对TCP请求或更高层级的网络协议进行转发,因此支持的协议更丰富,并且性能也远高于Nginx,可假设单机的LVS可支持几十万个并发的请求转发;

(2 )  F5是一种负载均衡硬件,与LVS提供的能力类似,性能比LVS更高,但价格昂贵。如果不是财大气粗的企业,推荐使用LVS。由于LVS是单机版的软件,若LVS所在服务器宕机则会导致整个后端系统都无法访问,因此需要有备用节点。

LVS 如何高可用呢?

可使用keepalived软件模拟出虚拟IP,然后把虚拟IP绑定到多台LVS服务器上,浏览器访问虚拟IP时,会被路由器重定向到真实的LVS服务器。当主LVS服务器宕机时,keepalived软件会自动更新路由器中的路由表,把虚拟IP重定向到另外一台正常的LVS服务器,从而达到LVS服务器高可用的效果。

架构演进7:通过DNS轮询实现机房间的负载均衡

由于LVS也是单机的,随着并发数增长到几十万时,LVS服务器最终会达到瓶颈,此时用户数达到千万甚至上亿级别,用户分布在不同的地区,与服务器机房距离不同,导致了访问的延迟会明显不同。此时,可以使用 DNS 进行负载均衡:在DNS服务器中可配置一个域名对应多个IP地址,每个IP地址对应到不同的机房里的虚拟IP。

图片

当用户访问taobao时,DNS服务器会使用轮询策略或其他策略,来选择某个IP供用户访问。此方式能实现机房间的负载均衡。至此,系统可做到机房级别的水平扩展,千万级到亿级的并发量都可通过增加机房来解决,系统入口处的请求并发量不再是问题。

问题是,光用DNS进行简单的 LVS负载均衡,是不够的。

所以呢?大部分的大厂应用,都是采用 智能DNS + 接入层流量二次路由的模式。

架构演进8:引入NoSQL数据库和搜索引擎等技术

随着数据的丰富程度和业务的发展,检索、分析等需求越来越丰富,单单依靠数据库无法解决如此丰富的需求。当数据库中的数据多到一定规模时,数据库就不适用于复杂的查询了,往往只能满足普通查询的场景。对于统计报表场景,在数据量大时不一定能跑出结果,而且在跑复杂查询时会导致其他查询变慢。

对于全文检索、可变数据结构等场景,数据库天生不适用,使用 elasticsearch 分布式搜索引擎解决。如对于海量文件存储,可通过分布式文件系统hbase解决

图片

对于全文检索场景,可通过搜索引擎如ElasticSearch解决,对于多维分析场景,可通过Kylin或Druid等方案解决。

当然,引入更多组件同时会提高系统的复杂度,不同的组件保存的数据需要同步,需要考虑一致性的问题,需要有更多的运维手段来管理这些组件等。

架构演进9:大应用拆分为微服务

引入更多组件解决了丰富的需求,业务维度能够极大扩充,随之而来的是一个应用中包含了太多的业务代码,业务的升级迭代、部署维护变得困难,效率低下。解决方式是,进行业务的解耦。按照业务板块来划分应用代码,使单个应用的职责更清晰,相互之间可以做到独立升级迭代。

不同的业务,可以解耦成不同的微服务。

这样的服务就是所谓的微服务,应用和服务之间通过HTTP、TCP或RPC请求等多种方式来访问公共服务,每个单独的服务都可以由单独的团队来管理。此外,可以通过Dubbo、SpringCloud等框架实现服务治理、限流、熔断、降级等功能,提高服务的稳定性和可用性。

这时候应用之间可能会涉及到一些公共配置,可以通过分布式配置中心 Nacos来解决。

图片

架构演进10:引入企业服务总线ESB对微服务进行编排

由于不同服务之间存在共用的模块,由微服务单独管理会导致相同代码存在多份,导致公共功能升级时全部应用代码都要跟着升级。不同微服务的接口访问方式不同,微服务代码需要适配多种访问方式才能使用,此外,微服务访问微服务,微服务之间也可能相互访问,调用链将会变得非常复杂,逻辑变得混乱。在微服务的基础上,以应用为单位,进行微服务的分组,并且引入企业服务总线ESB,对微服务进行编排,形成应用。

图片

通过ESB统一进行访问协议转换,应用统一通过ESB来访问后端服务,服务与服务之间也通过ESB来相互调用,以此降低系统的耦合程度。这种微服务编排为多个应用,公共服务单独抽取出来来管理,并使用企业消息总线来解除服务之间耦合问题的架构。

架构演进11:引入容器化技术实现动态扩容和缩容

业务不断发展,应用和服务都会不断变多,应用和服务的部署变得复杂,同一台服务器上部署多个服务还要解决运行环境冲突的问题。此外,对于如大促这类需要动态扩缩容的场景,需要水平扩展服务的性能,就需要在新增的服务上准备运行环境,部署服务等,运维将变得十分困难。

目前最流行的容器化技术是Docker,最流行的容器管理服务是Kubernetes(K8S),应用/服务可以打包为Docker镜像,通过K8S来动态分发和部署镜像。Docker镜像可理解为一个能运行你的应用/服务的最小的操作系统,里面放着应用/服务的运行代码,运行环境根据实际的需要设置好。

把整个“操作系统”打包为一个镜像后,就可以分发到需要部署相关服务的机器上,直接启动Docker镜像就可以把服务起起来,使服务的部署和运维变得简单。使用  Docker + Kubernetes(K8S) 后,在大促的之前,可以在现有的机器集群上划分出服务器来启动Docker镜像,增强服务的性能。

图片

大促过后就可以关闭镜像,对机器上的其他服务不造成影响。

架构演进12:以云平台承载系统

使用容器化技术后服务动态扩缩容问题得以解决,但是机器还是需要公司自身来管理,在非大促的时候,还是需要闲置着大量的机器资源来应对大促,机器自身成本和运维成本都极高,资源利用率低。

图片

系统可部署到公有云上,利用公有云的海量机器资源,解决动态硬件资源的问题。在大促的时间段里,在云平台中临时申请更多的资源,结合Docker和K8S来快速部署服务,在大促结束后释放资源,真正做到按需付费,资源利用率大大提高,同时大大降低了运维成本。

所谓的云平台,就是把海量机器资源,通过统一的资源管理,抽象为一个资源整体。在云平台上可按需动态申请硬件资源(如CPU、内存、网络等),并且之上提供通用的操作系统,提供常用的技术组件(如Hadoop技术栈,MPP数据库等)供用户使用,甚至提供开发好的应用。用户不需要关心应用内部使用了什么技术,就能够解决需求(如音视频转码服务、邮件服务、个人博客等)。

在云平台中会涉及如下几个概念:

IaaS:基础设施即服务。对应于上面所说的机器资源统一为资源整体,可动态申请硬件资源的层面;

PaaS:平台即服务。对应于上面所说的提供常用的技术组件方便系统的开发和维护;

SaaS:软件即服务。对应于上面所说的提供开发好的应用或服务,按功能或性能要求付费。

至此:以上所提到的从高并发访问问题,到服务的架构和系统实施的层面都有了各自的解决方案。

Nacos 高可用架构

当我们在聊高可用时,我们在聊什么?

  • 系统可用性达到 99.99%

  • 在分布式系统中,部分节点宕机,依旧不影响系统整体运行

  • 服务端集群化部署多个节点

Nacos 高可用,则是 Nacos 为了提升系统稳定性而采取的一系列手段。Nacos 的高可用不仅仅存在于服务端,同时也存在于客户端,以及一些与可用性相关的功能特性中,这些点组装起来,共同构成了 Nacos 的高可用。

图片

客户端高可用

先统一下语义,在微服务架构中一般会有三个角色:

  • Consumer

  • Provider

  • Registry

以上的registry 角色是 nacos-server,而 Consumer  角色和 Provider 角色都是 nacos-client。

图片

客户端高可用的方式一:配置多个nacos-server

在生产环境,我们往往需要搭建 Nacos 集群,代码中,是这样配置的:

server:
  port: 8081
spring:
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848,127.0.0.1:8848,127.0.0.1:8848

当其中一台Nacos server机器宕机时,为了不影响整体运行,客户端会存在重试机制。

package com.alibaba.nacos.client.naming.net;

/**
 * @author nkorange
 */
public class NamingProxy {

//api注册

public String reqAPI(String api, Map<String, String> params, String body, List<String> servers, String method) throws NacosException {

params.put(CommonParams.NAMESPACE_ID, getNamespaceId());

if (CollectionUtils.isEmpty(servers) && StringUtils.isEmpty(nacosDomain)) {
    throw new NacosException(NacosException.INVALID_PARAM, "no server available");
}

NacosException exception = new NacosException();

if (servers != null && !servers.isEmpty()) {

    Random random = new Random(System.currentTimeMillis());
    int index = random.nextInt(servers.size());
    
    //拿到地址列表,在请求成功之前逐个尝试,直到成功为止

    for (int i = 0; i < servers.size(); i++) {
        String server = servers.get(index);
        try {
            return callServer(api, params, body, server, method);
        } catch (NacosException e) {
            exception = e;
            if (NAMING_LOGGER.isDebugEnabled()) {
                NAMING_LOGGER.debug("request {} failed.", server, e);
            }
        }
        index = (index + 1) % servers.size();
    }
}
... 

该可用性保证存在于 nacos-client 端。

Nacos Java Client通用参数

参数名含义可选值默认值支持版本
endpoint连接Nacos Server指定的连接点,可以参考文档域名>= 0.1.0
endpointPort连接Nacos Server指定的连接点端口,可以参考文档合法端口号>= 0.1.0
namespace命名空间的ID命名空间的IDconfig模块为空,naming模块为public>= 0.8.0
serverAddrNacos Server的地址列表,这个值的优先级比endpoint高ip:port,ip:port,...>= 0.1.0
JM.LOG.PATH(-D)客户端日志的目录目录路径用户根目录>= 0.1.0
客户端高可用的方式二:本地缓存文件 Failover 机制

注册中心发生故障最坏的一个情况是整个 Server 端宕机,如果三个Server 端都宕机了,怎么办呢?

这时候 Nacos 依旧有高可用机制做兜底。

本地缓存文件 Failover 机制

当 springcloud 应用运行时,Nacos 注册中心宕机,会不会影响 RPC 调用。

Nacos 存在本地文件缓存机制,nacos-client 在接收到 nacos-server 的服务推送之后,会在内存中保存一份,随后会落盘存储一份快照snapshot 。有了这份快照,本地的RPC调用,还是能正常的进行。

关键是,这个本地文件缓存机制,默认是关闭的。

Nacos 注册中心宕机,Dubbo /springcloud 应用发生重启,会不会影响 RPC 调用。如果了解了 Nacos 的 Failover 机制,应当得到和上一题同样的回答:不会。

客户端Naming通用参数

参数名含义可选值默认值支持版本
namingLoadCacheAtStart启动时是否优先读取本地缓存true/falsefalse>= 1.0.0
namingClientBeatThreadCount客户端心跳的线程池大小正整数机器的CPU数的一半>= 1.0.0
namingPollingThreadCount客户端定时轮询数据更新的线程池大小正整数机器的CPU数的一半>= 1.0.0
com.alibaba.nacos.naming.cache.dir(-D)客户端缓存目录目录路径{user.home}/nacos/naming>= 1.0.0
com.alibaba.nacos.naming.log.level(-D)Naming客户端的日志级别info,error,warn等info>= 1.0.0
com.alibaba.nacos.client.naming.tls.enable(-D)是否打开HTTPStrue/falsefalse

snapshot 默认的存储路径为:{USER_HOME}/nacos/naming/ 中:

这份文件有两种价值,一是用来排查服务端是否正常推送了服务;二是当客户端加载服务时,如果无法从服务端拉取到数据,会默认从本地文件中加载。

在生产环境,推荐开启该参数,以避免注册中心宕机后,导致服务不可用,在服务注册发现场景,可用性和一致性 trade off 时,我们大多数时候会优先考虑可用性。

另外:{USER_HOME}/nacos/naming/{namespace} 下除了缓存文件之外还有一个 failover 文件夹,里面存放着和 snapshot 一致的文件夹。这是 Nacos 的另一个 failover 机制,snapshot 是按照某个历史时刻的服务快照恢复恢复,而 failover 中的服务可以人为修改,以应对一些极端场景。该可用性保证存在于 nacos-client 端。

Nacos两种健康检查模式

agent上报模式

客户端(注册在nacos上的其它微服务实例)健康检查。

客户端通过心跳上报方式告知服务端(nacos注册中心)健康状态;默认心跳间隔5秒;nacos会在超过15秒未收到心跳后将实例设置为不健康状态;超过30秒将实例删除;

服务端主动检测

服务端健康检查。

nacos主动探知客户端健康状态,默认间隔为20秒;健康检查失败后实例会被标记为不健康,不会被立即删除。

临时实例

临时实例通过agent上报模式实现健康检查。

Nacos 在 1.0.0版本 instance级别增加了一个ephemeral字段,该字段表示注册的实例是否是临时实例还是持久化实例。

微服务注册为临时实例:

# 默认true
spring:
 cloud:
  nacos:
   discovery:
    ephemeral: true

注意:默认为临时实例,表示为临时实例。

图片

注册实例支持ephemeral字段

如果是临时实例,则instance不会在 Nacos 服务端持久化存储,需要通过上报心跳的方式进行包活,如果instance一段时间内没有上报心跳,则会被 Nacos 服务端摘除。在被摘除后如果又开始上报心跳,则会重新将这个实例注册。

持久化实例则会被 Nacos 服务端持久化,此时即使注册实例的客户端进程不在,这个实例也不会从服务端删除,只会将健康状态设为不健康。

同一个服务下可以同时有临时实例和持久化实例,这意味着当这服务的所有实例进程不在时,会有部分实例从服务上摘除,剩下的实例则会保留在服务下。

使用实例的ephemeral来判断,ephemeraltrue对应的是服务健康检查模式中的 client 模式,为false对应的是 server 模式。

Nacos 1.0.0 之前服务的健康检查模式有三种:client、server 和none, 分别代表客户端上报、服务端探测和取消健康检查。在控制台操作的位置如下所示:

图片

在 Nacos 1.0.0 中将把这个配置去掉,改为使用实例的ephemeral来判断,ephemeraltrue对应的是服务健康检查模式中的 client 模式,为false对应的是 server 模式。

临时实例和持久化实例区别

临时和持久化的区别主要在健康检查失败后的表现,持久化实例健康检查失败后会被标记成不健康,而临时实例会直接从列表中被删除。

这个特性比较适合那些需要应对流量突增,而弹性扩容的服务,当流量降下来后这些实例自己销毁自己就可以了,不用再去nacos里手动调用注销实例。持久化以后,可以实时看到健康状态,便于做后续的告警、扩容等一系列处理。

图片

Nacos Server运行模式

Server的运行模式,是指 Nacos Server 可以运行在多种模式下,当前支持三种模式:

  • AP

  • CP

  • MIXED

这里的运行模式,使用的是CAP理论里的C、A和P概念。CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)。

可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)。

分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。如果在某个分布式系统中数据无副本, 那么系统必然满足强一致性条件,  因为只有独一数据,不会出现数据不一致的情况,此时C和P两要素具备,但是如果系统发生了网络分区状况或者宕机,必然导致某些数据不可以访问,此时可用性条件就不能被满足,即在此情况下获得了CP系统,但是CAP不可同时满足  。

基于CAP理论,在分布式系统中,数据的一致性、服务的可用性和网络分区容忍性只能三者选二。一般来说分布式系统需要支持网络分区容忍性,那么就只能在C和A里选择一个作为系统支持的属性。C 的准确定义应该是所有节点在同一时间看到的数据是一致的,而A的定义是所有的请求都会收到响应。

Nacos 支持 AP 和 CP 模式的切换,这意味着 Nacos 同时支持两者一致性协议。这样,Nacos能够以一个注册中心管理这些生态的服务。不过在Nacos中,AP模式和CP模式的具体含义,还需要再说明下。

AP模式为了服务的可能性而减弱了一致性,因此AP模式下只支持注册临时实例。AP 模式是在网络分区下也能够注册实例。在AP模式下也不能编辑服务的元数据等非实例级别的数据,但是允许创建一个默认配置的服务。同时注册实例前不需要进行创建服务的操作,因为这种模式下,服务其实降级成一个简单的字符创标识,不在存储任何属性,会在注册实例的时候自动创建。

CP模式下则支持注册持久化实例,此时则是以 Raft 协议为集群运行模式,因此网络分区下不能够注册实例,在网络正常情况下,可以编辑服务器别的配置。改模式下注册实例之前必须先注册服务,如果服务不存在,则会返回错误。

MIXED 模式可能是一种比较让人迷惑的模式,这种模式的设立主要是为了能够同时支持临时实例和持久化实例的注册。这种模式下,注册实例之前必须创建服务,在服务已经存在的前提下,临时实例可以在网络分区的情况下进行注册。

Nacos CP/AP模式设定

使用如下请求进行Server运行模式的设定:

curl -X PUT
'$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'
Nacos CP/AP模式切换

Nacos 集群默认支持的是CAP原则中的AP原则。但是Nacos 集群可切换为CP原则,切换命令如下:

curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'

同时微服务的bootstrap.properties 需配置如下选项指明注册为临时/永久实例 AP模式不支持数据一致性,所以只支持服务注册的临时实例,CP模式支持服务注册的永久实例,满足配置文件的一致性

#false为永久实例,true表示临时实例开启,注册为临时实例
spring.cloud.nacos.discovery.ephemeral=true

AP/CP的配套一致性协议

介绍一致性模型之前,需要回顾 Nacos 中的两个概念:临时服务和持久化服务。

  • 临时服务(Ephemeral):临时服务健康检查失败后会从列表中删除,常用于服务注册发现场景。

  • 持久化服务(Persistent):持久化服务健康检查失败后会被标记成不健康,常用于 DNS 场景。

两种模式使用的是不同的一致性协议:

  • 临时服务使用的是 Nacos 为服务注册发现场景定制化的私有协议 distro,其一致性模型是 AP;

  • 而持久化服务使用的是 raft 协议,其一致性模型是 CP。

AP模式下的distro 协议

distro 协议的工作流程如下:

  • Nacos 启动时首先从其他远程节点同步全部数据。

  • Nacos 每个节点是平等的都可以处理写入请求,同时把新数据同步到其他节点。

  • 每个节点只负责部分数据,定时发送自己负责数据的校验值到其他节点来保持数据一致性。

如图所示,每个节点负责一部分服务的写入。

图片

但每个节点都可以接收到写入请求,这时就存在两种情况:

  • 当该节点接收到属于该节点负责的服务时,直接写入。

  • 当该节点接收到不属于该节点负责的服务时,将在集群内部路由,转发给对应的节点,从而完成写入。

图片

读取操作则不需要路由,因为集群中的各个节点会同步服务状态,每个节点都会有一份最新的服务数据。而当节点发生宕机后,原本该节点负责的一部分服务的写入任务会转移到其他节点,从而保证 Nacos 集群整体的可用性。

图片

一个比较复杂的情况是,节点没有宕机,但是出现了网络分区,即下图所示:

图片

这个情况会损害可用性,客户端会表现为有时候服务存在有时候服务不存在。

综上,Nacos 的 distro 一致性协议可以保证在大多数情况下,集群中的机器宕机后依旧不损害整体的可用性。

Nacos 有两个一致性协议:distro 和 raft,distro 协议不会有脑裂问题。

CP模式下的raft协议

集群内部的特殊的心跳同步服务

心跳机制一般广泛存在于分布式通信领域,用于确认存活状态。一般心跳请求和普通请求的设计是有差异的,心跳请求一般被设计的足够精简,这样在定时探测时可以尽可能避免性能下降。

而在 Nacos 中,出于可用性的考虑,一个心跳报文包含了全部的服务信息,这样相比仅仅发送探测信息降低了吞吐量,而提升了可用性,怎么理解呢?

考虑以下的两种场景:

  • nacos-server 节点全部宕机,服务数据全部丢失。nacos-server 即使恢复运作,也无法恢复出服务,而心跳包含全部内容可以在心跳期间就恢复出服务,保证可用性。

  • nacos-server 出现网络分区。由于心跳可以创建服务,从而在极端网络故障下,依旧保证基础的可用性。

调用 OpenApi 依次删除各个服务:

curl -X "DELETE mse-xxx-p.nacos-ans.mse.aliyuncs.com:8848/nacos/v1/ns/service?serviceName=providers:com.alibaba.edas.boot.EchoService:1.0.0:DUBBO&groupName=DEFAULT_GROUP"

过 5s 后刷新,服务又再次被注册了上来,符合我们对心跳注册服务的预期。

集群部署模式高可用

最后给大家分享的 Nacos 高可用特性来自于其部署架构。

节点数量

我们知道在生产集群中肯定不能以单机模式运行 Nacos。

那么第一个问题便是:我应该部署几台机器?

Nacos 有两个一致性协议:distro 和 raft,distro 协议不会有脑裂问题,所以理论来说,节点数大于等于 2 即可;raft 协议的投票选举机制则建议是 2n+1 个节点。

综合来看,选择 3 个节点是起码的,其次处于吞吐量和更吞吐量的考量,可以选择 5 个,7 个,甚至 9 个节点的集群。

多可用区部署

组成集群的 Nacos 节点,应该尽可能考虑两个因素:

  • 各个节点之间的网络时延不能很高,否则会影响数据同步。

  • 各个节点所处机房、可用区应当尽可能分散,以避免单点故障。

以阿里云的 ECS 为例,选择同一个 Region 的不同可用区就是一个很好的实践。

部署模式

生产环境,建议使用k8s部署或者阿里云的 ECS 部署。

考虑的中等公司,都会有运维团队,开发人员不需要参与。

所以,这里介绍的开发人员必须掌握的,docker模式的部署。

高可用nacos的部署架构

图片

总结

高可用特性绝不是靠服务端多部署几个节点就可以获得的,而是要结合客户端使用方式、服务端部署模式、使用场景综合来考虑的一件事。

特别是在服务注册发现场景,Nacos 为可用性做了非常多的努力,而这些保障,ZooKeeper 是不一定有的。在做注册中心选型时,可用性保障上,Nacos 绝对是优秀的。

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值