OneProxy :: 智能择主模式,保障读写分离的强一致性读,做到应用透明!

今年双十一技术准备期间,我们客户发现他们的部分业务应用无法通过OneProxy中间层来实现读写分离的扩容方案,主要原因是业务应用对数据一致性的要求极高,否则可能引起业务逻辑问题,并且暂时没有办法进行代码优化。应当说这种情况是相当普遍的,在企业的供应链系统中,业务周期较长,并会涉及非常多的业务环节,由多个业务参与方,因此业务应用也是由不同参与方的不同模块构成。如何保证读写分离架构中,读操作的强一致性?比如以下业务逻辑:

start transaction;
update a set ......;
update b set ......;
commit;
select * from a where ...;
select * from b where ...;

如何保证,事务后的两个查询操作能查到最新的数据?在真实的应用场颢中,不同的业务逻辑,事务大小会千差万别,事务后需要强一致性的查询语句个数也不确定。也许我们会相到用强一致性的MySQL集群技术,比如MariaDB Galera Cluster或Percona XtraDB Cluster,这是一个相当不错的解决方案,那么在OneProxy中间层上,有没有其他的办法呢?可以让普通的主从结构的MySQL集群也能提供强一致性的读操作?为此目标,OneProxy引入了智能择主模式,可以保证读写分离架构下的强一致性读。其核心逻辑如下:

  1. 通过SQL语句分析,记录每一个表的最后更改时间。如果是事务更新,则为事务提交时间。
  2. 对不含分组汇总的查询语句,需要得到所涉及的表的更新时间,并保留最后的那个时间点。
  3. 检查备库的复制检查时间点,跳过检查时间点小于最后更新时间点的结点。
  4. 取得备库恢复时间点,如果恢复时间点小于最新更新时间点,则跳过此备库。
  5. 默认只对当前会话有效,可以设置成全局有效,全局级别读写分离效果会差一些。

如果所有的流量都经过OneProxy,则可以保证读写分离方案中的读操作的强一致性,从而使得对数据一致性要求极高的业务应用,可以放心大胆地使用读写分离方案来进行扩容,不必担心引发业务逻辑问题,在OneProxy已经使用表级的最后更改时间来自动踢除恢复不及时的从库节点,相当于实现了基于时间点的一致性读。如果需要设置成全局所有会话生效,只需要在OneProxy的配置文件中,增加如下参数:

......
# 0 default for current session, 1 for global
proxy-smart-master     = 1
......

需要注意的是,如果查询和更新都较多的表,读写分离的效果可能会打折,如果系统中查询的表和更新的表分离得比较好,则会取得非常好的读写分离效果;另外需要保证更新也通过中间件来操作,否则将得不到表的最新更新时间,引起业务脏读;第三需要启用OneProxy的主从时间检测,否则得不到准确的备库复制时延值,也会引起业务脏读。可以通过如下脚本来进行验证(其中第一条记录主备的值不同,以判断查询来源):

update t_rwsplit set col2 = col2 + 1 where id = 2;
-- from master
select id, col2 from t_rwsplit where id = 1;
-- from master
select id, col2 from t_rwsplit where id = 1;
select sleep(1);
-- from slave
select id, col2 from t_rwsplit where id = 1;
-- from slave
select id, col2 from t_rwsplit where id = 1;

特别提查,此功能需要将OneProxy升级到6.2.0版本。智能择主功能将使读写分离成为所有程序的标配!