MySQL中GTID追踪的自适应路由查询是怎样的

MySQL中GTID追踪的自适应路由查询是怎样的,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

基于GTID追踪的自适应路由查询

ProxySQL是一个工作在第七层(应用层)且支持MySQL 协议的的数据库代理,ProxySQL本身自带了高可用和高性能的功能,并且包含了丰富的功能集。在即将到来的2.0版本中的功能将会更加excited!

ProxySQL中最常用的功能当属查询的分析统计和基于路由查询做到的读写分离。

当客户端连接到ProxySQL执行查询时,ProxySQL 会先根据预先设定好的路由规则进行路由检查,并分发到这条语句应该被执行的实例上。最简单的例子就是将所有的读查询全部路由到从库,所有的写查询全部路由到主库。当然,由于读查询有可能在从库上读到非最新的数据,这个案例在生产上并不是实用的。因此,我们建议将所有的请求都发到主库上,同时由于ProxySQL 对SQL统计信息的支持,DBA可以针对性的创建更加精准的路由规则,将特定的查询路由到从库。详细信息和其他案例可以参考之前的文章

在ProxySQL支持高客制化的路由规则设定,甚至可以通过next_query_flagIN参数指定当前查询连接的下一个查询仍然在同一组(hostgroup)实例上执行,比如可以通过这个特性,指定插入数据语句的后面的查询语句仍然在同一个实例上被执行。但只有在DBA对应用逻辑非常清楚的情况下,才能知道哪些功能或者查询是先写后查的,因此这个特性实际应用起来比较复杂。

 上下文一致性读

虽然某些应用对数据实时性要求极高,但其对上下文一致性读还是兼容的,即客户端可以读到同一个ProxySQL连接中被自己修改后的数据。这个特性在MySQL默认的异步复制结构是无法保证的,异步复制情况下,在主上提交写后,从库上有可能因为传输时间占用或者执行速度的差异导致客户端并不能同时读到刚刚修改的最新数据。

那么我们如何保证只有当写事件被完全同步到从库后,查询才会由ProxySQL路由到从库呢?

基于GTID

GTID helps in this.

在MySQL 5.7.5更新后,客户端可以知道其最后写入事务的GTID,而且可以在任何当前GTID代表的事务已经被执行的从库上进行读操作。Lefred 在博客中举例描述了这个过程,如下:MySQL实例服务端开启session_track_gtids参数(这是个覆盖全局和线程级的参数,用于返回当前事务成功执行的标记和GTID编号)后,客户端就可以在从库上使用SELECT WAIT_FOR_EXECUTED_GTID_SET('3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5')的函数来判断刚刚在主库执行的写事务是否在从库上已经被执行。

虽然可以通过这种操作来保证上下文一致性读,但由于以下原因,这个方法对生产环境来说还是比较麻烦和不实用的:

在从库上执行业务查询时每次都要加上WAIT_FOR_EXECUTED_GTID_SET的话,会增加单个查询的响应时间

出于效率,若想从若干个从实例中找到已经执行完指定GTID的实例,可能需要在所有的从库上都执行一遍

很可能所有的从库在可接受的延迟等待时间内都没有完成该GTID的同步

也就是说上述的操作在生产环境中并不实用

 可以追踪GTID吗?

由于ProxySQL饰演着MySQL客户端的角色,当session_track_gtids 开启后,ProxySQL 也可以跟踪所有前端发来的所有请求的GTID,而且可以准确的获知每个前端连接最后的GTID值。这样就可以使用这些信息去路由读请求到正确的从实例(指已经执行完某个线程指定的GTID事务的从实例)上。那么,ProxySQL 怎么追踪指定的GTID是否在从库上已经被执行呢?

大概分为两种办法:

主动问询:ProxySQL 定期的查询所有实例的GTID执行情况

聆听告知,每当一个新的写事件产生且GTID编号被生成后,ProxySQL 会立刻接到告知

需要注意的是,由于每次问询之间总是有一定的间隔,导致主动问询方式总是不可避免的存在着基于问询间隔的延迟,问询的越频繁,获取的信息就越准确,但会增加MySQL实例的负载,且当ProxySQL实例过多时会占用查询带宽和流量。总而言之,理论上来说,这种办法效率又低,架构可扩展性又差。

那么聆听告知的情况

 实时获取已经执行过的GTID值

从技术上来说获取当前已经执行过的GTID 值很简单,只要实时消费(分析)binlog即可。但是这种方法需要把ProxySQL实例所在的机器模拟成一个从库,如若单个ProxySQL负载了很多个MySQL实例,那么势必会对提升CPU的消耗。更进一步,如果一个机柜或者交换机上部署了很多ProxySQL 实例,那么传输binlog也会对整个网络的带宽带来考验。举个例子,现有4个集群,每个集群中的主库每天产生40GB的binlog并且挂了5个从库,附加30个ProxySQL实例,那么,每个ProxySQL实例需要把自己模拟成24个主从实例的从库。总计每天要消耗30TB的网络带宽。对自建机房的话或许可以直接纵向或者横向加硬件解决,但对云主机来说,每天将会无法避免巨额的流量费用。

ProxySQL Binlog Reader

主动问询GTID执行情况在上个段落中被认为是没有扩展性,且消耗较大的资源的方法。ProxySQL Binlog Reader工具应运而生:

ProxySQL Binlog Reader是一个轻型,运行在MySQL实例机器上,且通过把自己模拟成一个从实例连接到MySQL实例的跟踪所有GTID事件的进程。

ProxySQL Binlog Reader 本身就是一个服务器,每当前端连接进入时,就会开始以一个高效节省带宽的方式进行Binlog的流传输。

说到这里,我想聪明的您应该猜到了ProxySQL实例饰演着ProxySQL Binlog Reader服务的客户端的角色。

 实时路由

ProxySQL Binlog Reader 让ProxySQL 可以知道每个MySQL实例当前GTID 的执行情况。那么,当客户端执行一条读写分离查询时,ProxySQL就会马上知道这个请求该被路由到哪台从服务器上。退一步说,即使当前所有的从实例都没有完成该GTID的执行,那么ProxySQL 也会明白这是个主写,从读的查询。

 细致的设置项,支持多集群

ProxySQL是高客制化的,本文所介绍的功能同样如此。最重要的就是可以设置读请求是否支持上下文一致性(以ProxySQL中的组为对象)。不能设置完上下文一致性就完事大吉,例如,针对一个读请求,需要指定B组对A组满足上下文一致性(这里的组指的是ProxySQL中的Hostgroup,A组应该是写组,B组则可写,可读,只要保证同一连接如果在A上写,但读被路由到B的时候,能够读到刚刚写入的操作即可)。不仅支持主从之间上下文一致性读,还支持切片集群A+切片集群B构成的A-B高可用架构中,上下文一致性读查询(被路由到A或B中),

 要求

基于GTID的上下文一致性读需满足如下条件:

Casual reads using GTID is only possible if:

ProxySQL 2.0 以后的版本

后端使用MySQL 5.7.5以上的版本,老版本不支持session_track_gtids

binlog格式为行格式

开启GTID

后端仅限于Oracle或者Percona分支的MySQL,MariaDB不支持session_track_gtids

 结论

ProxySQL 可以路由查询请求到指定的GTID已经被执行的从实例。本解决方案扩展性极佳,网络资源占用低,且已经在实际环境中进行验证。

看完上述内容,你们掌握MySQL中GTID追踪的自适应路由查询是怎样的的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!