速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

三万倍提升,起飞的 PostgreSQL 主从优化实践

  • 2021-06-22
  • 本文字数:2463 字

    阅读完需:约 8 分钟

三万倍提升,起飞的 PostgreSQL 主从优化实践

一、背景介绍


腾讯云数据库 PostgreSQL 作为支撑着腾讯内部大量的业务,这些业务不仅仅包含有正式线上运行的,也包括内部测试开发所使用的数据库。不同业务有着不同的述求,不同的使用方法会带来不同的数据库问题。


作为一个数据库平台,需要支持各种不同的业务场景,本文重点讲述在大量 drop 的业务场景下所遇到的问题。


当前业务场景因为其安全要求特别高,对数据的更新特别慎重,不能随意更新。所以业务架构设计将需要修改的主库数据通过数据转换拉取到可编辑的分支库中。只有在审核后才合入到主库当中。



刚刚我们讲到了为了保证核心空间数据安全性,不能被任意修改,在业务系统中设计了可编辑分支库和主库的一套逻辑。具体实现是,不同类型的数据分散存放于不同数据库实例当中。


  1. 当终端采集到的数据需要对主实例数据修改时,不会直接修改主库数据,会从指定的分支库中进行变更。

  2. 变更完成后,通过校验和审核后,将变更数据同步至主库实例当中。

  3. 完成数据的 merge 之后,当前分支库就有可能不需要了,需要删除。但是分支实例是可以复用的,所以分支实例保留。


通过上述 3 个步骤最大程度的保证了数据的安全,然后落实到 PostgreSQL 数据层,意味着就需要分支库就会不断的新增表,并且完成更新会丢弃掉这些表。所以数据库中有着大量的 create/drop 表,这就引入了今天要讲到的重点—PG 内核关于主从同步的痛点。PostgreSQL 主从复制在大量处理此类的 drop 操作的时候会导致日志堆积,应用变慢的问题。不仅仅是在高可用场景下,拉一个从库作为只读实例也同样会出现此类情况,一旦遇到此类场景就会出现以下几种严重的后果。


  • 数据应用慢,主从切换 RTO 受到严重影响,一旦处于业务高峰期,每一秒受到的损失都难以承受。

  • 只读实例数据更新缓慢,导致主实例与只读实例数据不一致,严重的还会导致业务出现 BUG,导致数据错乱等问题。

  • 若主从同步级别为 remote_apply,还会导致主库 hang 住,导致主库的 drop 同时也变慢,且 DDL 会持有排他锁,会导致实例的一系列故障等。


二、原理分析


关于 PostgreSQL 的主从复制处理逻辑,大家知道 PG 备机通过物理复制实现主从同步功能。日志同步到备机之后,备机会解析 wal 日志,来与主库保持数据一致,而 PG 备机在恢复一条 drop table 语句时要做的操作有哪些呢?


  1. 恢复系统表,例如 pg_class,pg_attrbute,pg_type 等,相当于移除表的元信息;

  2. close 表对应的文件;

  3. 遍历 buffer 中的页面,如果缓存的是该表的页面,则标记为 invalid,后面其他进程可以使用该页面,这里就调用的前文提到的 DropRelFileNodesAllBuffers;

  4. 发异步失效消息给其他 backend,通知该表已删除;

  5. 删除表对应的外存文件。



单看上面的流程图中感觉挺简单,但是 PG 内核在第三步 invalid buffer 的时候,有一个罪魁祸首就是 DropRelFileNodesAllBuffers 这个函数。


因为这里 PG 的实现是需要从头到尾遍历整个 shard_buffer,查看 buffer 是否缓存有将要删除的表的数据,将其标记为失效。而 PG 中页面大小默认为 8K,以 shard_buffer 大小 16GB 为例,则一共有 16GB/8K = 200W 个 page,每删除一个表这里需要循环 200 万+次,如果表上面有索引,每个索引也要循环 200 万次(当然如果一个事务内删除的表比较多,PG 做了优化,循环内可以使用二分查找判断是否是需要淘汰的页面)。


所以从业务上看,当存在大量数据导入并且快速删除表的循环的时候,因为主库可以并发执行所以感觉不出性能的影响,但是因为 PG 的备库是单进程的 recovery,就会出现主备同步日志堆积,数据延迟问题的问题,如下图所示(吉代表 G):



三、问题修护


在官网发布的补丁和修护计划中也没有发现想要修改这个点的一个计划,所以就只能我们自己开始操刀了。那么如何解决呢?


回到刚刚的流程图中可以发现,第三部 invaild buffers 这个步骤实际上并非一个串行的操作,和其他步骤没有什么联系,于是我们做了一个优化,就是将 invalid buffers 步骤从整体步骤中抽出来,单独放到一个子进程中去实现,这样整体消耗日志的速度就会加快,即可解决日志堆积的问题


