用户故事 | 工商银行核心应用 MySQL 治理实践

摘要
本文根据 2020 年 DTCC 数据库大会分享内容整理而成。工商银行在 2014 年就开始推广使用 MySQL。时至今日,生产环境的 MySQL 节点数量已经发展到近万个;应用场景也从外围低等级应用,推广到核心高等级应用。此次与大家分享,为承接核心业务数据存储的重担,工商银行在 MySQL 应用治理方面的思路和方案

演讲者介绍:林镇熙,工商银行小兵一枚,2014 年开始接触 MySQL,将 MySQL 5.5、5.7 版本引入工行。负责 MySQL 架构设计,开发规范,以及相关技术培训工作。

工商银行在核心应用 MySQL 的治理,主要分为三个方面:目前面临的情况和挑战、为了解决这些问题的思路和具体的方案,最后是后续提升的思路。 

一、 现状与挑战

1.1、现状

这是行内 MySQL 的部署节点数发展情况,从 2019 年 6 月开始到现在,在短短的两年期间,MySQL 节点规模上涨得非常厉害,翻了几番。绿色部分是目前这些节点当中的核心应用节点数的情况。核心应用占的比例其实是比较大的,有两个方面的因素:一方面是行内在数据库使用的策略上,对于新增的数据库节点,如果没有特别要求的话都会使用 MySQL 数据库;另一方面是与行业内业务发展情况相关,行内对于高容量、高并发、弹性扩展的业务需求非常旺盛,这种情况下对于分布式架构的数据库要求越来越多,所以对于分布式内容的应用规模也会比较庞大。行内将应用分为 ABCD 四个等级,最高等级为 A 类应用,核心应用就是指最高等级的 A 类应用。

1.2、面对的挑战

行内对高容量、高并发、弹性扩展的业务需求比较多。目前基本完成了分布式体系的建设,满足业务的需求,MySQL 也是分布式数据库体系的一部分,除了数据库之外也实现了分布式服务、软负载、分布式事务、分布式消息、批量、缓存、对象存储、文件存储,加上数据库等,共有九大运行支撑平台。通过这些平台的组合,形成了完整的分布式解决方案,满足业务的要求。

关于运维方面的压力,现在 MySQL 节点数量非常庞大,对于生产运维来说,为了能够支撑这么大的体量,运维的压力非常大,包括监控告警、故障恢复等。如果没有借助自动化、智能化的手段是很难满足运维的要求。这里我们是与第三方公司一起合作研发 MySQL 的管理平台,具体的是爱可生公司。我们也经历了很长的一段合作时间,能够把这套东西打磨出来,基本覆盖了完整的运维流程,特别是对故障的诊断和自动化的切换,效果也是非常好的。在这么多节点的大基数情况下,发生故障的总体概率会相对较高,但都可以很好地应对,在故障时迅速切换,基本不会对业务造成影响。

现在这么大的体量,如果按照传统物理机的部署模式,资源浪费会比较大,特别是在 CPU 方面。因为 MySQL 正常使用的话,CPU 资源一般都会比较低。这个问题行内看得比较远,资源规划方面已经实现了 90% 的容器化部署,目前大部分 MySQL 已经运行在容器上面,效果也非常明显,使用率能够提升 4-5 倍的程度。

本次我想重点介绍的内容是,现在核心应用接入到 MySQL,怎样才能保证生产运行的过程中,降低问题的数量和影响的程度?可以分为几个方面来讲:事前,我们希望能够在研发阶段尽快发现一些问题;事中,降低问题的影响;事后,希望快速定位到问题,迅速地予以解决。

二、 治理思路与方案

这些就是对治理思路的总结。首先是基础规范的管理工作。对于我们所需要做的工作,所有要求都是应该落在规范上面,希望做到有理有据,对于后面问题的定位和责任的划分都会非常有帮助。在此基础上,我们进行三个方面的治理工作,包括事前、事中和事后。

