多数据库Citus集群的维护
译者 | 李睿
审校 | 孙淑娟
本指南适用于数据库管理员(DBA),他们使用Citus管理PostgreSQL节点的内部集群,Citus是PostgreSQL的扩展,可实现水平可扩展性和列式存储。
当人工维护集群成为一项艰巨的工作时,每个数据库管理员(DBA)都会在某个时候达到一个阈值,并且一些自动化解决方案的必要性变得越来越明显。这里将讨论这种自动化解决方案的一个示例。
一、设置
使用以下Citus集群进行分析:
- PostgreSQL 14.2,Citus 10.2。
- Btrfs文件系统上的21个节点(包括一个协调节点),zstd压缩级别为10。
- 集群内36个数据库,遵循“一个租户一个数据库”的原则。
- pg_database_size报告的数据总量为151TB,btrfs fi使用报告的数据量为30TB。
集群中的每个数据库都包含自己独特的表和视图,包括物化、权限和配置参数。
二、特征
在自动化过程中,可以得出自动化解决方案应具备的以下一组特征:
简单:维护过程应该简单、明显、连贯和统一。尽量减少复杂的指令、从不支持的自定义shell脚本和部落知识。
审计:应记录在集群上执行的每个操作,其中包括操作的作者、操作的目的、日期和执行的确切命令。
历史性:当集群从备份中恢复时,应用到集群的一组更改应该很容易重新应用。
三、执行
1.基础
为了解决这些原则,决定使用Flyway数据库迁移工具。它允许通过版本化的迁移脚本对数据库模式进行增量演化。
迁移脚本存储在带有持续交付(CD)机制的Git存储库中,配置为在每次提交时运行迁移。这样,为了将更改应用到集群,数据库管理员(DBA)应该使用迁移SQL脚本创建提交并推送它。
这种设置非常常见,甚至适用于普通PostgreSQL,但对于Citus,有一些细微差别:一些命令应该在集群中的所有节点上执行,有时在特定节点上执行。幸运的是,PostgreSQL和Citus中有足够的机制来涵盖几乎所有用例。
2.单点维护
为了对集群中的数据库进行维护,最好创建一个专用数据库。在进一步的示例中,这将被称为维护。这是一个方便维护相关扩展和功能的地方,但最重要的是它保存了Flyway的历史表,反映了集群中所有数据库的演变,而不是在每个数据库中都有单独的历史表。
将在维护时执行的迁移脚本应该能够创建其他数据库,以及在它们上执行SQL。这就是dblink扩展发挥重要作用的地方:它允许连接到任何其他PostgreSQL服务器,包括localhost,并在那里执行任意SQL。考虑到这一点,创建带有Citus扩展的数据库的迁移脚本如下所示:
SQL
1 CREATE DATABASE new_citus_database; 2 SELECT DBLINK_EXEC('dbname=new_citus_database user=postgres', $remote$ 3CREATE EXTENSION citus; 4 $remote$);
需要注意的一点:数据库不能在事务中创建,因此需要通过脚本配置文件禁用它进行迁移。
在新数据库上创建Citus扩展是不够的。根据文档,为了让Citus工作,有必要:
- 在工作节点上创建同名数据库。
- 在这些数据库上创建Citus扩展。
- 使用集群中每个工作节点的地址调用citus_add_node()。
这很麻烦,因为它需要人工连接到工作人员或专用的Ansible剧本。幸运的是,维护数据库已经包含了从SQL脚本执行此操作所需的所有工具:
SQL
1-- Create database on every worker 2SELECT run_command_on_workers($cmd$CREATE DATABASE new_citus_database;$cmd$); 3 4-- Connect to the fresh database on worker nodes and create the Citus extension 5 WITH citus_workers AS (SELECT node_name FROM citus_get_active_worker_nodes()) 6 SELECT DBLINK_EXEC(FORMAT('host=%s dbname=new_citus_database user=postgres', node_name), $remote$ 7 CREATE EXTENSION citus; 8 $remote$) 9 FROM citus_workers; 10 11 -- Add workers to the fresh database on the coordinator 12 WITH citus_workers AS (SELECT node_name FROM citus_get_active_worker_nodes() ORDER BY node_name) 13 SELECT DBLINK_EXEC('dbname=new_citus_database user=postgres', format($remote$ 14 START TRANSACTION; 15 SELECT citus_add_node('%s', 5432); 16 COMMIT ; 17 $remote$, node_name)) 18 FROM citus_workers;
在这里,DBLINK_EXEC用于连接集群中的所有工作节点,以及协调器。对于DBLINK_EXEC不支持的SELECT语句,有一个解决方法:START TRANSACTION; ... COMMIT;。
可以以类似的方式配置新创建的数据库:
SQL
1 ALTER DATABASE new_citus_database SET WORK_MEM = '256MB'; 2 SELECT run_command_on_workers($cmd$ 3 ALTER DATABASE new_citus_database SET WORK_MEM = '256MB'; 4 $cmd$);
以及创建角色、授予权限和任何其他声明。
3.维护多个数据库
类似的方法用于在一个脚本中管理几个数据库。例如,假设已经创建了另一个数据库,另一个_citus_database,并且有必要在那里创建相同的表和视图。使用CTE可以轻松实现:
SQL
1 WITH databases AS (SELECT * 2 FROM (VALUES ('new_citus_database'), 3 ('another_citus_database')) AS t(db_name)) 4 SELECT DBLINK_EXEC(FORMAT('dbname=%I user=postgres', db_name), $remote$ 5 START TRANSACTION; 6 CREATE TABLE test_table 7 (user_id TEXT, data jsonb); 8 SELECT create_distributed_table('test_table', 'user_id'); 9 CREATE VIEW test_table_view AS SELECT * FROM test_table; 10COMMIT; 11 $remote$) 12 FROM databases;
在实践中,视图的创建应该被提取到一个特殊的可重复脚本中。
而代替CTE,创建实用程序PL/SQL函数是可能的并且更可取。例如,当在同一个实例上存在安装和未安装Citus扩展的数据库时,拥有一个仅在安装了Citus的数据库上运行SQL语句的函数会很方便。此类函数的示例如下所示:
SQL
CREATE OR REPLACE PROCEDURE public.execute_on_databases_with_citus(statement TEXT) LANGUAGE plpgsql AS $$ DECLARE db_name TEXT; BEGIN FOREACH db_name IN ARRAY (SELECT ARRAY_AGG(datname) FROM pg_database WHERE EXISTS(SELECT * FROM DBLINK(FORMAT('dbname=%s', datname), $cmd$SELECT TRUE FROM pg_extension WHERE extname = 'citus'$cmd$) AS t(citus_installed BOOLEAN)) AND datname NOT IN ('template0', 'template1')) LOOP RAISE NOTICE 'EXECUTING ON %', db_name; EXECUTE FORMAT('SELECT * FROM dblink_exec(''dbname=%s'', $_CMD_$%s$_CMD_$);', db_name, statement); END LOOP; END $$;
有了这样的功能,运行ALTER EXTENSION citus UPDATE就很容易了。例如:
SQL
CALL execute_on_databases_with_citus($cmd$ALTER EXTENSION CITUS UPDATE$cmd$);
所描述的管理方式非常灵活,允许数据库管理员(DBA)实现流畅管理体验所需的每一个逻辑。
4.注意事项
根据设置,可能需要配置.pgpass文件以便能够通过dblink连接到工作节点。从历史上看,它是作为Citus安全配置的一部分完成的,但随着Citus11的发布,它发生了变化。
5.综合
以上将前面描述的所有步骤放入迁移脚本中。迁移脚本的顺序在磁盘上可能如下所示:
Shell . └── db └── migration ├── R__test_table_view.sql ├── V1__init.sql ├── V2.0__create_new_citus_database.sql ├── V2.0__create_new_citus_database.sql.conf ├── V2.1__new_citus_database_configuration.sql ├── V3__another_citus_database.sql ├── V3__another_citus_database.sql.conf ├── V4__no_citus_database.sql ├── V5__common_table.sql └── V6__update_citus_extension.sql
有了这样的结构,如果使用CLI工具,现在可以调用flywaymigrate,或者如果喜欢Gradle插件,可以调用./gradlewflywayMigrate-i。将其推送到Git并配置最喜欢的持续集成(CI)/持续交付(CD)工具,例如GitLab或GitHubActions,将获得具有所需特征的解决方案。
四、局限性
以上所描述的方法有一个严重的局限性:由于DBLINK_EXEC的性质,多数据库语句是非事务性的。它要求迁移脚本以某种方式是幂等的:或者通过数据操作语言(DML)语句中的IFNOTEXISTS类子句,或者通过DROP重新创建对象。用Citus对象实现可能有点棘手,但几乎总是存在一种解决方法。例如,可以像这样使表的创建具有幂等性:
SQL
WITH databases AS (SELECT * FROM (VALUES ('new_citus_database'), ('another_citus_database')) AS t(db_name)) SELECT DBLINK_EXEC(FORMAT('dbname=%I user=postgres', db_name), $remote$ START TRANSACTION; CREATE TABLE IF NOT EXISTS test_table (user_id TEXT, data jsonb); DO $$ BEGIN EXECUTE $cmd$SELECT create_distributed_table('test_table', 'user_id');$cmd$; EXCEPTION WHEN SQLSTATE '42P16' THEN RETURN; END;$$; COMMIT; $remote$) FROM databases;
五、结语
这一指南展示了使用Citus集群获得最佳管理体验的基本原则和工具。Flyway工具的功能与Citus、dblink和PL/pgSQL提供的功能相结合,使数据库管理员(DBA)可以轻松管理各种规模的集群。
- 06-16卡巴斯基郑启良:支持信创发展是卡巴斯基的重要使命
- 06-16访问管理是确保现代工作场所安全的的五个关键原因
- 06-16零信任安全的演变:彻底改变网络安全策略
- 06-16GitHub上值得关注的20个网络安全项目
- 06-16英国曼彻斯特大学遭遇网络攻击,机密数据或遭窃!
- 06-16调查表明广告软件推送恶意软件感染了六万多个安卓应用程序
- 06-16微软向美国政府提供GPT的大模型,安全性如何保证?
- 06-16如何保护OT环境免受安全威胁?
- 01-11全球最受赞誉公司揭晓:苹果连续九年第一
- 12-09罗伯特·莫里斯:让黑客真正变黑
- 12-09谁闯入了中国网络?揭秘美国绝密黑客小组TA
- 12-09警示:iOS6 惊现“闪退”BUG
- 12-05亚马逊推出新一代基础模型 任意模态生成大模
- 12-05OpenAI拓展欧洲业务 将在苏黎世设立办公室
- 12-05微软质疑美国联邦贸易委员会泄露信息 督促其
- 12-05联交所取消宝宝树上市地位 宝宝树:不会对公
- 12-04企业微信致歉:文档打开异常已完成修复