TakinTalks大咖说| 大型活动数据库应急预案怎么做?B站专家这样说……

“所有的应急预案都应该围绕着公司自身的基建来设计,否则一切都只是空谈。现实中, 大型活动持续的时间一般不会很长, 但是流量非常高,一场赛事直播可能会在2-3个小时,一次电商大促、秒杀活动可能在 1 个小时甚至 10 分钟以内,所以大型活动中的应急预案一定是止损优先,以快、稳、准作为设计目标。”——陈阳

数据库作为存放数据信息的仓库,它的重要性不言而喻,数据库的应急预案自然是大家关心的重点,我们特地邀请了TakinTalks社区专家陈阳老师来分享他的预案制定经验。

TakinTalks大咖说| 大型活动数据库应急预案怎么做?B站专家这样说......

上次在Takintalks直播的分享中,大家对于B站是如何针对大型活动保障制作数据库应急预案好像挺感兴趣的,那今天就来跟大家具体聊聊数据库保障应急预案设计。

可靠性是 MTTF(平均失败时间) 和 MTTR(平均恢复时间) 的函数,评价一个团队将系统恢复到正常情况的有效指标就是 MTTR。 应急预案的意义是当系统发生突发故障时,能指导我们及时做出最有效的响应和处理,最大限度地争取时间减少损失。

常见的数据库问题

首先,我们先来看看数据库通常会出现哪些问题:

TakinTalks大咖说| 大型活动数据库应急预案怎么做?B站专家这样说......
TakinTalks大咖说| 大型活动数据库应急预案怎么做?B站专家这样说......


1.数据库宕机

没有数据库能保证 100% 不会宕机,所以在做数据架构设计时一定要考虑HA 能力,无论是选用集群模式(MGR、PXC 等),或是使用传统主从复制加上其他高可用组件(Orchestrator、MySQL Replication Manager、MHA等),都可以帮我们在宕机时把损失最小化。常见的宕机原因一般有:

  • 宿主机硬件故障: 硬件故障是真实场景中不可避免的问题;
  • 实例Crash: 一些数据库 Bug 或者物理文件被损坏也会导致数据库发生Crash;
  • 实例被 OOM Kill: 一般情况下, 基于 Innodb buffer pool 我们不会超分并且会留一定的内存 buffer,但是对于线程级别的私有变量最大内存总和可能会超分,通过不同系统之间的水位潮汐来提高服务器资源利用率, 这种场景下我们需要做好容量管理,不然控制不好则会触发 OOM;
  • 分布式数据库超过半数副本、节点异常。

2.主从延迟

主从复制是线上经常出现的问题之一,对于读写分离的业务来说,从库延迟的影响可能是致命的。一般有这些原因会导致主从延迟: 

  • 主库执行了一个非常大的数据变更事务;
  • 主库变更频率过快, 导致从库跟不上;
  • 使用原生的表结构变更语句进行大表的DDL ;
  • 从库配置参数较低、硬件性能较差;
  • 从库负载过高,导致性能变差 ;
  • 从库MDL 锁 ;
  • 主从之间网络问题 ;
  • 主从复制Bug (多线程复制 bug 最为常见)。

3.慢查询增多

慢查询也是我们经常会遇到的场景,严重情况下会导致数据库雪崩, 一般导致慢查询增多有如下原因:

  • 新业务上线 SQL 效率较差或者没有合适的索引;
  • 业务场景发生改变, 边缘场景被触发;
  • 数据倾斜, 导致未走合适的索引;
  • Innodb buffer pool 命中率低, 触发大量物理读;
  • 优化器 bug, 导致未走最优索引宿主机磁盘异常。

4.压力过载

压力过载一般会出现在如下的一些场景:

  • 突发流量;
  • 上游缓存失效;
  • 大型活动中流量超过预期。

5.性能抖动

正常情况下数据库响应时间比较稳定,但是数据库一些内部行为也会导致数据库偶尔出现性能抖动,比如对于 MySQL 来说刷脏(触发同步刷脏时尤为明显),对于分布式数据库来说Compaction、GC、热点 Region 都可能会导致性能出现抖动。 一般我们评估一个实例是否正常,会根据 P999 分位的响应时间来判断, 当然还有其他的一些可能会导致性能抖动的原因, 比如慢查询、批量操作、定时任务等。

6.数据丢失

数据丢失是研发或者 DBA 的噩梦,一般如下的场景可能导致数据发生丢失:

  • 未开启双一参数,在宕机场景下丢失;
  • 未使用半同步复制,在宕机场景下丢失;
  • 使用三方工具进行DDL的某些特殊场景下可能会丢, 比如pt-osc、gh-ost;
  • 误操作、误删除数据蓄意删除,也就是常说的运维人员删库跑路。

对于前面几种问题, 都可以通过参数配置、架构设计、流程规范来避免: 发生误删除一般都可以通过binlog 反解析或者备份恢复等手段找回数据;核心数据库可以考虑搭建延迟从库便于快速恢复;对于删库跑路的预防一定要做好严格的权限分离,比如数据库和备份的变更权限一定要由不同的团队、人员分别保存,以及危险命令的拦截能力和审批机制。那接下来我们就来说说数据层的设计思路。

数据层可靠性设计思路


1.扩容

扩容一般分为垂直扩容和水平扩容两种,对于传统MySQL来讲,垂直扩容的收益比通常不高, 而基于其本身状态的水平扩容又很难做到快速,所以如何做应急扩容一直是业内比较头疼的问题。这时候引入云原生数据库是一个不错的选择,业内的云原生数据库大都进行了存储计算分离改造,对于计算层可以通过 k8s 的HPA能力进行快速扩容,而存储层则依赖于底层共享存储或者分布式存储也有不同的扩容方式。在 B 站我们大量引入了 TiDB, 在一些适合弹性伸缩的场景下有不错的收益。

  • 垂直扩容:增大 buffer pool、 cpu 限制等配额,需要平台侧完善 Quota 管理和变更能力。
  • 水平扩容:对于MySQL来讲, 应急快速水平扩容只能用于读负载,我们会有一些异地机房的实例,一般情况下用作灾备以及离线用途, 在极端场景下可以通过平台操作一键接入读负载池;对于 TiDB 来讲,我们把计算节点放入 k8s,通过k8s 的HPA能力进行水平弹性伸缩。

扩展阅读: 这里推荐几篇分布式/云原生数据库相关的paper, 强烈建议大家阅读一下:

  • PolarFS: 《An Ultra-low Latency and Failure Resilient Distributed File System for Shared Storage Cloud Database》
  • Amazon Aurora: 《Design Considerations for High Throughput Cloud-Native Relational Databases》
  • TiDB: 《A Raft-based HTAP Database》

2.拦截

在数据层应该具备流量拦截的能力,这样当上层流量拦截失效时可以进行自保。 一般的设计思路有代理层拦截和 sdk 层拦截,我们大量使用了代理层拦截的设计,应用通过代理层接入数据库,在数据库管控平台可以针对某个数据库、某个服务、某类 SQL 指纹进行拦截。

这种手段可以有效阻止某些异常流量打崩数据库的场景, 比如:性能较差的语句,某个接口被爬、异常调用, 再或者上游缓存击穿后大量回源的高频请求。


3.切流

切流的前提是多副本以及多机房的建设,一般分为异地灾备、同城多活、异地多活、两地三中心、三地五中心等不同的架构设计。

  • 异地灾备:当主机房的实例全部不可用时进行切换,一般是由高可用组件触发切换,高可用组件本身应该是一个分布式跨机房的架构。比如在B 站, 我们的高可用组件是三机房投票决策的,同时应当注意避免跨机房专线异常造成的误判以及误切换熔断策略。
  • 同城双活:主库在同城某一个 zone,从库则分布在同城的不同 zone,每个 zone 的读请求实现单元内闭环,写请求则跨 zone 访问对应的主库,需要在数据库proxy 或者sdk层实现请求路由的自动感知和判断。
  • 异地多活:依赖业务单元化改造,读写请求全部单元内闭环,要求整体架构具备单元流量调度以及异常流量矫正的能力。属于同一个 global cluster 的集群间通过 DTS 进行双向数据同步,DTS 层需要解决数据回环问题以及冲突检测机制,对于数据冲突的场景提供不同的策略,比如覆盖策略、暂停同步策略等。对于冲突数据也可以考虑写入消息队列,便于业务侧矫正处理,同时应具备全局发号器主键填充能力,避免双向同步的主键冲突。
  • 两地三中心: 可以简单理解为同城多活加上异地灾备架构,其中灾备机房应当根据灾难承受程度和数据保护程度来权衡地理距离。

上述几种架构中, 异地灾备和同城双活的读流量通过数据库接入层管控进行切流,比如 proxy、sdk的元数据管理,写流量则以数据库高可用组件的切换作为切流手段;而异地多活架构下的切流方案一般是通过应用上层切换,比如 CDN、SLB、应用网关等实现。

TakinTalks大咖说| 大型活动数据库应急预案怎么做?B站专家这样说......

4.限流

限流也是数据层应该具备的应急能力之一。通常思路有sdk 层限流、代理层限流、内核层限流,其实现方法也各有不同。常用的限流算法有滑动窗口算法、漏斗算法、令牌桶算法等,对于数据库来说,在水位线控制合理的情况下,一般推荐令牌桶算法,这样对于瞬间的峰值流量有比较好的处理能力。

值得注意的一点是:对于 sdk 层限流或者 sidecar 模式的代理层限流设计,一般需要考虑全局的分布式限流能力,否则随着上游应用横向扩容, 对数据库的压力仍然有过载的风险。


5.熔断

熔断一般会考虑在 sdk 层或者 proxy 层来设计,既可以保护应用层自身不会被下游的数据库性能异常拖垮,又能防止数据库被上游持续的异常请求打至雪崩。

断路器的几种状态:

a.关闭

b.打开

c.半打开

TakinTalks大咖说| 大型活动数据库应急预案怎么做?B站专家这样说......

6.重试

