DS 是关系型数据库服务。有赞为什么重新打造 RDS 东西?这要从四个角度去分析:背景、问题、发展、实现。
有赞四个发展阶段的问题
首先,背景来说的话有赞是一家创业公司,它从 0 到 50 人团队的时候,业务相对而言还是比较单一的。这个时候的业务发展没有那么快。而到了 50-200 人阶段的时候,业务线非常的多,比如说微小店、微商城,再比如说分销的业务,这些业务线起来之后,流量是慢慢的缓增到 200-300 人阶段的时候,大量工程师在快速的涌入公司,并且设计量这个时候也在增长。到 300 人的时候不仅仅是流量的缓增,而且这个时候流量也满满地增长,这个是比较重要的。
这样四个阶段的背景下面产生什么样的问题呢?
在 0-50 人的时候,人员相对比较能 Hold 住 MySQL。
50-200 人阶段对数据库压力是比较大的,所以产生了读写分离的需求,因为单机 MySQL 压力是蛮高的。
而到 200-300 人不仅仅是流量的增加,而且是数据量的增加。对单一的垂直业务线而言本身数据量在 MySQL 是 Hold 不住的。
等到 300 人 + 的时候全部业务线全面开花,包括业务人员,开发人员很多 DDL 产生,流程会变得很重,这都是很典型的创业公司的问题。
技术栈的发展针对这些问题我们跟互联网公司差不多是一样的,首先它的发展而言对 MySQL 而言是单接使用率,然后到很典型使用应用程序,主动的去读或者是写 Master。
到第三阶段读写分离,这里有一个背景是说我们的业务是基于 PSP 原始线。所以当流量上来的时候,在 MySQL 中间一层加像 360 的一个开源组件 Altas。后面一个阶段,引入阿里巴巴的一个开源的带 Sharding 功能的方案 Cobar。
介绍一下这两个组件的区别和方案的对比。
360 开源组件 Altas 满足了读写分离的需求,但是在电商领域或者更严格要求 ACID 的金融领域来说的话事务性要求很高的,这点是短板;不过它做了更好的运维上面的上线、下线 MySQL 的控制。而阿里巴巴的开源组件 Cobar 是简单的对 MySQL 做一些 Sharding。这两个架构本身而言对有赞来说的话是经历了比较长的一个时间,直到我后来加入之后,我把这些问题梳理了一下,这些问题主要会产生线上的故障非常多,即便是引入了 360 或者阿里巴巴的架构实现来说的话还是有很多的问题。所以我们进行了改造,变成了 RDS-Proxy。
重塑,剖析 RDS-Proxy本身 RDS 不是一开始就有的。这个是 Proxy 的一个雏形,为了去掉 RDS 和 kober,我们在 kober 上进行了改造,所以 Proxy 是一个中间基层,所以上下协议都是通过 MySQL 协议来访问的。
在 Proxy 上我们增加了很多的功能,比如读写分离,还增加了 MySQL 的权重,原先是没有的。而 ConnPool 也做了大量改造,主要是增强了它的连接数的复用性。原来 Kober 和那个的连接池用的是 IP+Pool 再加 MySQL 数据库的 Sgam。而我们改造后是共同承载非常多的 Sharding。这个 BIO 和 NIO 是比较大的改造,本身这个是非常重要的一点,无论是哪个方案,对于 MySQL 而言,它的 IO 是同步的协议在 IO 上很消耗性能。所以我们加前端的连接和后端的连接改成 NIO。这样的话就可以释放出 Proxy 上大量的内存。这个改造后我们就大量的提升了线上的性能,包括 Plos 的性能。
除了性能的改造之外我们还做了一些类似 FastFailed 的机制,对于 RDS-Proxy 改造后我们形成了这样的功能,就是前面所说的几点,ShardingFuction 增强,很重要的一点是 BIO 改造成了 NIO,无论是前置的连接和后置的连接都进行了改造,而 FastFailed 是增加了垄断的机制。通过这些改造后大家会不会有疑问,说增加了这么多功能它的性能会下降,其实不然。实际上我们通过改造代码量增加了,但是性能是提高了非常多的。首先我们在这样的测试场景下面,我们的背景使在 E5-2630 24CPU 上,千兆网卡打满了,Proxy 本身会气动 8×24 线程。而实际测的数据如屏幕上显示的,较以前的性能来说有 30% 的提高,140K QPS。
做了这么多性能对于稳定性有什么样的效果呢?我们由原来一个季度里会有 1-3 次的故障,而且是全站故障,改造后变成了 0 个。我们现在目前改造之后是没有全站故障的,因为 MySQL 的访问,Proxy 的访问所导致的。
说了这么多,我们做了哪些功能?我举个简单的例子讲一下如何实现的,下面可能会比较烧脑,因为有一些代码,不太适合在开场或者热身的阶段,所以举个比较简单的事情。读写分离,原来是没有读写分析的,所以对静态类,这块是新加的功能,我先讲一下总体的功能。MySQL Data Note 里会使用到 Channl,每个 Channl 是去执行 SQL 语句的。本身 MySQL 会使用到 Sleef,每个请求用一个连接,或者多个请求复用一个连接。原来没有 Sleef 要求,我进行了改造,并且进行了检测是否可用。对于前置的连接来说的话进行判断是否进行读写分离。而对于读写分离我们是不愿意让业务上层去做太多改造所以用了 MySQL Fent,然后再做路由,去拿到后端的路由之后,然后决定是选择 Master 还是最底下的哪个 Sleef。最终这样的改造之后够可以满足到读写分离功能。
即便是做了这么多性能跟稳定性改造之后,其实还是有很多的问题。尤其是在 300 人的团队以上,这个时候团队里的技能是参差不齐的,尤其是有多的业务线,有很多的研发,有很多的流量,而这些引发出每一天做 DDL 的变更会很多。而在 DDL 的变更,像在一个集群数量大的时候,每个分片都要做对接,引发的故障也会多一些。并且研发人员多跟 DBA 交流和交互时间效率也会变得很低。并且业务开发人员他的 SQL 技能是跟不上,比如说覆盖索引,组合索引,MySQL 紧密索引,都没有什么概念,在技能没有跟上的情况下面,对于生产系统是一个非常大的挑战。并且 MySQL 本身也会有 Feel,Master 要挂掉,在这个时候会频繁发生 MySQL HA。而对 MySQLHA 是灾难性事情,数据是很难保持一致。所以在退化数据的时候,在退化的过程中数据的一致性是非常难以保证。所以在这样的问题下面,我们单纯的 RDS 功能增加有如下的,对 Proxy 的改造,增加了 DDL 支持工作流,让每个研发人员能够在同一个平台提交 DDL,并且帮助 DBA 节省他熬夜的工作时间,能够提升他自己的工作效率,这个是比较重要的。第三,对 MySQLHA 的一些改造。
讲 RDS 结构之前先一下 RDS 模块。它的模块如图。
Console 是作为总管理端和操作入口。Proxy 是从一开始就有,这是用户访问的代理层。而 HA Master 是作为 HA 检测和切换操作。Canal Manager 是作为数据驱动的事件通知系统,Tablet 是部署我在每个 MySQL 主机上面的代理,是一个 Local Agent,Tablet 现在能够承载于启动 MySQL 指令,能够对 MySQL 进行白名单的过滤,而 MySQL 本身是我们互联网重度依赖的一个开源的软件数据库的。在每个单机上会部署多个数据组。M 就是 Master1 的使令,Tablet 是跟 RDS 交互,当然 MySQL HA 要做的时候,检测中 MySQL Master 挂了,要启动其中的一个 F1 或者 0,是通过 Master 检测和控制的。本身 HA-Master 跟 Console 可以放同一个进程里,但是迭代是比较快,所以为了稳定性拆开,后续会考虑合并。然后把 MySQL 上面的 Realy 尽量搜集到且回放给 log。通过这样链路的调整之后,我们现在够去掉了原先 VIP 那个 RDS 的方案。右下角这端相对而言是互联网里比较常用的事件驱动源的架构对孵化的进程中,这个可以忽略。
效果展示这个是当时梳理的系统架构,系统里的概念,主要针对运维的需求和线上开发人员,还有 DBA 的一些需求和 MySQL 自己本身的一些概念所做的一些梳理。所以对 RDS 做了这些 Proxy 改造和 DDL 的工作流之后,我们对 RDS 有一个相对比较大的提升。整个控制台可以看到所有的都在这个控制台,可以看到单纯的流量是多少等等。这里截了两张图,没有太多的演示,因为这个产品界面本身也在不断的改,主要是这两个功能是比较重要的。
写在最后最重要的一点,我觉得在 300-1000 人或者在未来更多人的团队里,工作流是非常重要的,而且在使用 MySQL 过程中,它的本身就很复杂,无论它的合理实现或者不合理实现都会引发概念上或者实现上的一些区别,所以我们对 DDL 进行工作流的支持,这样的话就可以提高整个业务线上面开发效率,能够缩短业务上线时间。我认为这个是比较重要的工作效率的提高。虽然说很多的所谓想做高并发软件设计不适合做这个,但是这个是很重要的事。关于 RDS 前面讲了我们所做的,可能没那么多高大上的事情,但是实际上是我们已经做的事,和关于 RDS 未来我们还会继续往以下的系统模块再继续加深。RDS-Console,做更好的测试,RDS Proxy 做更好的性能和流量的划分。HA Master 会引入 Roft 协议做诊断,而不是像前面所看到的图里面,它是中间是居前判断。而 CanalManager 会并入,不是通过 Canal 量,而是通过整套系统输出的。而 Tablet 会做更多的试用和运维的动作,而 MySQL 没有太多的改造,只会做更新迭代。
提问:请问 DDL 具体怎么提高工作效率的?林足雄:我不知道多少人经历过 0-300 人团队或者 300 人团队。DDL 本身开发给 DBA 提交 DDL 的时候,它是通过口对口,或者文本文件或者是后来稍微改进一点的,比如工作流,在这里提交一个工单,然后 DBA 每天去过那些工单。过完工单之后,DBA 把具体的 DDL 在 MySQL 上通过命令函 CL 显示执行 DDL。而 DDL 本身当时来说是没有问题的。
我前面提到了,业务线非常多的时候,在七八个语句的时候效率蛮高的,当又有分片的时候来说,每条具体的语句就要形成 1014 个执行任务,DDL 的时间就会很大量的占用 DBA 的时间。还包括 DDL 对于每一个 Sharding 上是否成功 DBA 也关心。而是否成功这个动作本身还是需要同步等待的。比如说一百句数据库的话它就得等,或者过一段时间再检查。而改造变成把这些工作流全放在管理系统里。管理系统里通过开发人员在管理系统里提交工单,然后给具体的执行 MySQL,把执行的后果和进度提交到 Console 系统上,上报到 Console 系统可以通过界面展示,并且连动手机的报警和短信,或者我们有赞内部的 APP 系统搜集就可以。这样会减少 DBA 凌晨执行任务的时间。因为大量的 DBL 是在凌晨跑的。比如说十句以下的 DDL 下去,DBA 在凌晨不需要值班,以前是需要的。所以 DBA 的生命还是蛮宝贵的。
作者介绍
林足雄,有赞架构师,2010-2013 金山软件,开发经理 + 架构师;2013-2015 蘑菇街,架构师;2015- 至今 有赞,中间件 TL+ 架构师。