来自实践的教训
以下每段都是对实践中遇到的真实问题的总结,个别内容还有待更深入地探索。
自增列步长兼容性问题
准生产上线的当天,发现一个重要模块的某些功能随机报错,错误信息大致为“Primary Key not Found”,经过各层面的调查,最后终于发现是PXC的自调整自增列的默认行为,与公司使用的OR-Mapping的Ruby类库Active Record不匹配。PXC默认会开启wsrep_auto_increment_control,每个节点的自增列步长会根据PXC节点数量的变化自动设置,而Active Record的某些函数假设新增列的步长为1,并没有考虑到>1的情况。最终关闭wsrep_auto_increment_control并保持单点写入作为解决方案。
关于GTID空洞的坑
目前我们的实践经验是,GTID或者PXC单独使用都可以,如果二者同时使用,某些情况下会导致GTID产生空洞,再切换Slave时不能自动转接,需要DBA人工干预。具体细节如下:正常GTID为UUID:X1-Y1的格式,但有时会有:UUID:X1-X2:X3-Y1(X3>X2+1,也就是不连续)的情况发生。这里提醒读者,一定注意小心验证,防止Slave不能Switch Master的尴尬问题发生。具体原则就是Slave的UUID一定要是Master GTID的子集。一般说来可以通过SELECT GTID_SUBSET(“uuid:xxxxxx”,“uuid:yyyyyyy”)来提前判定,源代码层面以下代码段的检查需要正确返回才可以:
mysql-server/sql/rpl_binlog_sender.cc(5.6):707: int Binlog_sender::check_start_file() {…… if (! m_exclude_gtid->is_subset_for_sid(>id_executed_and_owned, gtid_state->get_server_ sidno(), subset_sidno)) { errmsg= ER(ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER); global_sid_lock->unlock(); set_fatal_error(errmsg); return 1; } if (! gtid_state->get_lost_gtids()->is_subset(m_exclude_gtid)) { errmsg= ER(ER_MASTER_HAS_PURGED_REQUIRED_GTIDS); global_sid_lock->unlock(); set_fatal_error(errmsg); return 1; }
不兼容SQL的问题
这里不再多说,GTID启用备战时,以下两个场景测试都被我们命中,得以提前推动开发团队进行完善。这里提醒读者的就是一定要采用尽量完备的测试用例,不然上线后会非常被动。
i.显示事务内的create/drop temp table不支持
ii. create table… select statement不支持
SST/IST对性能的影响
为了尽量避免PXC的SST(全量恢复),我们做了定制化设置:
wsrep_provider_options="gcache.size=1G" wsrep_sst_donor = pxc02 [sst] rlimit=70m
gcache.size用于尽量使用IST, wsrep_sst_donor用于保护PXC01的IO性能;
rlimit用于在IST/SST时三节点之间的网络限速。而且必须安装linux PV command。