2.1、规范起到的三个作用

首先规范能够制定操作的标准,例如建表的时候该怎样,每张表必须要有主键,建库建表甚至设计字段的时候不允许在 SQL 当中添加字符集和排序规则的属性,默认实例的属性就可以。

其次规范可做量化的控制,有时要求一条 SQL 扫描的数量与返回的数量都不能太多,执行时间不能太长等等,从定性角度看问题都不大,但要落到实处,这样的要求是不够的,因此需要提供量化的指标。比如对慢 SQL,要求联机交易扫描的行数和结果集行数比不能超过 100:1。对于一个事务,更新的数量不能超过 10 万条。指标在开始设计时可能并不完美,但在使用的过程中不断研究、完善,就能够定出来更细化的指标。对于开发或是运维,都要对这些程序的设计和运行有一个底线的意识,一定不能越过这条线。

再是为了避开一些 Bug。一个例子是,大表的 Truncate 会导致数据库 hang 住,昨天农行的同事也有讲到,大家遇到的问题基本都是一样的。另外一个例子是 Replace into 的 Bug,会导致主备的元数据信息不一致,如果发生切换,新的主库插入数据的时候会出现主键冲突,这个问题相对比较大。为避免此类问题,规范上会要求不允许使用。

2.2、具体规范内容有两个特点,供大家参考

规范应该是容易被理解的,所以在规范中特意针对每一个条款增加了一个解读的内容。虽然规范提出了一些要求,但在具体落实时还会有很多人并不知道为什么会有这样的要求。所以在文档当中增加了很多解释,可以让读者很清晰地知道,除了不能这么做之外,还能知道为什么不能这么做。

对于规范当中的内容,会尽量安排落地,例如事前的治理方面,涉及到表结构和代码的审核系统,都是基于规范的内容安排具体的落地。所以规范才会真正变成非常有效的工具,不会是一纸空文。

2.3、我们三个主要工作,事前预防,事中应急,事后诊断

首先是事前预防工作

表结构的审核,是规范要求的落地实现,包括每个表必须建立主键,禁止单独设立字符排序规则,或者使用 TimeStamp 的数据类型等。行内目前的表结构审核系统,除了进行审核之外还负责进行版本控制,主要有两种情况:对于新增表,建表的语句是由审核系统生成的,不需要人工来写代码,可以减少很多不必要的错误。这一点我也是深有体会。之前看到不少同事的表结构是从一个地方拷贝过来,有些属性不是很理解,特别是表的属性中存在存储引擎的属性、排序规则的属性,不知道的话就自己带进来了,里面的要求可能都不是我们想要的。现在我们都是统一使用 InnoDB 引擎,要是不小心的话就会把 MyISAM 的表带入进来,所以隐患还是比较大的。表结构变更,例如加一个字段或加一个索引,这也是由表结构审核系统生成,不需要人工实现。

代码审核方面,我们在 MySQL 审核基本上都是基于 MyBatis 的开发方式,包括配置文件的扫描和实现,下面举的例子就是代码审核的要点。现在也是在持续地补充和完善。

健康检查方面,可以举个例子,是关于慢 SQL。这也是大部分公司在 MySQL 遇到最多的一类问题。我们利用 MySQL 中的一张视图进行分析,作为检查的一个依据。这张视图中记录了每一条 SQL 从 MySQL 开机到现在运行的计数器,比如截止到目前运行的次数,花费的时间,扫描记录的条数。我们利用这张表的计数器的特点,在两个时间点采集相同的表的数据,并且将两个时间点的数据进行比较,可得到这段时间内这些 SQL 运行的指标。对于相同的语句在八点钟采集一次,在九点钟采集一次,之后两个数据相减就知道 SQL 在八点钟到九点钟一共执行 100 次,执行时间是 900 秒,扫描记录数是 9000 万。从这个数字来看,有些比较敏感的同事,会发现单条记录的执行时间应该是偏长的,并且单条记录扫描的记录数也明显偏多。那么这条 SQL 就有一个明显的效率问题,需要进行整改。大部分问题都是可以通过增加索引来解决。

事中应急

事中主要考虑应急,并且是自动化应急。接触过生产的同事对应急应该是深有感触,要遇到一个问题之后开始分析、定位问题,最后采取措施,中间这段时间可能是相对不可控的,有时很快能够处理,但也有需要几十分钟甚至几个小时才能处理完毕,这时已经对业务造成了非常大的影响。因此我们更多的要考虑,怎样实现这种自动化的应急手段。

关于监控查杀,我们希望能够通过监控实时地捕捉到性能上的问题,进行自动查杀的操作,也就是把对应的线程杀掉,避免问题的进一步扩大。刚才多次提到的慢 SQL,是我们面临的最大敌人,主要包括两个方面的危害:很多时候,有大量的数据扫描,导致吃 CPU 资源。在大并发情况下,一条 SQL 可以吃掉一个 CPU,几十个 SQL 就能够把服务器的 CPU 吃光,问题的影响也是非常大。SQL执行慢,并且有多个线程堆积的情况下,可以把 InnoDB 的线程池耗尽。在这种情况下,原来一些没有问题的 SQL,在执行的时候就会明显被拖慢,导致整个系统交易全部受到影响。所以就不仅仅是慢 SQL 的交易,整个系统的交易都会存在问题,影响很大。

我们对此已经实现联机交易的自动查杀功能,通过设置一个阈值,对于超过这个阈值的 SQL 自动杀掉。具体原理比较简单,通过类似 ProcessList 得到时间点和线程 ID,然后去查杀。在这里有个特别要注意的地方,为了实现这些,我们做了联机和批量用户分离操作,针对不同用户进行差异性处理。主要是因为联机和批量的特性不一样,批量的 SQL 有时会要做大批量的处理,时间是会比较长,这是很正常的。联机基本上是短平快的操作,大部分都是毫秒级的,稍微慢一点的可能是几秒钟,但十几秒、几十秒的话就是不正常了。所以是在用户分离的前提下再进一步做慢 SQL 的查杀。

关于大事务,我们的定义是在一个事务当中增删改的记录数超过一定的阈值。目前定义的阈值是 10 万条记录,超过 10 万条就定义为一个大事务。具体危害性可以从这张图进行介绍。每笔交易都会经历一个记录 binlog 再从备库返回的过程,这是 MySQL 半同步最基本的操作。如果记录的内容比较大,那么具体的量也随之非常大,不管是写入、传输还是落地方面时间都会有明显差异。目前我们觉得最大的问题在于,MySQL 主库写入 binlog 的处理都是单线程的,如果有一个交易写入,其它交易都是排队的状态。如果出现大事务的话,其它交易就会被卡住。

在主库出现堵塞的情况下,高可用的机制可以探测到主库长时间不可用,我们就会去做主备的切换。但是在大事务的情况下,切还是不切是比较大的问题。大事务的写入、传输和回放需要经历一个比较漫长的阶段,如果马上用备库的话,数据就已经不是最新的,也就是会丢掉一些数据;如果我们等待回放,做完以后再切,可能时间就不可接受了。所以这是一个两难的问题,我们要尽量避免大事务。

为了做到严格的控制,我们也对大事务实现了自动查杀,对于超过一定的阈值自动执行和操作。

自动查杀也不是立即能够实施,需要经历不断的小范围的试点,先做监控报警,再做自动查杀,这样一步一步走下来。

有候我们开玩笑,谈到删库跑路,例如遇到程序 Bug 有些数据会被误删,或者更新成其它我们不需要的数据,这时候就需要进行数据恢复。常规的办法是存量备份和增量 BinLog 进行追补。可追补的过程中是单线程的,基本上很难实施,因为存量备份都是每周一次,要是恢复的数据是五六天之前,追补的数据范围会非常大。我们采用两种方案:伪装成 Slave 进行回放,网上已经有现成的案例;为了更快地进行恢复,我们借鉴了一些业界恢复工具,主要包括两类,一类是 DML,比如 Delete 转化为 Insert,另一类是基于文件系统工具进行恢复。

