nacos 本地测试_Nacos注册中心落地实践

前言

公司在19年开始推进同城双活架构,未来规划是在南汇机房出现故障时能把所有读流量切到宝山机房,这样至少保证读请求是没问题的;我们的微服务使用的zookeeper来做服务发现, zk由于它的强一致性模型不适合多机房部署, 由于zk的服务发现模型是基于会话机制创建的临时节点, 就算两个机房各部署一套zk, 再部署一个sync服务两边同步,也会因为跨机房网络不稳定导致连接断开, zk会因此一开始就没有考虑继续用zk作为下一代服务发现的注册中心.

zk基于ZAB协议实现了强一致性,在出现网络分区时有可能因集群无法选出Leader导致服务不可用, 这时候不可以新部署,重新启动,扩容或者缩容,这对于服务发现场景来讲是不能接受的, 在实践中,注册中心不能因为自身的任何原因破坏服务之间本身的可连通性, 数据的短期不一致对客户端来说就是多一个或者少一个节点,对于业务层面完全是可以接受的, 因此注册中心在设计时应偏向AP架构.

背景故事

我刚入职的时候便接手了一个任务:把zk注册中心替换成consul,因为网上的介绍都说consul是AP架构, 而且consul在生产环境已经完全落地, 运维已经用了consul来做物理机的发现和监控, 因此当时的做法就是研究consul的接入文档和API, 完成了基于consul的开发和验证,上线了一个注册中心同步的服务,用于把zk注册中心和consul双向同步, 上线后很多服务开始报no active server的错误,最后排查下来发现我们线上的consul版本并不支持tag过滤的功能, 导致consul返回了在测试环境不会返回的服务实例信息, 最后导致反复触发服务上线下线事件, 进而引起了故障,最后把sync服务强制下线才解决; 这次事故还发现个问题是线上的prometheus会给所有thrift端口发送/metric http请求, 导致m2服务解析时直接内存溢出了, 需要重启服务才能解决.

这次事故我们吸取了深刻的教训, 由于没有深入了解Consul的原理, 导致解决问题花了较长时间,后面我们便把进度放慢, 先去熟悉Consul的技术架构, 深入Consul的源码才发现,Consul并不是AP架构, Consul的服务注册模型和KV模型都是基于Raft实现的强一致性,因此对于服务发现它是一个CP的架构, 而Consul内部Agent的发现和事件机制是基于Gossip流言协议实现的, 这个协议是最终一致性的,所以网上很多文章把Consul归类为AP架构, 这个是有问题的.

还有一个暴露出来的问题是运维用Consul来管理物理机,他们对可用性,一致性,性能这些指标并没有太多的要求, 因此业务和运维共用一套服务发现系统是有很大的风险的, 运维测试环境和生产环境安装的consul版本不一致就是如此, 因此基于一致性模型和数据共享的风险我们最终弃用了Consul.

注册中心选型

Eureka调研

基于我们在服务发现领域的积累, 最终一致性的架构比较适合注册中心的场景,因此我们调研了业界使用比较广泛的2款开源框架Eureka和Nacos.


Eureka是Netflix开源的一款提供服务注册和发现的产品,基于Java语言开发,在它的实现中,节点之间相互平等,部分注册中心的节点挂掉也不会对集群造成影响,即使集群只剩一个节点存活,也可以正常提供发现服务。哪怕是所有的服务注册节点都挂了,Eureka Clients上也会缓存服务调用的信息。这就保证了我们微服务之间的互相调用足够健壮.

看完前面的介绍可能会觉得Eureka的实现非常适合服务发现的场景,在SpringCloud体系下Eureka在很多公司都有成功的落地经验, 但深入Eureka源码层面进行分析时,我们发现了Eureka的一个巨大隐患, Eureka每个服务节点会保存所有的服务实例数据, 同时每个Eureka
会作为其他节点的Client, Eureka-Client也会保存一份全量的数据, 这就导致每个Eureka Server保存了2份全量的数据,因此当集群规模比较大时Eureka Server的压力会非常大,而且无法通过水平扩展来分担压力.

贴一张Eureka的官方架构图:f58c7f05b592f3c8e81310907b38ec44.png

