本文介绍DBLE与PolarDB多主集群(库表)结合使用的最佳实践。
原理介绍
DBLE是一个基于Java开发的数据库中间件,通过在应用和数据库之间部署一套代理,来帮助您实现非应用侵入式的分库分表。
PolarDB多主集群(库表)通过将不同的逻辑数据库分散到不同的主节点(RW),来实现读写能力水平扩展。
DBLE和PolarDB多主集群(库表)结合使用,通过DBLE将数据分散至多个数据库,再结合PolarDB多主集群(库表)实现读写能力扩展。原理图如下所示:
如果仅使用DBLE,在需要提升数据库集群读写能力时,需要先使用传统数据库运维手段进行数据复制和备份恢复,再配合业务系统停写、DBLE配置更新、数据验证、业务系统恢复等步骤来提升数据库集群的读写能力。其中,数据库的运维操作尤为复杂耗时。
使用PolarDB多主集群(库表)之后,您可以省去大部分手工扩展数据库集群的工作。您只需要通过控制台或OpenAPI为PolarDB多主集群(库表)增加节点即可。在业务低峰期,配合业务系统的停写,再执行
ALTER DATABASE name POLARDB_WRITE_NODE x
等操作,即可在数秒内将数据库集群的读写能力扩展到新增的节点上。大幅减少了数据库停写维护的时间,提高了业务系统的SLA。
DBLE的db.xml配置文件中可以配置数据库组(dbGroup)。建议将同一个PolarDB集群在多个数据库组中配置多次,使得数据库组与sharding.xml中的shardingNode 一一对应。通过这样的配置方式,能够减少在DBLE维护的长连接中执行use database
语句的频率,提高查询执行的性能。与此同时,需要确保DBLE配置的最大连接数总数不超过PolarDB集群的最大连接数。
注意事项
如果多个查询均需要开启显式事务,需要注意不同事务中操作表的顺序,确保不同的表按照同一顺序先后执行,避免因顺序问题导致死锁。
示例:以下两个事务中,事务1会按照先后顺序去获取
table_1
和table_2
两个表中id=1
的行锁,事务2则按照相反的顺序获取行锁。如果两个事务分别在两个MySQL连接中同时执行,MySQL会判定发生死锁,为了保证其中一个事务的顺利执行,另外一个事务会被回滚。事务1:
update table_1 set c = 1 where id = 1; update table_2 set c = 2 where id = 1;
事务2:
update table_2 set c = 1 where id = 1; update table_1 set c = 2 where id = 1;
DBLE存在死锁风险。在DBLE的实现中,一个前端连接可以对应多个后端连接,即使是将查询转发至同一分片,如果查询的表名不同,也会使用不同的后端连接。因此,上述示例中的两个事务经过了DBLE代理之后,会转换为四个MySQL连接。事务1的第二个连接,等待事务2的第一个连接释放行锁,进而导致事务1无法提交。而事务2的第二个连接,等待事务1的第一个连接释放行锁。由此两个事务形成了死锁。
说明DBLE操作涉及多个表和多个分片的事务,存在部分提交的风险,请您谨慎评估这些风险。
应用系统应使用数据库连接池连接DBLE的数据端口,以便在连接断开时自动恢复。
性能测试
使用Sysbench构造基准测试,查看DBLE结合PolarDB多主集群(库表)的弹性扩容能力。
测试环境
PolarDB多主集群(库表)包含4个数据库,4个RW节点(4核16 GB)。DBLE以非集群部署于ECS,DBLE提供1个逻辑库4个逻辑表,每个逻辑表均按id%4
散列到PolarDB多主集群(库表)的4个数据库上。
测试过程
初始状态下,4个数据库全部负载于其中一个RW节点,再使用Sysbench启动256个线程对所有逻辑表执行基准测试。测试期间,将3个数据库依次切换至空闲的RW节点,最终每个RW节点上均有且仅有一个数据库。查看集群整体的性能变化趋势。
如果业务的写入以自动提交(autoCommit=1)为主,PolarDB多主集群(库表)结合DBLE可以实现接近线性的性能提升。
QPS与MPS:
TPS与CPU使用率:
如果业务的写入以显式事务(autoCommit=0)为主,PolarDB多主集群(库表)结合DBLE可以实现仅次于线性的性能提升。以256个线程进行写入测试,弹性扩容效果如下:
QPS与MPS:
TPS与CPU使用率: