暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

浅析systemd管理postgres

PolarDB 2025-04-28
250

浅析systemd管理postgres

背景

高可用能力是公认的数据库必备能力,也是一款数据库产品的核心竞争力之一。资源充沛的时候,我们可以配置一主一备或者一主多备,通过主备复制同步数据,实现故障场景的快速切换。再结合代理,能够自动实现读写均衡和对主节点的跟踪,这似乎是一个较为完美的高可用方案。

但是,切换不是一个简单的动作,对于pg来说还要维护新的流复制关系。一主多备场景下,主节点的切换需要每个备库重新配置primary_info等参数并重启。主备存在延迟情况下,切换还会丢失数据。虽然可以配置强同步复制模式,但是对性能影响较大,同时备库挂掉还会影响主库可用。另外,虽然备库可以作为只读节点提供服务,但是由于复制延迟等原因,难以保证全局数据一致性,只读节点的利用率很难提升,浪费了很多资源。更极端的场景下,有时候受条件所迫只有一台主机,那主备切换的高可用方案就毫无用武之地了。

综上所述,主备切换不是完美的方案,给pg的运维增加了很多难度,如果能在故障场景下不需要切换就快速原地恢复数据库,那无疑是更好的选择。

自然地我们想到了用一个守护进程来管理postgres,能在postgres主进程退出的时候重新拉起数据库,最好能在机器重启之后也能把数据库自动启动。 systemd 就是其中一个方案。

systemd

systemd是Linux的系统工具,它的设计目标是为系统的启动和管理提供一套完整的解决方案。 根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。为了用systemd管理postgres,我们可以完成以下几步:

Step 1: 创建 **systemd**
 单元文件

首先,创建一个新的 systemd
 单元文件。这个文件通常会被放在 /etc/systemd/system
 目录下。

sudo nano /etc/systemd/system/postgresql.service

文件中添加以下内容:

[Unit]
Description=PostgreSQLdatabaseserver
After=network.target

[Service]
Type=forking
User=postgres
Group=postgres

# Environment variables
Environment=PGDATA=/var/lib/postgresql/data

# Commands to manage the service
ExecStart=/usr/pgsql/bin/pg_ctlstart-D${PGDATA}-l${PGDATA}/logfile
ExecStop=/usr/pgsql/bin/pg_ctlstop-D${PGDATA}-s-mfast
ExecReload=/usr/pgsql/bin/pg_ctlreload-D${PGDATA}

# Restart settings
Restart=on-failure
RestartSec=5

# Limits
LimitNOFILE=65536
LimitNPROC=65536

[Install]
WantedBy=multi-user.target

Step 2: 重新加载 **systemd**
 配置

保存并关闭文件后,重新加载 systemd
 配置:

sudo systemctl daemon-reload

Step 3: 启动并启用 PostgreSQL 服务

使用以下命令启动并启用 PostgreSQL 服务:

# 启动服务
sudo systemctl start postgresql

# 设置为开机自启
sudo systemctl enable postgresql

Step 4: 检查服务状态

你可以使用以下命令检查服务的状态,确保它正在运行:

sudo systemctl status postgresql

示例解释

  • [Unit] 部分:

    • Description
      : 描述功能。

    • After=network.target
      : 确保网络服务启动后才启动此服务。

  • [Service] 部分:

    • Type=forking
      : 指定服务会在启动时派生一个新的进程。

    • User
       和 Group
      : 指定运行该服务的用户和组,这里设置为 postgres

    • Environment
      : 定义环境变量,指定数据目录位置。

    • ExecStart
      : 启动服务的命令。

    • ExecStop
      : 停止服务的命令。

    • ExecReload
      : 重新加载配置的命令。

    • Restart
       和 RestartSec
      : 指定服务在失败后的重启策略。

    • LimitNOFILE
       和 LimitNPROC
      : 设置打开文件和进程的限制。

  • [Install] 部分:

    • WantedBy=multi-user.target
      : 指定该服务在多用户模式下启动。

这个示例假设 PostgreSQL 安装在 /usr/pgsql/bin/
 目录下,数据目录为 /var/lib/postgresql/data
。请根据你的实际情况调整路径。

通过这个 systemd
 配置文件,你可以使用 systemctl
 命令方便地管理 PostgreSQL 服务。例如:

  • 启动服务sudo systemctl start postgresql

  • 停止服务sudo systemctl stop postgresql

  • 重新加载配置sudo systemctl reload postgresql

  • 查看状态sudo systemctl status postgresql

缺点

  1. systemd 将被守护的程序进程维护在其 cgroups 层级结构中,一旦进程退出可以重新拉起;但是这要求被守护的程序只能被 systemd 来启动和停止,一旦它被其他程序重启,就脱离了守护。而用户习惯使用 pg_ctl 来管理数据库,一旦用户使用 pg_ctl 停止或者重启了数据库,就会导致数据库守护状态与实际运行状态不一致,从而脱离守护。最好有一个支持通过 pid 文件(如 pg 的 postmaster.pid)来守护被托管程序的方案。(尽管 systemd 也支持指定 PIDFile,但是它不以此作为守护状态的依据,仅会在停止被守护程序的时候清理它)

  2. 因为在 docker 容器中使用 systemd 需要特权模式(privileged)启动,但是开启了 privileged 的容器可以访问宿主上所有设备(几乎享有宿主上运行的进程的所有访问权限),这显然不符合一般的安全策略规范,如果为了安全考虑,那systemd的确不是一个在主机和容器场景下通用的组件守护方案。

supervisord

此外,基于开源项目 ochinchina/supervisord也可以实现以上需求,主要优势与缺点如下:

优势

  1. 既支持如 systemd 的子进程守护,又提供了 pidproxy 工具来支持对 pid 文件中的进程号进行状态守护(兼容 postmaster.pid 格式)

  2. 使用 golang 实现,可以通过交叉编译支持多 CPU 架构/操作系统、容器中使用无需特权模式、对安装环境无依赖、体积较小。

  3. 通过对其中 supervisord 和 pidproxy 组件的修改,可以支持一键停止 supervisord 和它托管的进程、兼容

缺点

  1. supervisord 本身没有被守护,被误杀后进程会脱离守护。

  2. 用户机器重启后程序无法自动拉起,这一点也非常致命,尤其是对于经常有重启需求但又不想手动运维的用户。

  3. supervisor需要额外的安装,而systemd是Linux本身提供的工具。

总结

对于云上数据库来说,只要探活机制足够可靠,守护进程+主备切换是能最快恢复的办法,也能覆盖更对异常场景。毕竟大部分故障不是通过重启就能解决的,机器断电、宕机、网卡故障、磁盘写满,太多的故障场景都需要备库来容灾。云厂商一般都能提供强大的管控能力,切换后流复制、节点重建等等也都不需要使用者关注。但是对于线下小型数据库系统来说,systemd等提供的守护能力也不失为日常运维的简单有效方案。很难找到完美的高可用方案,适合自身需要的就是好方案。


文章转载自PolarDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论