前面学习了MySQL数据库的复制、优化,以及基于复制技术实现业务层的读写分离方案,这些内容是为了铺垫MySQL数据库的高可用架构设计。因为复制是高可用的基础,但只用复制同步数据远远不够,还要结合自己的业务进行高可用设计。
同时,高可用也不仅仅是数据库的事,你要从业务的全流程出发,思考怎么设计一个真正健壮的高可用架构。
高可用概念(High Availability)
首先,我们来看一下wiki上对高可用的定义:
High availability (HA) is a characteristic of a system which aims toensure an agreedlevel of operational performance, usually uptime, for a higher than normal period.
从上面的描述来看,高可用是系统能提供无故障服务的一种能力。简单地说就是避免服务器宕机而造成服务不可用。
我们都知道,高可用是每个业务系统设计时,开发人员必须考虑的关键点。比如你的系统在发生不可用时,业务表现如何?用户能否容忍你的不可用时长?
而业界度量高可用能力也有统一标准:判断宕机时间,并以此计算出每年系统可用时间达到几个9,来判断高可用架构是否健壮。具体如下表:
通常来说,系统至少要达到4个9(99.99%),也就是每年宕机时间不超过52.56分钟,否则用户体验会非常差,感觉系统不稳定。
不过4个9宕机52分钟对于生产环境的影响还是比较大,但是5个9对大部分系统来说要求又太高。所以一些云服务商会提出一个99.995%的可用性概念,那么系统一年的不可用时长为26.28分钟。
高可用架构设计
系统要达到高可用,一定要做好软硬件的冗余,消除单点故障(SPOFsingle point of failure)。
冗余是高可用的基础,通常认为,系统投入硬件资源越多,冗余也就越多,系统可用性也就越高。
除了做好冗余,系统还要做好故障转移(Failover)的处理。也就是在最短时间内发现故障,然后把业务切换到冗余的资源上。
在明确上述高可用设计的基本概念之后,我们来看一下高可用架构设计的类型:无状态服务高可用设计、数据库高可用架构设计。
无状态的服务高可用设计(如Nginx)
高可用设计非常简单,发现问题直接转移就行,甚至可以通过负载均衡服务,当发现有问题,直接剔除:
上图中,当一台Nginx服务器出现问题,导致服务不可用,Load Balance复制均衡发现后,就可以直接把它剔除。对于上层用户来说,他只会在几秒内的访问出现问题,之后服务就立刻恢复了,无状态的服务,高可用设计就是这么简单。
数据库高可用架构设计
所以,系统高可用设计,真正的难点、痛点不在于无状态服务的设计,而在于数据库的高可用设计,这是因为:
数据持久化在数据库中,是有状态服务数据库的容量比较大,Failover的时间相对无状态服务会更多一些系统,如金融场景的数据库,会要求数据完全不丢失,这又增加了高可用实现的难度
其实从架构角度来看,数据库高可用本身也是业务高可用,所以我们要从业务全流程的角度出发,思考数据库的高可用设计。这里提供三种数据库的高可用架构设计方法,他们不仅适用于MySQL数据库,也适用于其他数据库。
基于数据层的数据库高可用架构
基于数据层的数据库高可用架构,就是基于数据同步技术。当主服务器Master发生宕机,则故障迁移到从服务器Slave。
对于MySQL数据库来说,就是基于前面介绍的复制技术。
可以发现,我们原先的Slave3从服务器提升为了主服务器,然后建立了新的复制拓扑架构,Slave1、Slave2都连接到新的Master进行数据同步 。
Slave2都连接到新的Master进行数据同步 。所以需要引入VIP(Virtual IP)虚拟IP技术,当发生宕机时,VIP也需要漂移到新的主服务器。
那么这个架构的真正难点在于:
如何保障数据一致性如何发现主服务器宕机故障转移逻辑的处理
我们可以通过MySQL提供的无损复制技术,来保障“数据一致性”。而“发现主服务器宕机”、“处理故障转移逻辑”要由数据库高可用套件完成,后续再来学习。
基于业务层的数据库高可用架构
完全基于业务实现,数据库只是用于存储数据。当一台数据库主服务器不可用,业务直接写另一台数据库主服务器就可以了。
Service服务器写入Master1主服务器失败后,不用等待故障转移程序启用主从切换,而是直接把数据写入Master2主服务器。这看似是一种非常简单、粗暴的高可用架构实现方式,但能符合这样设计的业务却并不多,因为该设计前提是状态可修改.
比如电商中的订单服务,其基本逻辑就是存储电商业务中每笔订单信息,核心逻辑就是往表Orders中插入数据,即:
INSERT INTO Orders (o_orderkey,..) VALUES (...)
这里o_orderkey是主键。为了实现基于业务层的数据库高可用,可以在主键生成过程中加入额外信息,比如服务器编号,这样订单的主键设计变为了:
PK = 有序UUID-服务器编号
这样的话,当写入服务器编号1时失败了,业务层会把订单的主键修改为服务器编号2,这样就实现了业务层的高可用,电商中的这种订单号生成方式也称为“跳单”。
而当查询订单信息时,由于主键中包含了服务器编号,那么业务知道该笔订单存储在那台服务器,就可以非常快速地路由到指定的服务器。
但这样设计的前提是整个服务的写入主键是可以进行跳单设计,且查询全部依赖主键进行搜索。
看到这里,你是不是觉得非常符合NoSQL的KV访问设计?
融合的高可用架构设计
“基于业务层的数据库高可用架构”中,虽然通过跳单设计,可以实现写入业务的高可用实现。但这时订单服务的查询功能会收到极大影响。当编号为1的服务器发生宕机,那么服务器编号为1的订单将无法查询。
所以,给出一种业务和数据层相结合的高可用设计。这个架构可以解决宕机后,查询服务受限的问题。
将不同编号的订单根据不同的数据库进行存放,比如服务器编号为1的订单放到DB1,服务器编号为2的订单放到数据库DB2中。
此外,这里也用到了MySQL复制中的部分复制技术,即左下角的主服务器仅将DB1中的数据同步到右上角的服务器。同理,右上角的主服务器仅将DB2中的数据同步到左上角的服务器,下面的两台服务器不变,依然从原来的MySQL实例中同步数据。
这样做的好处:
在常态情况下,上面两台MySQL数据库是双活的,都可以有数据写入,业务的性能得到提升
订单数据是完整的,服务器编号为1和2的数据都在一个MySQL实例上
更重要的是,当发生宕机,Service服务写入不受影响,写入服务器编号为1的订单通过跳表设计写入DB2。
同时,对于订单读取也不会收到影响,因为数据库都是在一个实例上:
总结
1.高可用是系统所能提供无故障服务的一种能力,度量单位是几个9
2.线上系统高可用目标不应该低于99.995%,否则系统频繁宕机,用户体验不好
3.高可用实现基础是:冗余+故障迁移
4.无状态服务的高可用设计较为简单,直接故障转移或剔除就行
5.数据库作为有状态的服务,设计比较复杂(冗余通过复制技术实现,故障转移需要对应的高可用套件)
最后给大家分享Spring系列的学习笔记和面试题,包含spring面试题、spring cloud面试题、spring boot面试题、spring教程笔记、spring boot教程笔记、最新阿里巴巴开发手册(63页PDF总结)、Java面试手册。一共整理了1184页PDF文档。私信博主(666)领取,祝大家更上一层楼!!!