但是按照上面的做法,解决了日志堆积问题之后,也带来了另外几个问题:


  • 当清理 buffer 动作未完成时,最后一步 unlink file 时就已经完成了,此时数据库如果正在做 checkpoint 时,就会去 flush buffer 中还未标记为不可用的 page,此时就会导致打开文件错误。

  • 当清理 buffer 动作未完成时,删除文件执行完成后,又创建了一个和刚刚删除的文件同名的文件,会导致后续的文件在内存中的映射会被异步的置为 invalid。


那么如何解决呢,我们这里是将 recover drop table 操作的时候将表信息写入一个共享的 hash 表中,当 invalid buffer 结束时将表从 hash 表中移除,这样如果在此过程中发生打开文件失败,则就检查是否存在此 hash 表中即可。


并且如果在新创建文件的时候也去遍历一下此队列,如果队列中存在同名文件正在 invalied buffer,则等待即可。而 PG 关于表文件命名是一个 uint32 整数保存,采用的是“全局分配,局部存储”的方式,即一个实例下的所有数据库使用一个计数器生成文件号,生成的文件保存在各自库的目录下,分配时,如果当前库下已有同名文件,则尝试下一个,直到没有冲突为止,计数器绕圈后重新开始。所以一个数据库下面支持的文件数理论上最多为 uint32 类型上限,40 亿左右。表,索引,物化视图,toast 表等都使用该计数器统一编号,所以发生文件名重用的情况可能存在,概率不大。


经过优化后,可以明显发现同类场景下主备同步差异由以前的最高 4 百多 GB 下降到了十多 MB,主从同步性能增强了 3W 多倍



四、结语


数据库是所有业务的基石,其每一个微小的改动都会对业务造成极大影响。所以在后端优化时每一步都是小心翼翼,本次优化对 PostgreSQL 数据库本身性能和能力也是一个极大挑战,我们克服了种种问题,完美的适应了业务场景。并且此特性在开源版本中仍未进行修改,后续我们继续优化此类特性,并且计划将提供至社区中。



头图:Unsplash

作者:唐阳

原文:https://mp.weixin.qq.com/s/Us0HE0KmO5rxhj8Le70DJA

原文:三万倍提升,起飞的 PostgreSQL 主从优化实践

来源:云加社区 - 微信公众号 [ID:QcloudCommunity]

转载:著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2021-06-22 08:003266

评论 1 条评论

发布
暂无评论
发现更多内容

开始每周写作计划

M1racle

关于GDB你需要知道的技巧

泰伦卢

c c++ C#

Python3.6.1官方文档练习——初入江湖(一)

小匚

Python python3.x 入门

金融「中台」十宗罪

FinClip

中台 企业中台 业务中台

笔记:《如何系统思考》之如何做到系统思考

wiflish

思维方式

各大公司面试题分类整理

是小毛吖

面试 后端

C++线程池的实现

泰伦卢

c++ C# 线程池

C++定时器的实现

泰伦卢

c c++ C#

业务代码的救星——Java 对象转换框架 MapStruct 妙用

周三不加班

MapStruct 对象转换

开源商业模式促进金融业科技生态的发展

FinClip

开源 金融科技

翻译和产品本地化的区别是什么?

葛仲君

翻译 本地化 全球化 产品开发

当我们谈到ThreadLocal的时候,我们在谈什么?

Jason

Java 多线程 ThreadLocal

【译】【UX】一个页面可以有多个面包屑导航吗?

Yukun

用户研究 UX 面包屑导航

机会是留给不停寻找他们的人,而不是原地等待的人

非著名程序员

程序员 提升认知 机会 行动派

浅谈SpringCloud之服务注册中心Eureka

北漂码农有话说

一个平凡程序员的年度总结

小智

程序员 人生

Clickhouse 性能测试

久吾尔岂

centos7 maven私服自动启动

kcnf

内存对齐

泰伦卢

c c++ C#

css常见问题总结

靖仙

CSS css3

从删库到跑路?

芦苇

产品 职业 产品经理 职业素养 职业道德

从一道面试题来看计算机基础知识的重要性

周三不加班

数组 堆栈 函数栈 函数栈调用

MySQL中 int(11)和 int(10) 到底有没有区别?

周三不加班

MySQL 字符宽度 数据库数据类型

聊聊苹果账号的那些事儿

不要艾特我

iphone

DDD 实践手册(4. Aggregate — 聚合)

Joshua

设计模式 领域驱动设计 架构模式

写作的意义到底是什么

董一凡

写作

面试指南 | 终于要跟大家见面了,我有点紧张。

Apache Flink

大数据 flink 流计算 实时计算

《TCP/IP详解》概述

网瘾少年SEC

TCP 网络协议 IP

写字工具更新史

Bonaparte

学习 读书笔记

Redis 6.0 新特性-多线程连环13问!

牧码哥

redis 多线程 io

一次线上服务高 CPU 占用优化实践

挖坑的张师傅

性能优化 JVM cpu

三万倍提升,起飞的 PostgreSQL 主从优化实践_架构_云加社区_InfoQ精选文章