POLARDB · 最佳实践 · POLARDB不得不知道的秘密 (3)

具体解释一下POLARDB上DDL的过程。在DDL的不同阶段,当需要对表进行结构变更前,主实例自己获取MDL锁后,会写一条redolog日志,只读实例解析到这个日志后,会尝试获取同一个表上的MDL锁,如果失败,会反馈给主实例。主实例会等待所有只读实例同步到最新的复制位点,即所有实例都解析到这条加锁日志,主实例同时判断是否有实例加锁失败,如果没有,DDL就成功,否则失败回滚。

这里涉及到两个时间,一个是主实例等待所有只读实例同步的超时时间,这个由参数`loose_innodb_primary_abort_ddl_wait_replica_timeout`控制,默认是一个小时。另外一个是只读实例尝试加MDL锁的超时时间,由参数`loose_replica_lock_wait_timeout`控制,默认是50秒。可以调整这两个参数来提前结束回滚DDL,通过返回的错误信息,来判断是否有事务没结束。
`loose_innodb_primary_abort_ddl_wait_replica_timeout`建议比`loose_replica_lock_wait_timeout `大。

举个实际例子方便理解:
用户可以通过命令`show processlist`中的State列观察,如果发现`Wait for syncing with replicas`字样,那么表示这条DDL目前处在等待只读节点同步的阶段。如果超过`loose_innodb_primary_abort_ddl_wait_replica_timeout`设置的时间,那么主节点会返回错误:
```
ERROR HY000: Rollback the statement as connected replica(s) delay too far away. You can kick out the slowest replica or increase variable 'innodb_abort_ddl_wait_replica_timeout'
```
如果没有超时,那么主节点会检查是否所有只读节点都成功获取MDL锁了,如果失败,那么主节点依然会返回错误:
```
ERROR HY000: Fail to get MDL on replica during DDL synchronize
```

如果主实例返回第二个错误,那么建议用户检查一下主实例以及所有只读实例上是否有未结束的大查询或者长时间未提交的事务。

这里顺便介绍一下大事务长事务的防范手段。参数`loose_max_statement_time`可以控制大查询的最大执行时间,超过这个时间后,会把查询kill掉。参数`loose_rds_strict_trx_idle_timeout`可以控制空闲事务的最长存活时间,当一个事务空闲状态超过这个值时候,会主动把这个连接断掉,从而结束事务,注意,这个参数应该比`wait_timeout/interactive_timeout`小,否则无效。

## 查询缓存问题
在MySQL低版本,查询缓存(Query Cache)能提高查询的性能,尤其是更新少的情况下,但是由于其本身也容易成为性能瓶颈,所以在最新的MySQL中此特性已经被移除。POLARDB目前的版本兼容MySQL 5.6,所以用户依然可以使用查询缓存,但是我们还是建议不使用,因为我们在引擎存储层做了很多优化,即使不用查询缓存依然有很好的性能。

由于POLARDB使用了物理复制,不同于binlog的逻辑复制,查询缓存在只读实例上的失效,依然需要通过redolog来保证,即当某条查询缓存失效的时候,需要通过redolog来通知所有只读节点,让他们把对应的查询记录也失效掉,否则通过只读节点会读到历史版本的数据。

当查询缓存失效时,会写redolog通知所有只读节点,这个机制默认是关闭的,通过参数`loose_innodb_primary_qcache_invalid_log`来控制。

综上所示,如果在只读节点上开启了查询缓存(只要有一个开启),那么必须在主节点上开启`loose_innodb_primary_qcache_invalid_log`,否则只读节点会读到历史版本的数据。考虑到HA切换会切换到任意一个只读节点,因此建议如果开启了查询缓存,在所有只读节点上也把`loose_innodb_primary_qcache_invalid_log`开启。

## 读写分离问题
POLARDB自带一个只读实例,增减只读实例非常快速,所以用户非常适合使用读写分离的功能,但是从目前用户的反馈来看,如果在插入数据后立刻查询,很容易查询到之前旧版的数据,为了解决这个问题,我们给出两种解法。一种是通过POLARDB数据库内核的强同步保证主实例和只读节点数据一致,另外一种是通过数据库前面的PROXY层来解决。下面简单介绍一下。

POLARDB集群基于物理复制构建,目前复制除了支持常规的异步复制(默认),半同步复制之外,还有强同步复制,即当事务提交时,只有当指定的只读实例应用完redolog日志后,主实例才给用户返回成功。这样即使后续的读请求发送到了只读节点,也能保证读到最新的数据。但是这个配置会导致性能大幅度下降,只有默认异步复制的三分之一左右,在使用之前请做详细的测试。简单说一下配置过程:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzszfy.html