关于数据库:如何避免这10类常见故障B站数据库架构设计做了这5步……

3次阅读

共计 5225 个字符,预计需要花费 14 分钟才能阅读完成。

往年 3 月 GitHub 在一周内呈现了屡次服务不可用的状况,每起事件继续时长在 2-5 小时,据有媒体统计,GitHub 在一周中屡次中断影响的开发者数量高达 7300 万。预先 GitHub 高级工程副总裁 Keith Ballinger 发文示意,「我晓得这会影响许多客户的生产力,咱们也非常重视这一点。过来几周产生的宕机事件根本原因是咱们的‘MySQL1’集群中的资源抢夺,在负载高峰期,影响了 GitHub 大量服务和性能。」

数据库故障对企业零碎服务的影响可见一斑,明天我将联合 B 站本身的实战经验来跟大家说说数据库故障治理相干的心得:

作者介绍

B 站 DBA Leader- 王志广
十年以上数据库运维教训,曾在多家大型互联网公司任职,主导和参加了多家数据库公有云建设、数据库多活、数据库架构从商业数据库到开源数据库的迁徙。目前次要专一于 B 站数据库多活、数据库服务治理等。
舒适揭示:本文约 4900 字,预计破费 8 分钟浏览。
回复“交换”进入读者交换群;

一、什么是数据库故障

数据库故障顾名思义就是数据库相干的故障,它在学术上没有明确的定义,故各公司个别以对利用的影响范畴来量化定义数据库故障。如下图所示:

二、常见的数据库故障有哪些?

故障治理就得隔靴搔痒,所以治理的第一步就是明确常见的数据库故障有哪些,明天就 MySQL、缓存两个大方向来跟大家一起梳理一下。

1、MySQL

作为在互联网公司宽泛应用的传统意义上的数据库,MySQL 的故障能够分为以下几种:

1.1 实例不可用
数据库作为一种非凡的利用,在其生命周期内无奈保障 100% 可用。数据库实例不可用的起因个别有:硬件故障:硬件故障是生产环境中无奈防止问题。常见的硬件故障蕴含了 CPU、内存、磁盘、主板等。系统故障:系统故障蕴含操作系统 bug 和数据库 bug。网络故障:网络故障蕴含网络设备故障和专线故障。其余:如资源分配不合理导致的 OOM。

1.2 数据提早
数据提早蕴含数据库的主从提早和依赖 binlog 的数据订阅服务的提早。

1.2.1 主从复制提早主从复制提早是线上经常出现的问题之一,对于读写拆散的业务来说,从库提早的影响可能是致命的。导致主从提早的起因个别有: 主库执行了一个十分大的数据变更事务;主库变更频率过快, 导致从库跟不上;应用原生的表构造变更语句进行大表的 DDL;从库配置参数较低、硬件性能较差;从库负载过高,导致性能变差;从库 MDL 锁;主从之间网络问题;主从复制 Bug (多线程复制 bug 最为常见)。

1.2.2 数据订阅服务的提早 binlog 的生产是数据订阅服务中的外围性能之一,对很多依赖 binlog 生产的业务来说,订阅服务的提早将导致线上业务的不可用,导致订阅服务提早的起因个别有:上游从库提早 Kafka 性能瓶颈 canal 类组件性能瓶颈

1.3 数据损坏

数据损坏随时可能产生在任何人身上,没有任何方法可保障它不会产生。导致数据损坏的起因如下:未开启双一参数,在宕机场景下失落;未应用半同步复制,在宕机场景下失落;应用三方工具进行 DDL 的某些非凡场景下可能会丢,比方 pt-osc、gh-ost;误操作、误删除数据或者蓄意删除,也就是常说的运维人员删库跑路。

1.4 性能降落

数据库的性能降落个别有以下几种体现慢查问增多、性能抖动、压力过载。

1.4.1 慢查问增多慢查问也是咱们常常会遇到的场景,重大状况下会导致数据库雪崩,个别导致慢查问增多有如下起因:新业务上线 SQL 效率较差或者没有适合的索引;业务场景产生扭转, 边缘场景被触发;数据歪斜, 导致未走适合的索引;Innodb buffer pool 命中率低, 触发大量物理读;优化器 bug, 导致未走最优索引宿主机磁盘异样。

1.4.2 性能抖动失常状况下数据库响应工夫比较稳定,然而数据库一些外部行为也会导致数据库偶然呈现性能抖动,比方对于 MySQL 来说刷脏(触发同步刷脏时尤为显著)。个别咱们评估一个实例是否失常,会依据 P999 分位的响应工夫来判断,当然还有其余的一些可能会导致性能抖动的起因,比方慢查问、批量操作、定时工作等。

1.4.3 压力过载压力过载个别会呈现在如下的一些场景:突发流量;上游缓存生效;大型流动中流量超过预期。

