
在Ubuntu上维护PostgreSQL最频繁的一个操作就是看服务状态。无论是数据库连不上、应用报错、还是例行巡检“PG服务现在到底是个什么状态”永远是第一个要回答的问题。这篇文章就把我在日常运维里用到的检查方法完整梳理一遍——从基础的systemctl命令到pg_isready健康检查再到写脚本做自动化判定以及服务起不来时的一套排查思路。不管你是刚接触Linux运维的新手还是已经在生产环境摸爬滚打一段时间的开发者这些命令和思路都能直接用上。1. 先搞清安装方式不同装法对应不同检查命令很多人一上来就敲systemctl status postgresql结果提示Unit postgresql.service not found然后就懵了。这个锅不怪命令怪安装方式。同一台Ubuntu机器上PostgreSQL的安装方式不同服务的管理方式完全不一样。检查服务状态之前先花30秒搞清楚自己是怎么装的能省掉后面一大串麻烦。1.1 三种主流安装方式对应完全不同的检查入口最常见的三种安装方式apt包管理器安装、源码编译安装、Docker容器部署。它们对应的服务管理方式几乎可以说是三个世界。用apt安装是最省心的方式。Ubuntu仓库里的postgresql包会自带systemd服务单元安装完成后自动注册开机启动日常启停和状态检查都走systemctl那一套。需要注意apt装的PostgreSQL版本不同服务单元的名字也不同Ubuntu 22.04默认装的是PostgreSQL 14服务名是postgresql14-main.service而不是单纯的postgresql。源码编译安装则是另一回事。你从postgresql.org下载源码自己make install的编译过程根本不会生成systemd服务文件。这种安装方式下服务管理靠的是PostgreSQL自带的pg_ctl工具数据目录的启停、状态查看都由pg_ctl来完成。如果你在源码安装的环境里敲systemctl status postgresql大概率会得到“Unit not found”这不是命令不对而是管理入口不对。Docker方式最特殊。容器里的PostgreSQL进程对宿主机来说就是一个普通进程服务状态要看容器的运行状态。docker ps看容器是否在跑docker inspect看健康检查详情docker logs看容器内日志。宿主机上的systemctl和容器内的pg_ctl都没法直接反映容器服务是否健康得用Docker自己的命令体系。三种方式的检查入口我用一张表理清楚安装方式服务管理入口典型检查命令状态含义来源apt安装systemdsystemctl status postgresql14-mainsystemd单元状态源码编译pg_ctlpg_ctl -D /usr/local/pgsql/data statuspostmaster进程状态Docker容器Docker CLIdocker ps/docker inspect容器运行状态与健康检查1.2 怎么在30秒内确认自己的安装方式判断安装方式其实很简单几个命令一敲就清楚。先看psql命令从哪来which psql如果输出/usr/bin/psql或者/usr/lib/postgresql/14/bin/psql基本可以确定是apt装的。如果路径是/usr/local/pgsql/bin/psql或者你自己编译时指定的目录那就是源码安装。再用dpkg确认一下dpkg -l | grep postgresql有输出说明系统里能查到postgresql相关的软件包记录这通常是apt安装的标志。源码编译安装的话这个命令大概率是空的除非你同时装了postgresql-common之类的辅助包。查Docker更直接docker ps | grep postgres有输出就说明你的PostgreSQL跑在容器里。这类环境还需要注意宿主机上可能同时装了PostgreSQL客户端工具但服务端根本不在宿主机上检查逻辑完全不同。结合进程路径一起看就更清楚了ps -ef | grep postgresapt安装的进程路径一般是/usr/lib/postgresql/14/bin/postgres源码安装则是/usr/local/pgsql/bin/postgres。看到进程路径安装方式就藏不住了。2. systemd体系下最标准的检查姿势如果你的环境是apt安装的这也是绝大多数Ubuntu服务器的情况systemd就是管理PostgreSQL服务的第一入口。这一套命令不搞懂后面排查问题会寸步难行。2.1 systemctl status一条命令看透服务全貌systemctl status postgresql14-main是日常巡检最常用的命令输出信息量很大我把关键字段拆开讲。systemctl status postgresql14-main正常运行时输出大概是这样的● postgresql14-main.service - PostgreSQL Cluster 14-main Loaded: loaded (/lib/systemd/system/postgresql.service; enabled-runtime; vendor preset: enabled) Drop-In: /etc/systemd/system/postgresql.service.d └─override.conf Active: active (running) since Thu 2024-01-18 09:32:11 CST; 3 days ago Main PID: 7321 (postgres) Status: ready Tasks: 8 (limit: 9449) Memory: 82.3M CPU: 15.203s CGroup: /system.slice/postgresql14-main.service ├─7321 /usr/lib/postgresql/14/bin/postgres -D /var/lib/postgresql/14/main ├─7326 postgres: checkpointer ├─7327 postgres: background writer ├─7328 postgres: walwriter ├─7329 postgres: autovacuum launcher ├─7330 postgres: logical replication launcher └─7331 postgres: stats collector这里每行信息都有用。Loaded告诉你服务是否被正确加载、开机自启是否配置Active是核心状态active (running)表示服务正在运行Main PID是PostgreSQL主进程的PID后面追日志、看进程都要用到Status: ready是PostgreSQL自己报告的健康状态比systemd的active更精细CGroup列表里那些子进程就是PostgreSQL的后台进程组能直观看到checkpointer、walwriter这些进程是否都在。Active字段除了active (running)还有几种常见状态Active状态含义常见场景active (running)服务正在运行主进程存活正常状态active (exited)服务启动过一次但主进程已退出一次性任务或启动后立即崩溃inactive (dead)服务已停止手动stop或系统关机failed服务启动失败或运行中崩溃配置错误、端口占用、权限问题2.2 适合脚本和快速判定的三个兄弟命令systemctl status输出太详尽不适合写进脚本自动判断。自动化检查场景下我常用另外三个命令。systemctl is-active是脚本写条件判断的首选systemctl is-active postgresql14-main正常输出active停止输出inactive启动失败输出failed。配合shell的if语句可以直接做状态判定返回码也很有用active时返回0非active状态返回非0。systemctl is-enabled专门查开机自启systemctl is-enabled postgresql14-main输出enabled表示开机自启disabled表示不会自启static表示单元没有安装/卸载逻辑、只能由其他单元触发。生产环境建议确认输出是enabled否则服务器重启后PostgreSQL不会自动拉起这个坑我踩过不止一次。systemctl list-units | grep postgres用来总览所有跟PostgreSQL相关的服务单元systemctl list-units | grep postgres这条命令能一次性列出所有已加载的postgresql单元适合系统里装了多个版本比如同时装了12和14时快速看清哪些集群在运行、哪些已停止。日常启停、重启的命令顺带列一下配合使用才完整sudo systemctl start postgresql14-main # 启动 sudo systemctl stop postgresql14-main # 停止 sudo systemctl restart postgresql14-main # 重启 sudo systemctl reload postgresql14-main # 重新加载配置不中断连接reload和restart的区别值得多说一句reload只是让PostgreSQL重新读取配置文件连接中的会话不受影响适合改了postgresql.conf里不用重启才能生效的参数restart则是杀掉所有进程重新拉起所有连接都会断开。生产环境优先用reload能少挨不少骂。2.3 认识postgresql相关的三个unit文件apt安装PostgreSQL后systemd里会有几个相关的服务单元名字容易搞混postgresql.service总入口单元它本身不做具体启停而是拉起下面所有的版本实例postgresql.service模板单元不指定实例时无法单独使用postgresql14-main.service具体实例单元14是主版本号main是集群名实际管理的是第三个单元前两个是辅助和模板。用systemctl cat postgresql14-main可以查看这个单元的使用哪个配置文件和启动参数systemctl cat postgresql14-main输出里能看到ExecStart那一行具体记录了postgres二进制路径和数据目录位置。确认服务配置对不对这条命令最直接。还有一个好的操作习惯手动修改了/lib/systemd/system/下或/etc/systemd/system/下的服务文件后必须执行sudo systemctl daemon-reload让systemd重新读取单元定义否则服务仍然按旧配置运行。3. 状态检查进阶进程活不等于服务好systemd显示active (running)只能说明PostgreSQL主进程还活着但服务到底能不能正常接受连接、能不能响应SQL查询那是另一码事。我在实际运维中遇到过好几次systemctl看是正常的但应用就是连不上。所以真正有效的状态检查要深入到PostgreSQL自己的反馈层。3.1 pg_isready最快最直接的检查手段pg_isready是PostgreSQL自带的健康检查工具专门用来测试服务器是否接受连接。它不建立完整会话只做连接握手因此开销极小非常适合写进监控脚本。pg_isready最简单的方式不带任何参数默认连接本机的5432端口通过Unix socket检查。如果PostgreSQL在运行且接受连接输出是/var/run/postgresql:5432 - accepting connections如果服务停了或者拒绝连接输出类似/var/run/postgresql:5432 - no response需要指定主机和端口时用-h和-p参数pg_isready -h 127.0.0.1 -p 5432pg_isready的退出码非常讲究写脚本时可以直接依赖退出码含义对应场景0服务器接受连接正常1服务器拒绝连接运行中但pg_hba.conf不允许当前来源连接2服务器无响应服务未启动或网络不通3无法连接连接参数错误或socket目录不存在注意区分退出码1和21是“服务活着但拒绝你”2是“服务根本没起来或者访问不到”。实际排查问题这两个码直接对应不同的下一步动作。我自己的习惯是pg_isready和systemctl is-active搭配用。systemctl看服务进程状态pg_isready看连接可用性两者都通过才认为服务真的“健康”。3.2 用psql查动态视图确认服务真正可用pg_isready能确认“端口在听”但确认不了服务真的能执行查询。要确认数据库真正可用还得连进去跑一条SQL。这是最硬的验证方式sudo -u postgres psql -c SELECT 1;这条命令能成功返回1才能说明数据库接待会话、执行查询的完整链路是通的。注意前面加sudo -u postgres是为了切换到postgres系统用户这是PostgreSQL数据库超级用户默认的peer认证模式下本地socket连接必须用它。服务状态检查常用的三条查询语句SELECT * FROM pg_stat_activity;这条能列出当前所有活动会话。如果服务状态异常但还能连进去可以借这张视图看谁占着连接、谁在跑长事务。SELECT pg_is_in_recovery();返回false表示当前节点是主库返回true表示是只读备库。很多“状态检查发现连不上写请求”的排查第一步就是用这个函数确认角色。SELECT version();确认数据库版本和编译信息排查版本相关问题时会用到。实际工作中这三条SQL配合起来能涵盖绝大多数状态确认场景。但我提醒一句如果服务处于半死状态比如磁盘满了psql可能连验证查询都执行不了此时不要死磕SQL先回退到日志检查。3.3 从系统层面观察端口和进程health check三件套的最后一块是直接从操作系统层面确认端口和进程。这是最底层的事实绕开了所有工具层的“翻译”。确认监听端口ss -tlnp | grep 5432正常输出能看到类似LISTEN 0 200 127.0.0.1:5432 0.0.0.0:* users:((postgres,pid7321,fd7))这条输出能看出监听地址、进程PID。注意127.0.0.1:5432表示只监听本机回环地址外部机器无法直接连接0.0.0.0:5432表示监听所有网络接口。后者一般要配合pg_hba.conf里的访问控制才安全。确认进程存活ps -ef | grep postgres重点看postgres主进程的启动参数-D参数后面的路径就是数据目录。如果主进程不在一堆辅助进程也跟着消失这是服务停止的典型特征。检查Unix socket文件ls -la /var/run/postgresql/PostgreSQL默认在/var/run/postgresql/目录下创建.s.PGSQL.5432这样的socket文件。这个文件存在说明有PostgreSQL实例在运行。一旦这个目录被误删或权限不对即使进程活着本地socket连接也会失败——这也是一个让人挠头的隐藏坑。3.4 把检查命令整合成一段脚本单条命令适合人肉排查但如果每天巡检、或者想在告警平台里做自动探测把检查逻辑写进脚本才是王道。下面是我在生产环境里一直在用的一段检查脚本思路三层检查逻辑清晰可以直接复制改改就能用#!/bin/bash # PostgreSQL健康状态检查脚本 # 三层检查systemd服务状态 - 端口连接性 - SQL查询验证 SERVICE_NAMEpostgresql14-main PG_HOST127.0.0.1 PG_PORT5432 PG_USERpostgres echo 第1层systemd服务状态 systemctl is-active $SERVICE_NAME if [ $? -ne 0 ]; then echo [FAIL] 服务单元未处于active状态 exit 1 fi systemctl is-enabled $SERVICE_NAME | grep -q enabled if [ $? -ne 0 ]; then echo [WARN] 服务未配置开机自启重启后需要手动拉起 fi echo 第2层端口与连接性检查 if pg_isready -h $PG_HOST -p $PG_PORT /dev/null 21; then echo [OK] pg_isready 检测通过 else echo [FAIL] pg_isready 检测失败 exit 2 fi echo 第3层SQL查询验证 if sudo -u $PG_USER psql -h $PG_HOST -p $PG_PORT -tAc SELECT 1; | grep -q 1; then echo [OK] SQL查询验证通过 else echo [FAIL] 无法执行SQL查询服务可能处于异常状态 exit 3 fi echo 检查完成PostgreSQL服务一切正常 这段脚本的执行逻辑是层层递进systemd不活就没必要测端口端口不通就没必要测SQL。每一层失败都有明确的退出码接到监控系统里可以直接根据退出码定位是哪一层出了问题。我建议把这段脚本放在/usr/local/bin/pg_check.sh配合crontab做定时巡检或者交给监控平台定期调用避免每天靠人肉敲命令。4. 服务状态异常时按这套思路排查服务状态不健康无非两类情况压根起不来或者起来了但有问题。下面这套排查思路我按顺序讲每一步都是基于实际排障经验总结的按这个顺序走能少走很多弯路。4.1 第一件事永远先看日志排查PostgreSQL问题日志是最终裁判。不要靠猜先看它自己说了什么。apt安装的PostgreSQL日志通常在/var/log/postgresql/postgresql-14-main.log查看最近的日志sudo tail -n 100 /var/log/postgresql/postgresql-14-main.log如果系统用journald做了统一收集也可以直接查systemd日志sudo journalctl -u postgresql14-main -n 50 --no-pager日志里出现的关键词直接对应问题类型日志关键词大概率问题FATAL: could not open ...数据目录/配置文件不可读Permission denied权限不足多半是数据目录属主不对could not bind IPv4 socket端口被占用invalid value for parameter ...postgresql.conf里配置项写错database system was not properly shut down上次非正常关机需要恢复out of memory内存不足或参数设置过大日志的时间戳要和故障时间对上定位到故障发生的那一段往往问题原因直接写在里面。4.2 按顺序排查权限、数据目录和磁盘权限和数据目录的问题比想象中常见。尤其是手工移动过数据目录、或者从快照恢复、迁移过服务器的情况下属主经常不对。检查数据目录属主ls -ld /var/lib/postgresql/14/main sudo stat /var/lib/postgresql/14/main数据目录的属主必须是postgres用户和postgres组权限通常是700。如果属主是root或者别的用户PostgreSQL启动时会因为无法访问数据目录直接失败。磁盘空间是另一个高频排查点。数据库服务在磁盘写满时表现很怪可能进程还在、日志都说正常但就是无法执行写操作df -h重点看/和/var两个挂载点的使用率。使用率到100%时PostgreSQL所有写事务都会失败此时需要尽快清理空间哪怕是先删掉归档日志腾出余量。4.3 处理配置语法错误和端口冲突配置改坏了导致服务起不来是新手最容易犯的错。postgresql.conf里写错一个参数名、一个数值类型不对都会导致启动失败。服务失败后先直接看日志有没有告诉你哪个配置项不对sudo tail -n 20 /var/log/postgresql/postgresql-14-main.log如果日志写得不够详细可以用PostgreSQL自带的配置测试模式提前检验sudo -u postgres /usr/lib/postgresql/14/bin/postgres -D /var/lib/postgresql/14/main -C log_min_messages或者直接以单用户模式试启动看能否正常加载配置sudo -u postgres /usr/lib/postgresql/14/bin/postgres --single -D /var/lib/postgresql/14/main端口冲突也好办用ss看是什么进程占了5432sudo ss -tlnp | grep 5432如果是别的服务占了端口可以改PostgreSQL的port参数也可以停掉占用进程。这个没什么技术难度难在发现是这个问题——所以我在前面反复强调第一步要看日志和查端口。4.4 资源限制与系统层因素PostgreSQL在系统资源不足时也会“状态异常”。最典型的是内存不够被OOM killer干掉。遇到服务运行一段时间后突然死掉先看系统日志sudo journalctl -k | grep -i oom sudo dmesg | grep -i oom有OOM记录的话就要审视PostgreSQL的shared_buffers、work_mem这些内存参数是不是设置过大特别是跟机器实际内存不匹配的时候。shared_buffers通常建议不超过物理内存的25%太大反而引起性能问题和内存竞争。文件句柄限制也可能导致“服务活着但不干活”。检查进程的nofile限制cat /proc/7321/limits | grep open files输出Max open files如果是1024这种低值数据库在高并发场景下会频繁报“too many open files”这时需要调整systemd服务单元的LimitNOFILEsudo systemctl edit postgresql14-main写入[Service] LimitNOFILE65535然后daemon-reload加restart生效。5. 常见问题速查与避坑经验把高频问题和排查方法放在一起查起来最方便。下面这张表是我根据日常运维整理的真实问题清单场景覆盖从刚装完到上线运行整个周期。5.1 高频问题速查表现象可能原因处理方法Unit postgresql.service not found服务名输错或源码安装没有systemd单元确认版本用postgresql14-main源码装用pg_ctlActive: failed且日志报端口被占用5432端口被其他进程占用ss -tlnp | grep 5432定位进程改配置或停进程服务active但应用连不上监听地址只绑定了127.0.0.1修改listen_addresses注意同步改pg_hba.conf防火墙规则psql提示Connection refused服务未启动或端口/IP配置不对先查systemctl状态再查日志FATAL: role xxx does not exist数据库角色未创建用postgres超级用户CREATE ROLE或CREATE USERFATAL: database xxx does not exist数据库未创建createdb创建目标库服务启动后秒退数据目录损坏或配置重大错误看日志定位必要时恢复备份服务器重启后PG没有自动启动开机自启未启用systemctl enable postgresql14-main磁盘满导致无法写入数据盘空间耗尽清理WAL、归档日志、旧备份扩容后重启服务OOM导致进程被kill内存参数过大或系统内存不足看dmesg确认调小shared_buffers/完善swap5.2 几个容易踩的坑第一个坑sudo -u postgres被遗忘。很多人喜欢直接psql -U postgres然后被peer认证拒绝。Ubuntu上PostgreSQL默认的本地认证方式是peer意思是操作系统用户名必须和数据库角色名一致。所以只有sudo -u postgres切换到postgres系统用户本地psql才能免密直连。第二个坑版本升级后服务名变了。从PostgreSQL 12升到14后服务名从postgresql12-main变成了postgresql14-main。如果你的脚本还写死systemctl restart postgresql12-main实际重启的是老版本的服务新版本压根没动。升级后第一件事就是把所有脚本里的服务名同步更新。第三个坑/var/run/postgresql/目录被误删。你手动rm -rf /var/run/postgresql/再重建时如果目录属主不是postgres、权限不是2775PostgreSQL就创建不了socket文件本地连接全部失败。这个目录在tmpfs上重启后会自动重建但运行中删了就得手动恢复正确属主chown postgres:postgres /var/run/postgresql chmod 2775 /var/run/postgresql。第四个坑把systemctl reload当成万能热更新。reload确实能加载大部分postgresql.conf参数但有些参数比如shared_buffers、listen_addresses必须重启才能生效。改配置前先翻文档确认参数类别的习惯一定要养好不然改了没生效白忙活一场。我个人在实际运维中的体会是检查服务状态不能只依赖一条命令把“进程层、连接层、查询层”三层检查串起来才能对PostgreSQL的状态心里有底。另外定时巡检脚本一定要尽早配上人肉查状态既低效又容易漏让机器替你做这件事你才有时间处理真正需要人判断的麻烦。最后分享一个小技巧每次排查完问题把根因和解决过程记到自己的运维笔记里PostgreSQL的坑其实翻来覆去就那么几类记过一轮之后再遇到类似问题基本就是查表的事了。