高可用

发布时间:2022-06-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了高可用脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

互联网三高之高可用

王江伟1

(1. 石家庄铁道大学,河北省 石家庄市 050000)

摘要: 提到高可用,高性能,高并发很多人都喜欢混为一谈,一大堆集群分布式,缓存等等,其实这是三个不同的概念,也会相互结合着使用。 本文主要介绍高可用的相关技和解决方案

关键词:高可用,分布式

中图分类号:   文献标志码:A

引言

本文主要介绍一下互联网三高(高并发、高性能、高可用)中的高可用,看完本文相信能解开你关于高可用设计的大部分困惑

第一章 前言

1.1  高可用概念和目的

高可用性H.A.(High AvailabilITy)指的是通过尽量缩短因日常维护操作(计划)和突发的系统崩溃(非计划)所导致的停机时间,以提高系统和应用的可用性。它与被认为是不间断操作的容错技术有所不同。HA系统是企业止核心计算机系统因故障停机的最有效手段

高可用(High availability,即 HA)的主要目的是为了保障「业务的连续性」,即在用户眼里,业务永远正常或者说基本正常)对外提供服务的。高可用主要是针对架构而言,那么要做好高可用,就要首先设计好架构,第一步我们一般会采用分层的思想将一个庞大的 IT 系统拆分成为应用层,中间件,数据存储层等独立的层,每一层再拆分成为更细粒度的组件,第二步就是让每个组件对外提供服务,毕竟每个组件都不是孤立存在的,都需要互相协作,对外提供服务才有意义。

1.2   系统可用性衡量

 

 

第二章 互联网架构剖析

2.1  微服务架构

目前多数互联网都会采用微服务架构,常见架构如下:

 

  1. 接入层:主要由 F5 硬件或 LVS 软件来承载所有的流量入口
  2. 反向代理层:Nginx,主要负责根据 url 来分发流量,限流等
  3. 网关:主要负责流控,风控,协议转换等
  4. 站点层:主要负责调用会员,促销等基本服务来装配 JSON 等数据并返回给客户端
  5. 基础 service:其实与站点层都属于微服务,是平级关系,只不过基础 service 属于基础设施,能被上层的各个业务层 server 调用而已
  6. 存储层:也就是 DB,如 MySQLoracle 等,一般由基础 service 调用返回给站点层
  7. 中间件:ZK,ES,redis,MQ 等,主要起到加速访问数据等功能,在下文中我们会简单介绍下各个组件的作用

如前所述,要实现整体架构的高可用,必须要实现每一层组件的高可用,接下来我们就来分别看一下每一层的组件都是如何实现高可用的

2.2  接入层&反向代理层

这两层的高可用都和 keepalived 有关,所以我们结合起来一起看

 

对外,两个 LVS 以主备的形式对外提供服务,注意只有 master 在工作(即此时的 VIP 在 master 上生效),另外一个 backup 在 master 宕机之后会接管 master 的工作,那么 backup 怎么知道 master 是否正常呢,答案是通过 keepalived,在主备机器上都装上 keepalived 软件,启动后就会通过心跳检测彼此的健康状况,一旦  master 宕机,keepalived 会检测到,从而 backup 自动转成 master 对外提供服务,此时 VIP 地址(即图中的 115.204.94.139)即在 backup 上生效,也就是我们常说的「IP漂移」,通过这样的方式即解决了 LVS 的高可用。

keepalived 的心跳检测主要通过发送 ICMP 报文,或者利用 TCP 的端口连接和扫描检测来检测的,同样的,它也可以用来检测 Nginx 暴露的端口,这样的话如果某些 Nginx 不正常 Keepalived 也能检测到并将其从 LVS 能转发的服务列表中剔出。

借用 keepalived 这个第三方工具,同时实现了 LVS 和 Nginx 的高可用,同时在出现故障时也可以将宕机情况发送到对应开发人员的邮箱以让他们及时收到通知处理,确实很方便,Keepalived 应用广泛,下文我们会看到它也可以用在 MySQL 上来实现 MySQL 的高可用。

2.3微服务

接下来我们再来看一下「网关」,「站点层」,「基础服务层」,这三者一般就是我们所说的微服务架构组件,当然这些微服务组件还需要通过一些 RPC 框架如 Dubbo 来支撑才能通信,所以微服务要实现高可用,就意味着 dubbo 这些 RPC 框架也要提供支撑微服务高可用的能力,我们就以 dubbo 为例来看下它是如何实现高可用的

我们先来简单地看下 dubbo 的基本架构

 

思路也很简单,首先是 PRovider(服务提供者)向 Registry(注册中心,如 ZK 或 Nacos 等)注册服务,然后 Consumer(服务消费者)向注册中心订阅和拉取 Provider 服务列表,获取服务列表后,Consumer 就可以根据其负载均衡策略选择其中一个  Provider 来向其发出请求,当其中某个 Provider 不可用(下线或者因为 GC 阻塞等)时,会被注册中心及时监听(通过心跳机制)到,也会及时推送给 Consumer,这样 Consumer 就能将其从可用的 Provider 列表中剔除,也就实现了故障的自动转移,不难看出,注册中心就起到了类似 keepalived 的作用.

