数据库 频道

分布式数据库的存储引擎要复杂得多

前阵子一个朋友问我,为什么使用分布式数据库的时候SQL语句的超时不能设得太高。他在使用某分布式数据库的时候,经常发现SQL因为超时而被自动KILL掉,于是把超时参数设置得极大,调了超时参数,慢SQL不会因为超时而被杀死,但是数据库时不时出现一些莫名其妙的HANG死,要不就是DDL操作假死悬挂,要不就是突然主从同步延时过高。原厂工程师分析了之后,建议他们调小超时参数。于是他们就陷入了两难,调小超时,很多业务跑不出来,就必须改应用来适应数据库的超时设计,满足了大查询的需求,数据库又会变得不稳定。

实际上这位朋友面临的困境是很多刚刚开始使用分布式数据库的朋友都遇到过的。因为不愿意做应用分拆,怕国产集中式数据库撑不住,所以选了分布式数据库。没想到上了分布式数据库,发现应用更需要改造了。这是因为分布式数据库的存储引擎是与集中式数据库截然不同的,其复杂度要高出数个等级来。

从集中式数据库迁移到分布式数据库,首先会面临的就是数据分布问题。大多数应用系统都有复杂的多表关联查询。哪怕仅仅是单表的扫描查询,如果SQL的WHERE条件与数据的分布键没有关系,那么一条SQL就需要发送到所有节点去执行,然后再汇聚数据,这就会产生读放大。如果只是一条SQL还好说,分布式数据库节点多,跑起来可能更快。但是如果类似的SQL有几十条,数百条并发执行,那么再豪华的硬件配置都可能被撑爆了。涉及到多表关联查询问题就更大了,对于集中式数据库,JOIN操作只要在内存里进行,速度还是很快的,但是如果其中一部分要借助磁盘排序,性能一下子会下降很多。而在分布式数据库中,如果JOIN需要借助网络数据交换来完成,那性能下降比起集中式数据库的磁盘排序又要慢上几个档次了。因此在使用分布式数据库的时候,表组、分布键、复制表等的设计是不可缺失的,想要平替,最后肯定会遇到坑的。

写事务就更麻烦了,集中式数据库的锁资源就是内存中的一个数据结构,通过LATCH保护,其访问效率是极高的,分布式数据库的每个存储节点或者计算存储融合节点都有独立的日志流,也都有数据持久化机制。一个事务如果涉及到多个存储节点,那么其事务提交必然是多阶段的。本地要提交到日志流里,跨节点的分布式事务又有一层全局事务管理机制。如果多阶段提交事务失败,还需要有相应的补偿机制。最关键的是全局资源的锁的成本远超集中式数据库,因此如果某个操作长时间不完成,可能会影响其他的组件。比如以LSM-TREE为存储结构的数据库,如果某个操作HANG住,很可能会影响转储、合并等关键操作,一个小问题可能扩散为大问题。超时的设计是十分必要的,牺牲某一条SQL来确保整个集群的稳定性是个无奈的必选题。而对于应用开发人员或者最终用户来说,拆解特别大型的SQL对的业务逻辑,也就成了必须要去做的事情了。基于分布式事务的高昂成本,应用的单元化改造也成为了必选项。除非你的应用对性能不关注,否则尽可能减少分布式事务是在应用迁移时必须考虑的问题。

尽可能减少某个事务的延时对于分布式数据库应用而言也是十分关键的,一个设计良好的应用,每个事务中影响的数据行的数量必须有很理性的控制。虽然现在绝大多数分布式数据库都已经可以把每个事务相关的行数设置到无限大,但是受限于内存、网络包的大小等因素,尽可能减少每个事务修改的记录数,是一种比较安全的用法。

0
相关文章