总结了一下Eureka存在的问题

  • 订阅端拿到的是所有服务的全量地址,这个对于客户端的内存是一个比较大的消耗(不使用官方客户端可以解决),每个server节点会在内存里保存2份全量的注册信息

  • pull模式:客户端采用周期性pull方式存在实时性不足以及拉取性能消耗的问题(开发长轮询功能)

  • 一致性协议:Eureka集群的多副本的一致性协议采用类似“异步多写”的AP协议,每一个 server都会把本地接收到的写请求(register/heartbeat/unregister/update)发送给组成集群的其他所有的机器,特别是hearbeat报文是周期性持续不断的在client->server->all other server之间传送

  • 当读请求增多的时候集群需要扩容,但扩容又会导致每台server承担更多的写请求,扩容效果并不明显,而且每个server内存中保存2份全量的数据,内存会成为瓶颈

  • 1.x版本更新频率很低,2.x版本闭源, 问题修复频率低

Nacos调研

除了Eureka之外,我们还调研了另一款采用AP架构的Nacos注册中心,Nacos由阿里开源,在国内很多公司有成功落地经验,由于Nacos包含注册中心和配置中心两部分功能,以下内容只涉及注册中心.

nacos总体思路和eureka差不多,但是解决了eureka存在的一些问题:

  • pull时效性问题:采用udpPush+ack的方式, 并且支持定时pull

  • 心跳请求在server间来回转发的问题:采用分片方式每个server负责一部分service的状态检查,并定时向其他server同步

  • 扩容效果不明显问题:采用hash分片机制,每个server处理一部分service, 虽然每个server存储的数据量是一样的,但扩容可以解决写入的瓶颈

除此之外Nacos的其他几个关键特性:

  • 支持多个namespace,实现租户隔离

  • 支持CP和AP两种一致性模式, CP模式也是采用的Raft协议

  • 支持主动和被动的心跳检测方式, 主动检测支持TCP,HTTP和MySQL协议, 由Nacos Server主动向服务实例发送探测请求来更新节点的健康状态,主要用来监控那些持久的节点,比如数据库,Redis实例等, 被动检测是由节点主动通过HTTP接口向Nacos Server发送心跳请求

下面这个是Nacos Server的请求处理流转图

2105eff2714248d9786c0edb22019d2d.png

综合对比后,我们决定用Nacos来作为我们微服务的下一代注册中心.

Nacos开发篇

官方的Nacos还无法直接在我们的生产环境上使用, 因为Nacos采用的Udp Push的方式来更新服务实例, 而Udp Push需要每个服务实例多监听一个端口,我们线上基本都是一个物理机部署好几个服务, 采用监听端口的方式很容易就端口冲突了, 因此我们需要将Udp Push改造成HTTP 长轮询的方式;

Nacos Server验证和改造

  • HTTP长轮询改造

Http长轮询功能是基于Servlet 3.0 提供的AsyncContext的能力, nacos-client收到订阅请求后会和nacos-server建立HTTP长连接, nacos只有在服务实例有变更时才向客户端返回最新的数据, 延迟基本在ms级别.

  • MetaServer改造

Nacos Server之间互相发现是通过配置文件里配置服务列表实现的,如果要新增一个节点, 需要修改配置文件并重启所有节点; 因此为了后面方便快速扩容, 我们把Server列表接入了配置中心,可以动态更新server集群的地址;

Nacos-Client默认也是通过配置的方式获取获取server集群地址, 同时也支持通过vipServer的方式来动态刷新服务列表, 需要客户端配置一个http url, 由于我们线上物理机都安装了Consul Agent, 因此我们直接把Consul当做MetaServer, 当health server列表有变更时把变更后的地址写到Consul的KV里, Nacos-Client动态的从Consul KV获取healthy集群的地址.

  • 压测和断网测试

Nacos官网给出的压测结果是非常优秀的, 我们压测下来也发现线上只需要部署三个节点就能满足要求,Nacos的代码质量也比较高, 服务GC一直都比较稳定, 最后我们线上是部署了5个节点.

由于Nacos采用的是AP架构, 我们需要重点关注出现网络分区或机器故障的场景下Nacos的实际表现, 因此针对各种可能出现的场景都做了验证,下面列出来的是发现问题的几个场景:

  • 测试场景1:网络分区5分钟,网络恢复后2个server数据一直会不一致

