OneProxy :: 启用SQL复杂度分析,为数据、应用架构师量身定制的功能。

2008年加入支付宝,现在已经是全球最大的在线支付公司,去做一个高级的DBA和数据架构师,在整个6年的职业生涯中,业务量从每天100万笔上涨到每天超过2亿笔,必须用一个分布式的数据库架构来支持如此高并发的业务。但并非天生就是分布式的,最早所有的表都放在一个数据库的一个用户下,并且跑在一台IBM的小型机和一台EMC的存贮上,那是一段很有意思的经历(事后回忆),每次业务高峰(双十一)来临之前,都成功地进行了一次数据库系统的拆分,刚刚好顶住了业务的发展,而数据库也从最初的一台机器扩展到将近1000台机器(大部份的MySQL和少量的Oracle)。现在越来越多的公司有了大量的业务,从我过去的经历中,可以得到什么呢?

企业里研发资源永远都不不够的,架构优化和新业务开发谁更重要?没有人知道确切的答案!新业务研发的资源是可以确切地估计的,而架构改造的方案提出后总会被问“一定要这样吗”、“资源实在紧张,有没有更省力的办法”等难以回答的问题。因此我的第一要务是要澄清我的方案,并且能说明这已经是最优的做法了。

数据库的拆分成为系统的关键,因为应用已经是分机器布署,并可随时扩容。问题是已经找不到人对系统中差不多上千张表都熟悉的DBA、开发和架构师了。半路加入公司的我什么都不清楚,发现有许多表已经找不到原始的开发人员来询问了,有一些离职了,还有一些转岗了,切实地反映了代码即文档的现象。当时我面临的困难是如何提出一个清晰的拆分方案,包括资源估计和效果分析,否则让管理者无法做出真正的决策。

数据库拆分(Sharding)是谁都知道的出路,但问题是如何得到一个清晰的拆分策略,要清楚到可以估计资源计划可以落地的程度。因此联合开发人员编写脚本来扫描代码库里所有SQL Map文件中的SQL语句,以知道哪些表经常出现在同一个事务中或同一个查询中,再结合从Oracle Statspack中得到的SQL执行频率信息,来得到最终可以落地的拆分方案。在业务高速发展的阶段,用最少的资源去获得最大的收益是必要的,因此要尽量少拆分事务和复杂查询。这样的扫描分析工作持续了大约半年时间,为的只是得到一个较为准确的关联度分析报告(如Zabbix复杂度分析报告)来避重就轻。

现在可以用OneProxy中间件(MySQL版本/PostgreSQL版本,也许会在2016年出Oracle的版本)来做此类统计分析工作。假设我们通过OneProxy中间件提交了如下事务(由两个不同表的查询构成的一个事务)到数据库后端。

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select count(*) from my_hash;
+----------+
| count(*) |
+----------+
|        9 |
+----------+
1 row in set (0.07 sec)
mysql> select count(*) from my_list;
+----------+
| count(*) |
+----------+
|        9 |
+----------+
1 row in set (0.06 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

这个事务的执行频率信息就会被OneProxy实时统计出来,所有的事务会根据事务所涉及的表进行归类统计,而非根据相同的SQL来归类统计。所有只涉及“my_hash”和“my_list”这两张表的事务会被统计成一条记录,可以运行“list trans_debug”命令来得到事务执行的频率。

mysql> list trans_debug;
+---------------------+------+
| TRANMAP             | EXEC |
+---------------------+------+
| trx:my_hash,my_list |    1 |
+---------------------+------+
1 row in set (0.00 sec)

如果执行频率(参照“EXEC”列)比较高,在分库分表时就不应当将“my_hash”和“my_list”两个表分到不同的数据库中,如果在拆解事务的过程中需要引入应用层的分布式事务,代价(包括运行代价和代码改造代价)也是极大的,因此要保证尽量不拆分高频事务,而是选择拆分执行频率不高的事务。接下来通过中间件运行一个复杂的SQL,此SQL中包含了两个表的关联操作。

mysql> select t1.id from my_hash t1
    ->    join my_list t2 on t1.id = t2.id;
+----+
| id |
+----+
|  7 |
+----+
1 row in set (0.00 sec)

再次到OneProxy管理端口中执行“list trans_debug”命令去查询关联分析的结果,可以看到多了一条记录。

mysql> list trans_debug;
+---------------------+------+
| TRANMAP             | EXEC |
+---------------------+------+
| trx:my_hash,my_list |    1 |
| qry:my_hash,my_list |    2 |
+---------------------+------+
2 rows in set (0.00 sec)

如果在OneProxy中间件上接入正式的应用,就可以很快地得到一个表与表之间关联程度(事务关联或查询关联)的分析报告,将对你制定一全明确的数据库拆分策略或做一次大的系统优化提供有利的基础,任何时侯清晰的分析对推动事情是致关重要的。