最后是事后诊断

最重要还是数据的采集能够完整到位,对事后诊断才是有帮助的。除了常规的数据采集,针对 MySQL,还有些高密度和低密度的采集。高密度是针对后台线程情况的采集,是为了解决一些瞬间的性能波动,有时只是一两分钟或者更短的十几秒、几十秒的波动,通过高密度的采集能够作为事后分析的依据。低密度是刚才提到的慢 SQL 的性能数据,目前是十五分钟采集一次。SQL 的历史执行情况对问题分析也十分有帮助,也是十五分钟采集一次。

三、 后续提升思路

3.1、首先是问题的定位,有两方面

在问题发生之前,怎样在研发测试环境,甚至生长环境能够提前捕捉到;问题发生的时候怎样能够迅速地定位到问题,迅速采取一些措施解决。前面有提到检查和自动化的处理,但还是远远不够,还是有很多的提升空间。

3.2、其次是问题的预判

根据一些性能数据,包括性能指标和 SQL 的执行情况、发展曲线提前进行预判。比如有些表刚开始的数据量不是很大,即使有些 SQL 效率不高,执行的情况还是可以接受的。但随着数据量的增长,执行时间和扫描数据量都在不断攀升,在达到一个临界值影响到具体业务之前,我们希望能够找到它,并且尽快修正过来。

3.3、最后是关于问题的自愈

现在希望借助于智能自动化的手段,能够在出现问题的时候自动地做修复,避免这些问题进一步扩大。例如,有些程序写得不够好,就会出现全表扫描的情况,如果是在出现问题后再去定位添加索引,时效性会比较慢。希望我们的程序能够自动发现这个问题,然后加上一个索引,可以让这个业务基本上不受到影响。

以上就是我的分享主题,可能讲得也不是很深,都是比较浅的东西,希望大家能够多多指正。

嘉宾互动环节
嘉宾:工行的核心系统是开源自己搭建的还是商用的产品?
林镇熙:我们是用 MySQL 社区的开源版本,5.7,我们是一主多从、两地三中心的架构。

嘉宾:你们是容器化部署还是物理机部署?
林镇熙:我们 90% 以上都是容器化部署,就是使用 K8S 架构解决方案,存储是使用本地 SSD。

嘉宾:工行使用 MHA 架构吗?
林镇熙:我们刚开始也有考虑,分析下来 MHA 有一定的缺陷,所以我们是跟第三方公司一起合作研发一整套的运维平台,去实现故障的判断、定位和切换。

嘉宾:相当于工行自己研发了另外一套高可用系统是吗?
林镇熙:是的。

嘉宾:工行还有 10% 的 MySQL 跑在物理机上面是吗?
林镇熙:是的。

嘉宾:工行容器化单机可以跑到多少实例数?
林镇熙:1 个主机是 4 个以上的容器,现在上线的是 4-8 个左右。

嘉宾:本地 SSD 还是共享存储?
林镇熙:本地 SSD。

关于爱可生

上海爱可生信息技术股份有限公司是国内开源数据库解决方案领导者、工业互联网高维数据应用创新者。爱可生为产业互联网创新应用提供高性价比、快速落地实现的多数据库管理平台、分布式数据库系统、数据库容器云平台、多地多中心跨云容灾等解决方案。

在工业互联网相关垂直行业,深入分析数据价值,构建数据中台和业务中台的基础软件 PaaS 平台,用数据技术驱动企业高质量增长。公司产品已被广泛应用于各行业,累计用户超过 400 家,其中包括工商银行、中国人寿、中国太保、国家电网、上汽集团、中国移动、华为等 30 多家世界 500 强企业。

你可能感兴趣的:(mysql)