2、缓存

常见的缓存故障蕴含以下几种:缓存穿透、缓存击穿、缓存雪崩,上面开展具体说说。

2.1 缓存穿透

缓存穿透是指查问一个基本不存在的数据,缓存层和长久层都不会命中。在日常工作中出于容错的思考,如果从长久层查不到数据则不写入缓存层,缓存穿透将导致不存在的数据每次申请都要到长久层去查问,失去了缓存爱护后端长久的意义。造成缓存穿透的起因有两个。本身业务代码或者数据呈现问题(例如:set 和 get 的 key 不统一)。一些歹意攻打、爬虫等造成大量空命中。

2.2 缓存击穿

缓存击穿次要是是以下两种场景:以后 key 是一个热点 key(例如一个秒杀流动),并发量十分大。重建缓存不能在短时间实现,可能是一个简单计算,例如简单的 SQL、屡次 IO、多个依赖等。在缓存生效的霎时,有大量线程来重建缓存,造成后端负载加大,甚至可能会让利用解体。

2.3 缓存雪崩

缓存雪崩,个别是由大量的 key 集中在一段时间内生效,或者 redis 服务故障所引起的, 导致查问申请查不到缓存,大量的申请涌入数据库。缓存雪崩会导致以下两种结果:数据库霎时被大量的流量打死该服务接口拜访工夫过长,导致耗尽了线程资源,从而引起整个零碎的解体。

三、B 站在数据库故障治理方面做了啥?

下面讲述了常见的数据库故障,上面咱们来说说如何从数据库架构设计上来躲避故障,这里会联合 B 站的一些实际来跟大家分享。

1、高可用

高可用(High Availability)是零碎架构设计中必须思考的因素之一,它通常是指,通过设计缩小零碎不能提供服务的工夫。所以在做数据架构设计时肯定要思考 HA 能力,无论是选用集群模式(MGR、PXC 等),或是应用传统主从复制加上其余高可用组件(Orchestrator、MySQL Replication Manager、MHA 等),都能够帮咱们在实例不可用时把损失最小化。

2、扩容

扩容个别分为垂直扩容和程度扩容两种,对于传统 MySQL 来讲,垂直扩容的收益比通常不高,而基于其自身状态的程度扩容又很难做到疾速,所以如何做应急扩容始终是业内比拟头疼的问题。这时候引入云原生数据库是一个不错的抉择,业内的云原生数据库大都进行了存储计算拆散革新,对于计算层能够通过 k8s 的 HPA 能力进行疾速扩容,而存储层则依赖于底层共享存储或者分布式存储也有不同的扩容形式。

在 B 站咱们大量引入了 TiDB,在一些适宜弹性伸缩的场景下有不错的收益。

垂直扩容:增大 buffer pool、cpu 限度等配额,须要平台侧欠缺 Quota 治理和变更能力。程度扩容:对于 MySQL 来讲,应急疾速程度扩容只能用于读负载,咱们会有一些异地机房的实例,个别状况下用作灾备以及离线用处,在极其场景下能够通过平台操作一键接入读负载池;对于 TiDB 来讲,咱们把计算节点放入 k8s,通过 k8s 的 HPA 能力进行程度弹性伸缩。

3、多活建设

多活是高可用的升级版,个别分为异地灾备、同城多活、异地多活、两地三核心、三地五核心等不同的架构设计。(回顾传送门:B 站 SRE 负责人亲述 713 故障后的多活容灾建设)

异地灾备:当主机房的实例全副不可用时进行切换,个别是由高可用组件触发切换,高可用组件自身应该是一个分布式跨机房的架构。比方在 B 站, 咱们的高可用组件是三机房投票决策的,同时该当留神防止跨机房专线异样造成的误判以及误切换熔断策略。

同城双活:主库在同城某一个 zone,从库则散布在同城的不同 zone,每个 zone 的读申请实现单元内闭环,写申请则跨 zone 拜访对应的主库,须要在数据库 proxy 或者 sdk 层实现申请路由的主动感知和判断。

异地多活:依赖业务单元化革新,读写申请全副单元内闭环,要求整体架构具备单元流量调度以及异样流量改正的能力。属于同一个 global cluster 的集群间通过 DTS 进行双向数据同步,DTS 层须要解决数据回环问题以及冲突检测机制,对于数据抵触的场景提供不同的策略,比方笼罩策略、暂停同步策略等。对于抵触数据也能够思考写入音讯队列,便于业务侧改正解决,同时应具备全局发号器主键填充能力,防止双向同步的主键抵触。

两地三核心: 能够简略了解为同城多活加上异地灾备架构,其中灾备机房该当依据劫难接受水平和数据保护水平来衡量天文间隔。上述几种架构中,异地灾备和同城双活的读流量通过数据库接入层管控进行切流,比方 proxy、sdk 的元数据管理,写流量则以数据库高可用组件的切换作为切流伎俩;而异地多活架构下的切流计划个别是通过利用下层切换,比方 CDN、SLB、利用网关等实现。

 4、Proxy 数据库