最后发现是Nacos的同步任务有Bug,该Bug已提交PR并采纳,参考issue1665

  • 测试场景2: 两个实例网络分区后服务实例的变化过程

由于采用的分片处理的模型, 当某一个节点和其他节点网络分区了并且15s内没有恢复, 这个节点上的实例会集体下线几秒钟,客户端会出现大量的no active server, 这个问题我在Github与Nacos团队有讨论过, 参考issue1873,他们给出的解决方案是Nacos Server之间剔除过期节点的时间间隔要小于 (服务实例超时时间-服务实例心跳间隔)

后面我们修改了Nacos Server之间的心跳配置,改为每秒发送一次心跳, 超过10s没有收到心跳就摘除该Server.

  • 测试场景3: Nacos Server重启后服务实例的变化

Nacos Server启动后会从其他Server同步全量的数据, 但如果同步过来的部分服务原先是由自己负责处理心跳的, 而这些实例的心跳时间戳是比较早的(Nacos-Server之间并不会同步服务实例最新的heartbeat时间戳), 这些服务会被每5s执行的ClientBeatCheckTask删除掉,但很快会重新注册上.

如果不在业务高峰期重启一般问题不大, 但想了下还是加了个保护模式, 当Nacos-Server集群地址有变更时, 暂停主动的ClientBeatCheckTask 30s, 这样Nacos Server可以无损的发布和重启, 重启Nacos Server对业务完全无影响.

双注册中心架构

Nacos注册中心上线后, 我们需要考虑的是和现有zk注册中心的兼容问题, 由于我们线上还有很多使用服务还在使用老版本微服务sdk, 这些服务很多都找不到维护的人, 因此我们预计到未来很长一段时间内需要保留2个注册中心, 因此需要有个服务对2个注册中心的数据进行双向同步.

Nacos官方提供了Nacos-Sync来做注册中心数据的迁移, 但调研后发现这是一个单机版的实现,主要用于一次性迁移数据, 无法达到高可用, 因此我们需要自己开发一个Sync服务,用于zk和nacos双向同步数据.

Sync服务处理的原则:

  1. 无状态, 服务实例无论是注册在zk还是nacos,两个注册中心的数据必须是一致的, 而且允许中间状态的存在(在升级过程中一个服务可能部分实例用zk,部分用nacos)

  2. 一个业务服务在绝大多数情况下,一般只存在一个双向同步任务, 在sync服务上下线过程中可能reHash出现多个sync节点都存在同一个服务的sync任务,但结果必须是一致的

  3. 一个业务服务的同步方向,是根据业务服务实例元数据( Metadata )的标记 fromSync 来决定的,比如服务实例是注册在zk, 该实例同步到nacos后会加一个fromSync的
    MetaData, 这样从Nacos同步到zk时会忽略fromSync=true的实例,避免来回同步

我们采用了一致性 Hash 方式来解决任务分配的问题,当一台或者几台同步服务器挂掉后,采用 Zookeeper 临时节点的 Watch 机制监听同步服务器挂掉情况,通知剩余同步服务器执行 reHash,挂掉服务的工作由剩余的同步服务器来承担,通过一致性 Hash 实现被同步的业务服务列表的平均分配,基于对业务服务名的二进制转换作为 Hash 的 Key 实现一致性 Hash 的算法.

Sync服务在给Nacos发送心跳时, 将心跳上报请求放入队列,以固定线程消费,当一个sync节点处理的服务实例数超过一定的阈值会造成业务服务实例的心跳发送不及时,从而造成业务服务实例的意外丢失。其实对于sync过去的服务来说, 心跳的间隔可以设置的长一些, 因为服务实例一旦在一个注册中心下线了, 会被sync服务监听到然后主动下线,这些实例并不需要nacos server频繁的主动剔除检查, 因此我们实际采用了一个15~45s的随机值作为心跳间隔, 极大的减少了sync服务发送心跳的压力,同一个服务的所有实例也不会出现集体下线的情况.

Sync服务平滑上下线

由于我们依赖zk的临时节点来做一致Hash, 当某个sync节点下线时,其他节点监听到该节点下线时有延迟的, 这样就会出现sync过去的实例会有1s左右的下线, 针对这个场景,我们实现了主动下线的逻辑, 在重启sync节点前发送主动下线命令, 该节点主动把自己从zk上摘除,并执行慢清理操作, 这样在该节点停止之前其他节点能把对应的syncTask接管过去, 实现无损下线.

