Azure Function实现Postgres分区表定时Blob备份与旧分区清理的方法
完全可以通过编程方式跑通全流程,不用依赖Azure Data Migration Service,也不需要引入复杂的外部工具,基于你已经在用的Npgsql包+Azure Blob官方SDK就能搞定。
核心执行步骤
整个流程完全匹配你的业务规则:先备份过期的天维度分区,校验备份有效后再分离删除分区,具体操作如下:
第一步:识别要处理的过期分区
写个简单的SQL通过Npgsql查询Postgres的系统元数据,拉取这张时序主表的所有天级子分区,筛出已经超出保留周期的旧分区:-- 替换成你实际的主表名、保留的起始分区名即可 SELECT child.relname AS partition_name FROM pg_inherits inherits JOIN pg_class child ON inherits.inhrelid = child.oid JOIN pg_class parent ON inherits.inhparent = parent.oid WHERE parent.relname = '你的时序主表名' -- 按你分区的命名规则筛选,比如分区统一命名为xxx_20240501,直接字符串对比就行 AND child.relname < '你的主表名_保留周期的起始日期后缀';拿到分区列表后加一层硬校验,只处理符合命名规则的旧分区,避免误删数据。
第二步:流式导出旧分区数据(完全适配Azure Postgres的权限限制)
Azure托管的Postgres不开放普通用户的服务器端文件写入权限,没法直接执行COPY 表 TO 服务器本地文件的命令,直接用你已经引入的Npgsql自带的客户端COPY接口就行:
调用Npgsql连接的BeginTextExport方法,执行COPY (SELECT * FROM 待处理分区名) TO STDOUT,把分区数据直接流式拉到Azure Function的进程内存里,不需要在数据库服务器上存任何临时文件。导出的时候可以直接用GZip流包裹输出流,自动压缩备份文件,节省Blob存储成本。第三步:直传Azure Blob Storage
不用把导出的大文件暂存到Function的临时磁盘,直接把Npgsql输出的COPY流对接Azure.Storage.Blobs SDK的流式上传接口,从数据库导出到Blob上传全程连续流式传输,低内存占用,就算单个分区有几百万行数据也不会触发Function的内存限制。
Blob命名直接对应分区名,比如backup/partitions/time_series_20240501.csv.gz,后续找备份的时候一眼就能定位。第四步:校验无误后删旧分区
上传完成后先做两层校验:一是对比数据库里统计的分区总行数,和导出过程中记录的导出行数一致;二是试读一下上传到Blob的文件,确认内容完整没损坏。
校验过了再执行分区清理命令,通过Npgsql执行就行,因为是独立分区的删除操作,整个过程毫秒级完成,不会影响主表的在线查询:ALTER TABLE 你的时序主表 DETACH PARTITION 待处理分区名; DROP TABLE 待处理分区名;
实际落地的注意点
- 权限要求很低:数据库连接账号只需要对应分区的
SELECT权限、主表的ALTER权限就能跑通全流程,不需要Azure Postgres的管理员权限。 - 执行节奏刚好匹配:用Azure Function的定时触发器设成每天凌晨跑一次,刚好对应天分区的备份周期,而且旧分区没有实时写入,跑备份任务完全不会影响线上业务。
- 额外依赖极少:整个流程不需要在Function环境装pg_dump、psql这些额外的Postgres客户端工具,核心导出逻辑全靠你已经引入的Npgsql就能实现,只需要加一个
Azure.Storage.Blobs的NuGet包对接Blob存储就行。
内容的提问来源于stack exchange,提问作者Yash Mochi