代理数据库代理(又名 proxy)是位于数据库服务和应用服务之间的网络代理服务,用于代理应用服务拜访数据库时的所有申请。数据库代理个别蕴含以下外围性能:读写拆散拦挡限流熔断通过对 Proxy 的大量应用,咱们能够实现针对某个数据库、某个服务、某类 SQL 指纹进行拦挡,限流、熔断来阻止某些异样流量打崩数据的场景。

 

5、慢查问预警

慢查问是导致数据库性能降落中多数具备可预测性的内容,为此咱们专门建设了慢查问预警体系,这套体系蕴含日志采集、流式解决、后果剖析、告警及其他操作(如:自愈等)。慢查问预警系统的采集样本是过来 7 天同时间段前后十分钟,和当天前 10 分钟数据,通过屡次线性回归,咱们实现了对偶发性的抖动的过滤,不同业务级别环比倍数、持续性增长(未到阈值倍数,但持续增长或存在)慢查问的预警,并且基于规定引擎实现自定义解决。

 6、一个具体的小案例分享

上面分享一个针对复制 bug 的处理过程。
问题背景:业务研发收到多起创立预约的问题反馈,如:创立预约后拉取不到预约详情查问从库未读取到相干数据

外围解决步骤:DBA 先查看从库复制状态,未发现复制异样;应用 show global variables like ‘%gtid%’ 查看 gtid,发现 gtid_binlog_pos 不发生变化,故判断可能是 mariadb 多线程复制 bug 导致数据不同步;与业务研发共事沟通后,通过批改 proxy 配置将所有流量切换到主库,同时切换 canal 到主库,最终因复制 bug 导致的业务影响很快被管制下来。

后续优化:减少心跳表以躲避复制 bug 导致的惯例复制监控不可用。基于高可用、心跳表、数据库负载(QPS、CPU、网络等)等信息,实现在从库异常情况下将流量切换到主库和数据订阅的数据源切换到主库。

阐明:触发该复制 bug 后,应用 show slave status 看不到复制状态的任何异样,下图是过后的监控:

四、数据库故障演练应该怎么做?

故障演练是一种遵循混沌工程试验原理的解决方案,提供丰盛的故障场景模仿(如宕机、CPU 负载过高、网络提早、丢包、磁盘写满、I/ O 飙高、OOM)等,可能帮忙分布式系统晋升容错性和可恢复性。故障演练须要建设一套规范的演练流程,蕴含筹备阶段、执行阶段、查看阶段和复原阶段。

数据库作为根底软件,其本身的故障演练不能独立于利用场景,而是作为利用零碎演练的一部分存在。上面分享下一个故障演练的案例。B 站很多业务的数据库是 Gzone 架构,保障单机房的数据库、缓存是否能够承载业务的全副流量是 Gzone 架构的外围要求。下图是模仿单机房故障演练的架构图:

此次演练是模仿在同城一个 IDC(B 机房)因某种不可抗力的状况下,通过 CDN 将流量切换到 A 机房,验证单机房中利用、缓存、数据库是否能够承载全副流量,呈现非预期内的状况下现有预案是否能够笼罩相干场景、相干关联系统的可用性等。最终咱们通过模仿 check 了数据库切流的成果以及相干预案的覆盖度、有效性,为零碎的稳定性减少了一份保障。因为故障演练这块的内容比拟多,下次咱们再开一篇来说说故障演练的流程与实操。(如果你对 B 站「故障演练」感兴趣,后盾回复“0922”订阅相干内容)

五、总结与瞻望

万物流变,无物常驻。博尔赫斯 · 赫拉克利说过:没有人能两次踏进同一条河流,故障也是相似的,每次故障产生的工夫、地点、起因、影响范畴、解决的人都不同。若从这个角度来看故障治理,它是在解决过来某一个时刻的问题,那为什么还要做故障治理呢?

简略来说,故障治理的目标就是通过技术手段提前躲避相似的故障问题,不让零碎在同一个中央跌倒两次,而且大量的实际也证实了这些做法的有效性。将来 B 站在数据库故障治理方面也会继续发力,咱们将继续关注数据库故障标准化、演练常态化。通过常态化的演练更早发现和裸露问题,不断丰富的故障场景,能够做到最小粒度定义故障、发现故障和解决故障。

公众号回复【0922】订阅故障演练内容
回复【交换】进入读者交换群
回复【7161】获取「B 站多活容灾建设」材料

申明:本文由公众号「TakinTalks 稳定性社区」联结社区专家独特原创撰写,如需转载,请后盾回复“转载”取得受权。

正文完
 0