最后我们的双注册中心架构如下:

0b1e5bbe5dc72247dd32e8bef111d25f.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/505865.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python通讯录管理系统 tk_通讯录管理系统课程设计

按照惯例,一波课程设计走起~ 这次写的是通讯录管理系统,经过几番大修和N1次小修之后BUG已经很少了~先来看看期间遇到的哪些问题吧: Qusetion 1:针对手机号的排序问题(即交换结构体) 2:文件写入和…

h5与小程序服务器如何辨别,小程序丨教你六招,快速区分H5页面还是APP页面

限制的H5技术和原生APP的技术很多类似或者实现效果很相像,不仔细去观察,大多人不会察觉两种有何不同。第九程序帮大家整理出比较容易判断的一个APP页面是原生的还是H5页面的方法。希望可以帮到大家,以便更加容易区分H5页面和原生App页面。 一…

蜗轮蜗杆计算软件_正确的组装蜗轮蜗杆减速机至关重要

点 工业传动共享平台”关注置顶引领减速机传动机械前沿、机械视频,汽车、加工技术、3D打印、自动化、机器人、生产工艺、轴承、模具、机床、钣金等行业前沿在这里等你 正确组装蜗轮蜗杆减速机对于公司在任何工业应用中的生产率和盈利能力至关重要。不可避免…

双重差分模型能做固定效应吗_数据分析之道 | 双重差分法(DID)

Picture from InternetDID是什么?双重差分法(DID)又被称为“倍差法”,小名“差中差”,是种专门用于分析政策效果的计量方法。我国最早引入DID方法对公共政策评估的权威文献是周黎安和陈烨(2005),研究税费改革对农民收入增长的影响…

python并发处理list数据_3种方式实现python多线程并发处理

标签&#xff1a; python奇淫技巧 最优线程数 NcpuCPU的数量 Ucpu目标CPU使用率 W/C等待时间与计算时间的比率 为保持处理器达到期望的使用率&#xff0c;最优的线程池的大小等于 $$NthreadsNcpu*Ucpu*&#xff08;1W/C$$ cpu密集型任务&#xff0c;即$W< 如果希望CPU利用率…

先出报表还是先计提所得税_一道大综合题搞定“与子公司的内部交易合并报表抵销分录”的逻辑...

有小朋友私信问我一道选择题&#xff0c;关于对子公司长期股权投资&#xff0c;存在内部交易时&#xff0c;合并报表抵销分录的问题。在跟她沟通的过程中&#xff0c;我了解到好多同学并不清楚单体报表&#xff0c;和母公司合并报表之间的关系&#xff0c;这导致大家很容易死记…

sql 百分号_SQL思维导图和代码分享

本人SQL新手&#xff0c;五一期间自学了《SQL必知必会》一书&#xff0c;在此简要分享学习心得&#xff0c;若有差错&#xff0c;请各位大佬们多多指教呀&#xff01;本人的SQL学习计划是先根据《SQL必知必会》一书入门&#xff0c;了解SQL的整体框架&#xff0c;语法等&#x…

python qt开发_Python 使用Qt进行开发(三)

下面我们实现日期时间框的添加&#xff0c;表示日期时间的文本框可以使用QtWidgets控件下的 QDateEdit() , QTimeEdit() , QDateTime() 三个方法实现。1&#xff0c;使用QDateEdit() 我们可以得到一个只显示日期的文本框&#xff0c;在文本框中我们可以手动输入日期&#xff0c…

java获取字符串第一位_Java程序员经典面试题集大全 (十一)

>>> 学习交流群 < < <111. Java中byte表示的数值范围是什么&#xff1f;答&#xff1a;范围是-128至127112.如何将日期类型格式化为&#xff1a;2013-02-18 10:53:10&#xff1f;public class TestDateFormat2 {public static void main(String[] args) thro…

django开源电子文档管理系统_Python实操技术分享:Django文件管理系统,Apple的学习思路...

一、客户端产品要求有一个更新状态按钮&#xff0c;点击更新数据后会弹出结果页面作用是检查本次读取的文档信息与数据库中文档数据的区别。同时对数据库进行对应的新增和删除操作。然后把最终的数据库信息按行显示出来&#xff0c;包括4列内容文件名&#xff0c;文件路径&…

