当前位置:首页 > 问答 > 正文

多数据库环境下Citus集群那些琐碎又必须的维护工作和坑点分享

(来源:Citus官方文档、AWS RDS for PostgreSQL/Citus维护指南、实际运维经验分享)

多数据库环境下用Citus,首先一个事儿就是初始的集群规划,这个一开始没想好后面全是麻烦,比如你一开始只用了4个 worker 节点,每个节点32G内存,后来业务数据量暴增,你发现需要加机器了,但问题来了,Citus 的哈希分片数是固定的,默认是32,你加新节点后,数据不会自动从老节点搬一些到新节点上以达到空间平衡,老节点还是撑得满满的,新节点空着,这叫“存储空间不平衡”。(来源:Citus创建分布式表后分片不可再更改的特性)你得手动操作,用 rebalance_table_shards() 这个函数来重新平衡,这个过程会挪动数据,非常吃I/O和网络,必须在业务低峰期搞,而且得盯着,万一网络闪断一下可能就失败了。

说到分片,另一个琐碎的点是选择分布列,这个选错了简直是灾难。(来源:Citus最佳实践中关于分布列选择的强调)比如你把用户表按user_id分片,订单表按理说也应该按user_id分片,这样查一个用户的所有订单时,Citus可以把查询精准地发送到同一个worker节点上执行(这叫“并置”,Colocation),效率很高,但要是你手一抖,或者之前不懂,把订单表按order_id分了,那完了,每次查用户订单,Citus都得向所有worker节点广播查询,再把结果收回来,慢得要死,还拖垮整个集群,这种设计上的坑,后期改起来等于重做一张表,要停机迁移数据,非常痛苦。

多数据库环境下Citus集群那些琐碎又必须的维护工作和坑点分享

日常维护里,最躲不开的就是备份恢复,Citus官方明确说了,直接用pg_dump备份协调器(Coordinator)节点是没用的,因为它只存了分片的元数据,真实数据都在worker节点上。(来源:Citus文档“备份和恢复”章节)你必须停掉所有数据库连接,然后同时、并行地去备份每个worker节点和协调器节点,这个“很重要,因为要保证所有节点备份的数据在同一时间点,不然数据对不上,恢复的时候也一样,要把所有节点的备份恢复到同一个时间点,再启动集群,这个过程非常繁琐,自动化脚本是必须的,而且得定期做恢复演练,不然真出事了发现备份是坏的或者恢复流程走不通,那就傻眼了。

监控也是一大堆琐事,你不能只看整个集群的总体CPU、内存,那没用,你得深入到每个worker节点去看。(来源:实际运维中的经验教训)因为数据可能不平衡,或者某个查询正好卡住了某一个分片,导致“热点”问题,表现出来就是整个集群查询变慢,但你一看总体监控,资源利用率都不高,结果一查,发现是worker D节点CPU 100%了,其他节点闲着呢,所以监控必须细化到每个worker节点的详细指标:长事务、锁等待、慢查询、磁盘空间、网络流量等等。

多数据库环境下Citus集群那些琐碎又必须的维护工作和坑点分享

还有版本升级,Citus的版本是跟着PostgreSQL主版本走的,你想升级Citus扩展的版本,比如从10.2到10.3,可能比较简单,在线就能搞,但如果你想升级PostgreSQL的大版本,比如从13升到14,那就复杂了。(来源:Citus社区升级讨论)官方推荐的方法是:搭建一个全新的PostgreSQL 14+Citus新版本的集群,然后把老集群的数据用pg_dump/pg_restore或者逻辑复制的办法导过去,这个过程耗时很长,而且几乎要求停服,因为要保证数据一致性,你得写详细的方案,反复测试,找个维护窗口才能做。

一些意想不到的坑点,Citus对某些PostgreSQL的特性支持是有损的。(来源:Citus局限性文档)比如大对象(Large Objects)类型,它就不支持,如果你原来的单机PostgreSQL数据库里用了大对象,迁移到Citus前就得想别的办法替代,还有外键约束,你只能在同一组分片表之间创建外键(也就是分布列相同且并置的表),想给不同分布列的表加外键?不行,这些限制在应用设计阶段如果没考虑到,等代码写完了发现不支持,改动成本就太大了。

用Citus不是一劳永逸的,它把单机数据库的维护复杂性分摊到了多台机器上,维护点变多了,监控维度也更细了,那些自动化的、脚本化的日常巡检和操作,比如空间使用预警、定期重平衡、备份验证,看起来琐碎,但恰恰是保证这么一个分布式数据库能稳定跑下去的关键。