2.4中间件

我们再来看下这些中间件如 ZK,Redis 等是如何实现高可用的呢

ZK

上一节微服务中我们提到了注册中心,那我们就以 ZK(ZooKeePEr)为例来看看它的高可用是如何实现的,先来看下它的整体架构图如下

 

Zookeeper 中的主要角色如下

Leader: 即领导者,在集群中只有一个 Leader,主要承担了以下的功能

事务请求的唯一调度和处理者,保证集群事务处理的顺序性,所有 Follower 的写请求都会转给 Leader 执行,用来保证事务的一致性

集群内部各服务器的调度者:处理好事务请求后,会将数据广播同步到各个 Follower,统计 Follower 写入成功的数量,超过数 Follower 写入成功,Leader 就会认为写请求提交成功,通知所有的 Follower commit 这个写操作,保证事后哪怕是集群崩溃恢复或者重启,这个写操作也不会丢失。

Follower:

1.处理客户端非事务请求、转发事务请求给 leader 服务器

2.参与事物请求 Proposal 的投票(需要半数以上服务器通过才能通知 leader commit 数据; Leader 发起的提案,要求 Follower 投票)

3.参与 Leader 选举的投票

可以看到由于只有一个 Leader,很显然,此 Leader 存在单点隐患,那么 ZK 是怎么解决此问题的呢,首先 Follower 与 Leader 会用心跳机制保持连接,如果 Leader 出现问题了(宕机或者因为 FullGC 等原因无法响应),Follower 就无法感知到 Leader 的心跳,就会认为 Leader 出问题了,于是它们就会发起投票选举,最终在多个 Follower 中选出一个 Leader 来(这里主要用到了 Zookeeper Atomic broadcast,即 ZAB 协议,它是为 ZK 专门设计的一种支持崩溃恢复的一致性协议),选举的细节不是本文重点,就不在此详述了。

除了 ZAB 协议,业界上常用的还有 Paxos,Raft 等协议算法,也可以用在 Leader 选举上,也就是是在分布式架构中,这些协议算法承担了“第三者”也就是仲裁者的作用,以承担故障的自动转移.

2.5Redis

Redis 的高可用需要根据它的部署模式来看看,主要分为「主从模式」和「Cluster 分片模式」两种

主从模式

先来看一下主从模式,架构如下

主从模式

主从模式即一主多从(一个或者多个从节点),其中主节点主要负责读和写,然后会将数据同步到多个从节点上,Client 也可以对多个从节点发起读请求,这样可以减轻主节点的压力,但和 ZK 一样,由于只有一个主节点,存在单点隐患,所以必须引入第三方仲裁者的机制来判定主节点是否宕机以及在判定主节点宕机后快速选出某个从节点来充当主节点的角色,这个第三方仲裁者在 Redis 中我们一般称其为「哨兵」(sentinel),当然哨兵进程本身也有可能挂掉,所以为了安全起见,需要部署多个哨兵(即哨兵集群)

哨兵集群

这些哨兵通过 gossip(流言) 协议来接收关于主服务器是否下线的信息,并在判定主节点宕机后使用 Raft 协议来选举出新的主节点

2.6Cluster 分片集群

主从模式看似完美,但存在以下几个问题

1.主节点写的压力难以降低:因为只有一个主节点能接收写请求,如果在高并发的情况下,写请求如果很高的话可能会把主节点的网卡打满,造成主节点对外无法服务

2.主节点的存储能力受到单机存储容量的限制:因为不管是主节点还是从节点,存储的都是全量缓存数据,那么随着业务量的增长,缓存数据很可能直线上升,直到达到存储瓶颈

3.同步风暴:因为数据都是从 master 同步到 slave 的,如果有多个从节点的话,master 节点的压力会很大

了解决主从模式的以上问题,分片集群应运而生,所谓分片集群即将数据分片,每一个分片数据由相应的主节点负责读写,这样的话就有多个主节点来分担写的压力,并且每个节点只存储部分数据,也就解决了单机存储瓶颈的问题,但需要注意的是每个主节点都存在单点问题,所以需要针对每个主节点做高可用,整体架构如下

 

原理也很简单,在 Proxy 收到 client 执行的 redis 的读写命令后,首先会对 key 进行计算得出一个值,如果这个值落在相应 master 负责的数值范围(一般将每个数字称为槽,Redis 一共有 16384 个槽)之内,那就把这条 redis 命令发给对应的 master 去执行,可以看到每个 master 节点只负责处理一部分的 redis 数据,同时为了避免每个 master 的单点问题,也为其配备了多个从节点以组成集群,当主节点宕机时,集群会通过 Raft 算法来从从节点中选举出一个主节点

2.7ES

再来看一下 ES 是如何实现高可用的,在 ES 中,数据是以分片(Shard)的形式存在的,如下图所示,一个节点中索引数据共分为三个分片存储

 