为了提高服务的健壮性,一般会建议应用侧具备请求重试机制,但是需要注意几个点,避免因为重试管理不当而导致更严重的问题:

  • 写请求重试应当考虑幂等性
  • 重试应该有最大次数限制
  • 多级链路调用应当注意总重试次数管理,比如一个 3 层依赖调用链路,假设每层都重试3 次的话,理论上到达数据库的总重试的次数可能最大是27 次。

大型活动应急预案

接下来我们来看看怎么去设计一套数据库应急预案。首先,所有的应急预案都应该围绕着公司自身的基建来设计,否则一切都只是空谈。

现实中大型活动持续的时间一般不会很长,但是流量非常高,一场赛事直播可能会在2-3个小时,一次电商大促、秒杀活动可能在 1 个小时甚至 10 分钟以内,所以大型活动中的应急预案一定是止损优先,以快、稳、准作为设计目标。

1.应急预案5要素

一个完整的应急预案设计应该包含:适用场景、触发条件、执行人员、操作影响、执行步骤这五个要素, 同时需要注意以下几点:

  • 场景之间的界限定义要清晰;
  • 启动条件必须有明确的判断阈值,比如: 主从延迟超过 60s,持续 1 分钟;
  • 应急预案大都会有一定程度的业务感知,需要明确操作影响, 包括正面和负面影响;
  • 执行步骤最简化, 建议封装成工具或者平台,让操作者能一键执行;
  • 具备启动前置的判断机制,防止被误触发;
  • 大型活动前必须要重新 Review应急预案,随着我们基础架构的不断升级迭代,上次的应急预案可能已经不再合适,必须及时更新。

2.应急预案通用设计思路

基于上述快、稳、准的设计目标,我们把 B 站具有业内通用性的一些数据库应急预案设计思路列出来,以供参考:

  •  宕机: 高可用组件会自动进行failover,一般时间在 30s 之内,收到宕机切换的告警之后,需要人工检查一下高可用的切换是否符合预期,以及对应的流量是否都已经自动转移到对应实例。如果出现failover未能生效的场景,DBA 通过平台的应急切换功能进行人工切换,单个实例的操作生效期一般在 1分钟左右。
  •   慢查询突增:
  1. 被动: 对于配置了熔断机制的应用,如果窗口周期内超时的请求量符合熔断条件,会被自动熔断;
  2. 主动: DBA 会先把对应的慢查询语句加入黑名单,这样会从 proxy 层拦截掉相同指纹的 SQL 语句,防止影响整个实例的性能导致问题进一步恶化,操作的生效期为 10s 以内。
  •  性能过载:DBA 进行初步判断,如果满足快速扩容条件,则把负载不高的其他机房从库调度到读负载池,操作生效期为 10s 以内;如果不满足快速扩容条件,则启动限流方案。
  •   主从延迟:
  1. 被动:会触发自愈降级服务,对从库的刷盘参数进行双 1 降级,牺牲极端情况下数据一致性来提高性能,等延迟追上后自动复原;
  2. 主动:DBA 从平台上进行实例级别的切流到未延迟的从库上.。
  •   数据误删除: 如果有延迟从库,优先从延迟从库恢复数据;如果没有,对误删除的量级进行判断,小数据量优先使用binlog 反解析,大数据量使用备份进行恢复到指定时间点;如果是 TiDB,优先使用闪回查询进行数据恢复。

3.一个典型的应急处理case

下面我们来看一个典型的慢查询应急处理过程:

问题背景:某个线上接口(调用 SQL 复杂)缓存在边缘场景失效,导致大量的慢查询持续回源数据库,造成从库过载进而影响了其他所有依赖该数据库的服务。

核心过程:DBA先执行快速扩容预案,发现不能完全解决问题,与研发沟通后, 继续执行 SQL 拦截预案,最终故障整体影响面被比较快速地控制下来。

特别注意:通常情况下,业务研发修改代码再灰度验证所需要的周期比较长,DBA 应该利用现有的平台以及服务管控能力,判断最优止损的决策并执行,帮助业务一步步减少业务影响面直至完全恢复。

TakinTalks大咖说| 大型活动数据库应急预案怎么做?B站专家这样说......

总结

数据库应急预案触发的场景是系统出现了突发的异常,这便要求运维人员平时熟练掌握这些流程,定期进行预演。而且不同维度的演练也能帮我们去发现预案本身在边缘场景的设计缺陷,避免关键时刻不能生效的情况。
最后,数据库应急预案和公司内部的基建设强相关,在不断迭代提高底层基础架构的健壮性的基础上才能有更灵活、更平滑的应急预案供我们选择。所以别人的最佳实践不一定就是最适合我们的,通往罗马的路有很多条,找到当前适合自己的最优解才是关键。

— — — — — — — — — — — — —

预案做了,没有办法验证?全链路压测帮你快速验证预案的有效性!

《开源Takin使用训练营》免费学习压测方法,免费使用压测工具。

本文来自投稿,不代表TakinTalks稳定性技术交流平台立场,如若转载,请联系原作者。

(0)
上一篇 2022年6月27日 下午3:38
下一篇 2022年7月14日 下午2:11

相关推荐

发表评论

邮箱地址不会被公开。