技术大佬问我,中间件是如何做到高可用的(上)

当我们在讨论软件高可用的时候,我们到底是在说什么?

应用具备高可用? 中间件具备高可用? 应用上层的nginx具备高可用? DNS 具备高可用?

连身为一线互联网大厂的阿里都宕机了,所谓的高可用,其实是不可用?

对于高可用,网上有这样两种声音:一种是无用论 ,一种是神话论

无用论的观点。比如:一线互联网大厂阿里语雀 都宕机8个小时以上了,高可用的3个9都达不到,但还看到他们 到处宣讲自己系统有多么的高可用,所谓的高可用,其实是不可用。

还有一种 神话论的观点。比如:高可用,是解决系统可用性的高级手段和唯一法宝;过分夸大高可用的作用;将其视为解决软件可用性的的万能药;是解决所有可用性问题的唯一因素。

个人观点

阿里语雀宕机的个别事件,并不能代表软件高可用思想是无用的。这种说法,多少有点以偏概全的谬误。

软件高可用是软件三高的特征之一,因其实现的技术较复杂;大学里开设的专业课程又很少会单独讲到这块;另外在实际的业务研发中,又很少的接触和考虑到它,所以在大众面前,显的很神秘;而这份神秘感,在外界不断的强化对软件高标准的追求时,导致在研发人面前,显的很神话(科班不教,工作中又很少接触,涉及到的技术又很晦涩难懂,又是后端技术人在技术层面追求的目标之一 )。并且这种神话还有可能会掩盖软件领域其它技术问题,比如应用的性能,安全性,应用性等。

系统高可用不是万能的,系统高可用是有一定的前提条件的。这些前提条件包括,系统运行所依赖的硬性条件,软件环境,还有人为因素

硬性条件 比如:电力,网络;所在机房在物理地址上的稳定性。地球都毁灭了,还在说系统具备高可用,那就是在扯淡了;除非系统是垮星球部署。一般软件的高可用方案不能解决这些问题。

软件条件 :指系统运行依赖的底层软件,比如操作系统,或者底层驱动,或者三方依赖,又或者部分服务器的磁盘,网络 物理上的损害。软件层面和部分物理机的硬件故障,导致的系统不可用,是一般软件高可用方案擅长解决的问题领域。

人为因素 :删库跑路;人为写的隐藏bug 导致全系统宕机;APP首页打不开等。这些人为因素和系统性bug,导致的全局软件不可用;也不是一般软件高可用方案擅长解决的领域;要防止这些问题的发生,可能更需要借用软件领域的其它"银弹"。比如 code review;服务的降级,限流;线上操作权限限制和规范化管理等。

高可用的衡量指标有哪些呢?

一般用可用性指标 来进行衡量,即系统全年 提供服务的时间/一年的时间。比如一年365天,系统正常运行了364天,可用性为 99.72%;

假设系统要达到 3个9的可用性,即99.9%,一年能宕机(不可提供服务)多久了? 8.76个小时

假设系统要达到 4个9的可用性,即99.99%,一年能宕机(不可提供服务)多久了?0.876个小时,52.56分钟

而一般我们说系统要至少达到 4个9才具备高可用。 即一年只能宕机 52.56分钟。太难了,特别是系统还在不断的发展和演进中,还要想达到此目标,那更是难上加难。

中间件高可用的初级玩法是怎样的了?

冗余: 高可用的基石

软件层面冗余:比如服务冗余,数据冗余;像redis 有主从节点。从节点是对主节点服务和数据冗余;kafka的topic 有分区的概念;分区上有主从之分,从分区是对主分区数据的冗余。kafka数据冗余的机制和流程请看《技术大佬问我,kafka是如何做到数据的高可靠的(上)》《技术大佬问我,kafka是如何做到数据的高可靠的(下)》

硬件层面也有冗余:比如电力冗余,网络冗余等;在机房没电的时候,备用的UPS就该上场了。

故障检测

故障检测,是主动发现集群中问题节点 的关键。我们都希望集群中的服务节点是健康的,如果有不健康,不能对外提供服务怎么办?最理想的状态,是无缝的用前面提到的 正常的冗余节点 替换那些 不健康节点,以此保证系统具备最高可用性。

而如何发现集群中,某个节点不健康了,一般通过两种方式:

像,常用中间件redis,是通过哨兵节点,以一定的检测频率,不断的像其他master和slave节点,发送探活请求,来进行存活检测;此种方式属于被动接受健康检查

kafka 主要是借用三方中间件zk来实现故障检测(最新的版本可以kafka自带选KRAFT机制): kafka broker节点,也是以一定的频率,主动向zk发送心跳请求;kafka 认为: 如果broker不能向zk 发送心跳,那么在zk上注册的临时节点,就会被删除;以此触发对应的watch事件,然后被kafka controller 节点监听到该事件,感知到整个集群中,那些节点是非存活。

故障转移----选主

选主核心思想:候选节点的数据,尽量和主节点保持一致。

kafka的选主思想: kafka的选主,是由controller节点负责的。controller会从ISR分区列表里,顺序选择下一个从分区做为该分区的主分区。(该选主算法非常的简单,之所以这么的简单,是因为 kafka 规定,分区如果是在ISR分区集合里,就是和主分区保持同步的,没有和主分区保持同步,会被踢出ISR分区列表,即我们说的非ISR分区)

redis的选主过程和思想较为的灵活和复杂了:

1) 在进行选主之前,redis需要从众多的哨兵节点中,选举一个哨兵出来,进行选主操作

2) 确定好了选主哨兵后,由该哨兵进行后续的选主工作

3) 哨兵会排除待选节点超过断开连接一定时长的节点(这个能理解,毕竟超过一定时长,该节点大概率会落后主节点数据太多)

4)哨兵会对从节点上配置的优先级进行排序,优先级越高,被选中的权利越大(有点 人为干预选举过程了,比如机器配置好的,优先级配置的高一点,被选中的概率也高一些)

5)优先级相同的情况下,会比较replica offset,replica offset越大的,就越接近主节点的数据,会优先被选择为新主

6) 如果上面的条件都满足的情况下,选择 run id比较小的slave做为新主(较小的"run id"通常表示节点是最近启动的,因此它可能拥有较新的数据,而较大的"run id"则可能表示节点已经运行了较长时间,可能存在较旧的数据。)

通知外部切换 --------外部无缝切换

选取新主后,redis外部切换

redis的外部,主要有两部分,一部分是redis客户端,一部分是其它的slave。

其它的slave感知到新主,可通过redis的pub/sub机制,通知给其它从节点进行新主的切换。

而redis客户端需要感知到新主,不同的redis客户端,底层机制可能不太一样。比如Lettuce、Jedis客户端 定期向Redis服务器发送PING命令以检查连接的健康状态。如果客户端的连接不再有效(比如连接的是原主节点,但该节点已经不再是主节点),客户端库会尝试重新连接到集群,并根据最新的集群拓扑结构来更新连接信息。

如果客户端使用了Redis Sentinel作为监控和管理工具,那么Sentinel客户端会持续监听Redis主节点切换事件。一旦发生主节点切换,Sentinel客户端会收到通知,并可以更新客户端的连接信息以连接到新的主节点。

选取新主后,kafka客户端外部切换:

kafka客户端感知到新主分区变化,主要是kafka 客户端通过和broker集群进行通信时感知到的。

比如kafka客户端的IO线程,会以固定的频率,向集群发送Metadata请求以获取当前的集群元数据,包括主题(topics)、分区(partitions)以及每个分区的leader副本等信息。当主分区发生切换时,集群的元数据会更新,客户端下次发送Metadata请求时会收到更新后的元数据,从而感知到主分区的变化,以此切换底层的链接信息。

总结

  1. 高可用并不是解决软件所有问题的唯一因素,无需贬低高可用,也无需一味的赞扬高可用。一般软件的高可用,有自己解决的问题领域,这些领域包括,底层操作系统出现故障时,集群中某些节点不能提供服务时,集群中某些物理机的硬件不能正常工作时

  2. 高可用的度量指标,一般用系统在一年时间内,能正常工作的时间比例来进行计算;3个9也是灰常的厉害了。

  3. 软件高可用的一般玩法。冗余,故障检测,故障转移,外部通知和切换。

原创不易,请 点赞,留言,关注,收藏 4暴击^^

相关推荐
DogDaoDao3 小时前
leetcode 面试经典 150 题:有效的括号
c++·算法·leetcode·面试··stack·有效的括号
桂月二二4 小时前
探索前端开发中的 Web Vitals —— 提升用户体验的关键技术
前端·ux
Ai 编码助手5 小时前
在 Go 语言中如何高效地处理集合
开发语言·后端·golang
小丁爱养花5 小时前
Spring MVC:HTTP 请求的参数传递2.0
java·后端·spring
Channing Lewis5 小时前
什么是 Flask 的蓝图(Blueprint)
后端·python·flask
hunter2062066 小时前
ubuntu向一个pc主机通过web发送数据,pc端通过工具直接查看收到的数据
linux·前端·ubuntu
qzhqbb6 小时前
web服务器 网站部署的架构
服务器·前端·架构
刻刻帝的海角6 小时前
CSS 颜色
前端·css
九酒6 小时前
从UI稿到代码优化,看Trae AI 编辑器如何帮助开发者提效
前端·trae
浪浪山小白兔7 小时前
HTML5 新表单属性详解
前端·html·html5