但只有一个节点的话,显然存在和 Redis 的主从架构一样的单点问题,这个节点挂了,ES 也就挂了,所以显然需要创建多个节点

 

一旦创建了多个节点,分片(图中 P 为主分片,R 为副本分片)的优势就体现出来了,可以将分片数据分布式存储到其它节点上,极大提升了数据的水平扩展能力,同时每个节点都能承担读写请求,采用负载均衡的形式避免了单点的读写压力

ES 的写机制与 Redis 和 MySQL 的主从架构有些差别(后两者的写都是直接向 master 节点发起写请求,而 ES 则不是),所以这里稍微解释一下 ES 的工作原理

 

首先说下节点的工作机制,节点(Node)分为主节点(Master Node)和从结点(Slave Node),主节点的主要职责是负责集群层面的相关操作,管理集群变更,如创建或删除索引,跟踪哪些节点是集群的一部分,并决定哪些分片分配给相关的节点,主节点也只有一个,一般通过类 Bully 算法来选举出来,如果主节点不可用了,则其他从节点也可以通过此算法来选举以实现集群的高可用,任何节点都可以接收读写请求以达到负载均衡的目的

 

再说一下分片的工作原理,分片分为主分片(Primary Shard,即图中 P0,P1,P2)和副本分片(Replica Shard,即图中 R0,R1,R2),主分片负责数据的写操作,所以虽然任何节点可以接收读写请求,但如果此节点接收的是写请求并且没有写数据所在的主分片话,此节点会将写请求调度到主分片所在的节点上,写入主分片后,主分片再把数据复制到其他节点的副本分片上,以有两个副本的集群为例,写操作如下

 

2.8MQ

ES 利用数据分片来提升高可用和水平扩展能力的思想也应用在其他组件的架构设计上,我们以 MQ 中的 Kafka 为例再来看下数据分片的应用

Kafka 高可用设计,图片来自《武哥漫谈IT》

如上是 Kafka 集群,可以看到每个 Topic 的 Partition 都分布式存储在其它消息服务器上,这样一旦某个 Partition 不可用,可以从 follower 中选举出 leader 继续服务,不过与 ES 中的数据分片不同的是,follower Partition 属于冷备,也就是说在正常情况下不会对外服务,只有在 leader 挂掉之后从 follower 中选举出 leader 后它才能对外提供服务.

2.8存储层

接下来我们再来看一下最后一层,存储层(DB),这里我们以 MySQL 为例来简单地讨论一下其高可用设计,其实大家如果看完了以上的高可用设计,会发现 MySQL 的高可用也不过如此,思想都是类似的,与 Redis 类似,它也分主从和分片(即我们常说的分库分表)两种架构

主从的话与 LVS 类似,一般使用 keepalived 的形式来实现高可用,如下所示

 

如果 master 宕机了,Keepalived 也会及时发现,于是从库会升级主库,并且 VIP 也会“漂移”到原从库上生效,所以说大家在工程配置的 MySQL 地址一般是 VIP 以保证高可用

数据量大了之后就要分库分表了,于是就有了多主,就像 Redis 的分片集群一样,需要针对每个主配备多个从,如下

 

之前有读者问分库分表之后为啥还要做主从,现在我想大家应该都明白了,不是为了解决读写性能问题,主要是为了实现高可用.

4  结束语

看完了架构层面的高可用设计,相信大家对高可用的核心思想「冗余」和「自动故障转移」会有更深刻的体会,观察以上架构中的组件你会发现冗余的主要原因是因为只有一主,为什么不能有多主呢,也不是不可以,但这样在分布式系统下要保证数据的一致性是非常困难的,尤其是节点多了的话,数据之间的同步更是一大难题,所以多数组件采用一主的形式,然后再在主和多从之间同步,多数组件之所以选择一主本质上是技术上的 tradeoff.

  那么做好每个组件的高可用之后是否整个架构就真的可用了呢,非也,这只能说迈出了第一步,在生产上还有很多突发情况会让我们的系统面临挑战,所以除了做好架构的高可用之外,我们还需要在做好系统隔离,限流,熔断,风控,降级,对关键操作限制操作人权限等措施以保证系统的可用。另外我们最好能做到事前防御,在系统出问题前把它扼杀在摇篮里,所以我们需要做单元测试,做全链路压测等来发现问题,还需要针对 CPU,线程数等做好监控,当其达到我们设定的域值时就触发告警以让我们及时发现修复问题(我司之前就碰到过一个类似的生产事故复盘大家可以看一下),此外在做好单元测试的前提下,依然有可能因为代码的潜在 bug 引起线上问题,所以我们需要在关键时间(比如双十一期间)封网(也就是不让发布代码)

此外我们还需要在出事后能快速定位问题,快速回滚,这就需要记录每一次的发布时间,发布人等,这里的发布不仅包括工程的发布,还包括配置中心等的发布.

 

 

参考文献:

[1] 苏三. 你管这破玩意儿叫高可用, 2022.

 

 

 

脚本宝典总结

以上是脚本宝典为你收集整理的高可用全部内容,希望文章能够帮你解决高可用所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。