python语言编程基础视频_网络编程-5_ Python系列视频(一)——Python语言基础_Python视频-51CTO学院...

通过学习&#xff0c;对Python有一定的了解&#xff0c;学习Python语法&#xff0c;可以使用Python原生语言开发项目。对于Python的应用于开发有一个系统的认知&#xff0c;对于未来的发展方向有清晰的认识。主要知识点包括基本语法、文件操作、库、面向对象、进程线程协程、网…

python打包出现乱码_python解压zip包中文乱码解决方法

乱码得原因&#xff1a; 由于ZipFile模块导出遇到中文解码不对&#xff0c;windows上会出现&#xff0c;linux是否会出现不知道没测试过。 解决方式&#xff1a; 1. 搞个文件名引射表(不太方便&#xff0c;少量文件夹套用时候还可以) 2. 修改源码解码格式(不太方便&#xff0c;…

redis重启命令_请收下这份redis持久化详解

前言Redis支持RDB和AOF两种持久化机制&#xff0c; 持久化功能有效地避免因进程退出造成的数据丢失问题&#xff0c; 当下次重启时利用之前持久化的文件即可实现数据恢复。RDB介绍按指定时间间隔把数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发。自动…

arp miss攻击_网络应用华为S9300核心交换机ARP安全配置

ARP安全简介ARP 安全通过过滤不信任的ARP 报文以及对某些ARP 报文进行时间戳抑制来保证网络设备的安全性和健壮性。网络中有很多针对ARP 表项的攻击&#xff0c;攻击者通过发送大量伪造的ARP 请求、应答报文攻击网络设备&#xff0c;主要有ARP 缓冲区溢出攻击和ARP 拒绝服务攻击…

python实现二分查找算法_两种方法实现Python二分查找算法

一. arr[1,3,6,9,10,20,30] def findnumber(l,h,number): mid(lh)//2 if arr[mid]number: print("找到了"str(mid)) elif arr[mid] l mid return findnumber(mid1,h,number) elif arr[mid]>number: h mid return findnumber(0,mid-1,number) else: print("…

python 动态规划 回溯_回溯算法 - 全排列算法实现(pythondart)

回溯算法 , 就是 穷举解决一个回溯问题,实际上就是一个决策树的遍历过程.路径: 也就是已经做出的选择选择列表: 也就是你当前可以做的选择结束条件: 也就是到达决策树底层,无法再做选择的条件.回溯算法的一个特点: 它不像动态规划存在重叠子问题可以优化,回溯算法就是纯暴力穷举…

python 苹果id申请_如何申请百度机器翻译API的ID和Key,为Python调用做准备

1.打开以下页面&#xff1a; http://api.fanyi.baidu.com/api/trans/product/index 2. 在网页找到“立即使用”并点击&#xff0c;之后&#xff0c;如果要求你登录百度&#xff0c;那就用你已有的百度账号登录&#xff0c;如果没有百度账号&#xff0c;请先申请一个百度账号&am…

华为简易压缩算法python_Python(9) --实现一个简单的压缩软件/解压软件的功能

#压缩软件#导入所需模块&#xff0c;设置界面import osimport zipfileimport tkinterimport tkinter.messageboximport tkinter.filedialogroot tkinter.Tk()root.title(我的压缩软件)root.minsize(300,400)#设置需要压缩文件的路径变量filenames []#添加文件的函数def addfi…

python from import什么意思_Python 引用From import介绍

一. 模块的定义与分类模块是什么&#xff1f;​ 这几天&#xff0c;我们进入模块的学习。在学习模块之前&#xff0c;我们首先要知道&#xff0c;什么是模块&#xff1f;​ 一个函数封装一个功能&#xff0c;你使用的软件可能就是由n多个函数组成的(先不考虑面向对象)。比如抖音…

去掉窗口_Flink 基础——窗口(Window)理论篇

窗口是什么要知道 Flink 面对的是无限的数据流&#xff0c;而批处理只是流处理的一个特例&#xff0c;然而我们的计算只能基于一个有限的集合&#xff0c;这个时候窗口正好定义了这其中的概念。因此可以说了解窗口机制是学习 Flink 的基础也是关键。总结来说&#xff0c;窗口将…