很多老项目还在 CentOS 7 上跑着,业务要上 PostgreSQL,第一件事就是安装。这事看着简单,但我在实际环境里见过太多翻车现场:装完系统默认源里的 9.2 老版本、初始化没做直接启动失败、远程连不上结果查了半天是防火墙……这篇就把 CentOS 7 从零装 PostgreSQL 15 的完整路子捋一遍,顺带把初始化、远程访问、权限配置、日常维护这些容易踩坑的地方都讲清楚。不管你是刚接触 Linux 的新手,还是要给老生产环境补一套数据库的老手,这篇文章都适用。我会按真实落地的顺序来写:先讲为什么选官方源、再讲安装和初始化、然后讲配置和连接、最后讲排错和调优,保证每一步都有可复现的命令和参数。
1. 安装方式选型与版本选择
1.1 为什么不要用 CentOS 7 自带的 PostgreSQL
CentOS 7 的默认 yum 源里其实是有 PostgreSQL 的,直接yum install postgresql-server就能装上。但问题在于,系统源里的版本停留在 PostgreSQL 9.2,这个版本官方早就停止维护了,连安全补丁都不再更新。除非你只是临时在本地验证一个极度老旧的业务,否则用它上新项目就是在给自己埋雷。
还有一点,CentOS 7 发行于 2014 年,它自带的 PostgreSQL 9.2 是那个年代的产物,很多现代数据库特性都没有。比如 9.2 不支持JSONB的高效索引,不支持CREATE EXTENSION里一堆常用扩展,连scram-sha-256密码认证协议都没有,安全性和功能性和现在的 15、16 完全不是一个量级。所以生产环境装 PostgreSQL,第一原则就是:绕过系统默认源,使用 PostgreSQL 官方提供的 PGDG 源。
1.2 三种安装方式对比
我在不同环境里用过三种主流安装方式,简单整理一下各自的优缺点:
| 安装方式 | 版本新旧 | 依赖管理 | 安装时长 | 维护成本 | 适合场景 |
|---|---|---|---|---|---|
| PGDG 官方 yum 源 | 新,可选 10 到 17 | yum 自动解决 | 几分钟 | 低,yum upgrade 即可更新 | 绝大多数生产环境 |
| 系统默认 yum 源 | 很旧(9.2) | yum 自动解决 | 几分钟 | 低但版本太老 | 仅测试或特殊兼容需求 |
| 源码编译安装 | 自己选版本 | 手动解决 | 30 分钟以上 | 高,升级麻烦 | 需要定制编译参数或离线环境 |
第三种源码编译在某些离线内网环境确实被逼用过,编译 PostgreSQL 本身不难,难的是后续维护。每次打补丁、升小版本都要重新 configure、make、make install,还要自己处理 systemd 服务文件,效率很低。所以只要环境能联网,我都优先用 PGDG 源,这也是社区和官方推荐的标准做法。
1.3 版本具体怎么选
PGDG 源里同一时间会有多个大版本共存,装 15 就装postgresql15-server,装 14 就装postgresql14-server,互不干扰,安装路径也区分开,比如 15 装在/usr/pgsql-15,14 装在/usr/pgsql-14。
选择版本时我一般看两个点:一是业务代码兼容性,如果你的 SQL 用到了某个老版本才有的语法,先确认目标版本是否支持;二是生态支持周期,PostgreSQL 每个大版本大概有 5 年维护期,尽量选还在维护窗口内的版本。以当前时间点来说,14 和 15 都属于成熟稳定且用户量非常大的版本,教程多、踩坑资料全,作为新装数据库完全够用。如果你对未来特性有强需求,再考虑更新的版本,但最好不要在生产环境用刚发布的大版本,等几个小版本补丁后再上会更稳妥。这篇文章后面的命令都以 15 为例,其他版本把数字换成对应的版本号即可。
2. CentOS 7 安装 PostgreSQL 15 完整实操
2.1 配置 PGDG 官方 yum 源
安装 PostgreSQL 的第一步是配置官方源。PGDG 为 RHEL/CentOS 系提供了打包好的 repo RPM,装上之后会自动在/etc/yum.repos.d/下生成pgdg-redhat-all.repo文件。执行命令:
sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm这里有个关键点:EL-7 和 EL-8、EL-9 的 repo RPM 不能混用。CentOS 7 必须用EL-7,如果你把 EL-8 的包装上去,yum 会报依赖错误或者干脆识别不到可用的 PostgreSQL 版本。装完可以用yum list available | grep postgresql15确认一下源是否生效,能列出postgresql15.x86_64、postgresql15-server.x86_64这些包就说明源没问题。
另外提醒一句,如果你的服务器访问外网较慢,yum 安装时可能会卡在下载阶段。这种情况可以先给系统 yum 配置好镜像源,再装 PGDG 源,同时用yum clean all && yum makecache刷新缓存。PGDG 源本身没有国内官方镜像,但通过合理的 yum 加速策略,实际下载速度也能接受。
2.2 安装服务端和扩展包
源就绪后,执行安装命令:
sudo yum install -y postgresql15-server postgresql15-contrib很多人会问为什么一定要装postgresql15-contrib。简单说,contrib 包里包含了一堆常用扩展和工具,比如pg_stat_statements(慢 SQL 分析必备)、dblink、postgres_fdw、pgcrypto等。如果不装这个包,后面创建扩展时会直接报extension "xxx" is not available。虽然可以按需单独补装,但既然是一次性安装,直接带上 contrib 省得后面麻烦。
安装完成后验证一下版本:
/usr/pgsql-15/bin/postgres --version正常情况下会输出类似postgres (PostgreSQL) 15.x的信息。同时也看一下 systemd 服务是否已经生成:
systemctl list-unit-files | grep postgresql你会看到postgresql-15.service,注意这个服务名带版本号,不是通用的postgresql.service。很多人初始化完成后执行systemctl start postgresql,结果提示找不到服务,就是因为没带版本号。
2.3 初始化数据库目录
在 CentOS 7 上通过 yum 安装 PostgreSQL 后,数据库不会自动初始化,也不会自动启动,必须手动执行初始化脚本。这是和 Debian/Ubuntu 系最大的区别,Ubuntu 上安装包会在安装时自动建好 cluster,CentOS 7 不会。
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb这条命令做的事情是什么?它会在默认数据目录/var/lib/pgsql/15/data下执行initdb,生成postgresql.conf、pg_hba.conf、PG_VERSION等基础文件,并创建postgres超级用户。执行成功后输出末尾会有Success. You can now start the database server.的提示。
如果这一步报错,最常见的原因是/var/lib/pgsql/15/data目录已经存在且不为空,或者目录属主不是postgres用户。解决办法是先清掉残留目录再初始化:
sudo rm -rf /var/lib/pgsql/15/data sudo /usr/pgsql-15/bin/postgresql-15-setup initdb切记不要自己去mkdir一个 data 目录然后手工 initdb,因为 systemd 服务文件里配置的目录路径是固定的/var/lib/pgsql/15/data,你随便换地方会导致服务启动时找不到数据目录。
2.4 启动服务并设置开机自启
初始化完成后,启动服务:
sudo systemctl enable postgresql-15 sudo systemctl start postgresql-15 sudo systemctl status postgresql-15enable是设置开机自启,start是立即启动。status查看运行状态,看到active (running)就说明服务正常。这时检查端口监听情况:
ss -lntp | grep 5432正常会看到 PostgreSQL 默认监听在127.0.0.1:5432。如果只想本机访问,这样已经够了;要远程连接,继续看后面的配置。
2.5 初次登录并设置密码
PostgreSQL 安装后默认会创建一个名为postgres的系统用户,同时数据库中也有一个同名的超级用户。CentOS 7 的 PostgreSQL 默认配置下,本地 socket 连接走的是peer认证,意思是操作系统用户名和数据库用户名必须一致。
所以第一次登录要切换到 postgres 系统用户:
sudo -i -u postgres psql看到postgres=#提示符就进入 psql 交互界面了。先给 postgres 用户设置一个强密码:
ALTER USER postgres WITH PASSWORD '你的强密码';然后退出 psql,退回到普通用户:
\q exit这里我强烈建议密码用 16 位以上、包含大小写字母数字和特殊字符的强密码。数据库超级用户的权限非常大,一旦泄露整个库都完了。后面创建业务账号时不要复用这个密码,每个账号独立密码。
3. 核心配置:远程访问与账号权限管理
3.1 修改 postgresql.conf 关键参数
PostgreSQL 的主配置文件位于/var/lib/pgsql/15/data/postgresql.conf。默认情况下 PostgreSQL 只监听本机回环地址,要支持远程访问,需要修改listen_addresses参数。用 vim 打开配置文件:
sudo vim /var/lib/pgsql/15/data/postgresql.conf找到#listen_addresses = 'localhost'这一行,取消注释并修改为:
listen_addresses = '*'如果想指定多个 IP,可以写成'192.168.1.10,192.168.1.11';如果只需要外网访问这一个实例,'*'更省事,配合 pg_hba.conf 的访问控制能保证安全。
除此之外,这个文件里还有几个参数我建议顺手确认一下。port = 5432是默认端口,一般不用改。max_connections建议根据机器内存和业务并发量调整,单机内存充裕的话先保持默认 100 也能跑,等压测后按需调。password_encryption = scram-sha-256在 PostgreSQL 15 里默认就是这一项,比老的 md5 安全得多,确认是这个值就不要动。
修改完需要重启服务才能让listen_addresses生效:
sudo systemctl restart postgresql-15注意区分restart和reload。改listen_addresses、port这类参数必须 restar,而该pg_hba.conf里的认证规则只需要 reload,reload 不会断开现有连接,生产环境更友好。
3.2 配置 pg_hba.conf 客户端认证规则
如果说 postgresql.conf 管的是“数据库监听哪里”,那 pg_hba.conf 管的就是“谁能连、怎么验证身份”。这个文件的完整路径是/var/lib/pgsql/15/data/pg_hba.conf。
默认内容的最后几行一般是:
host all all 127.0.0.1/32 ident host all all ::1/128 ident这两个配置表示只允许本机通过 IPv4 和 IPv6 连接,认证方式是ident。要允许远程连接,需要追加一行规则,比如允许所有网段通过密码连接:
host all all 0.0.0.0/0 scram-sha-256但站在安全性角度,我不建议你直接写0.0.0.0/0。更合理的做法是只放行业务所在网段,比如:
host all all 192.168.1.0/24 scram-sha-256这条规则的意思是:来自192.168.1.0/24网段的客户端,可以访问所有数据库和所有用户,认证方式为scram-sha-256。如果你只想让某个特定 IP 访问,就把网段写成1.2.3.4/32。
认证方式这里绝对不要配trust。trust 的意思是“免密信任”,只要网络能到,任何人都能直接以任意用户名登录,这是生产环境的大忌。scram-sha-256是目前 PostgreSQL 最安全的密码认证方式,明文密码不会在网络上传输,推荐使用。
改完执行 reload 使配置生效:
sudo systemctl reload postgresql-15然后从另一台机器试连一下:
psql -h 数据库服务器IP -p 5432 -U postgres -d postgres能连上也别高兴太早,防火墙和安全组没放行一样会超时,这个我放在排查部分细说。
3.3 创建业务数据库和专用账号
实际项目中我从来不用 postgres 超级用户跑业务。正确的姿势是每个应用单独建用户、单独建库,权限最小化。这样做的好处是:即使某个应用的数据库账号泄露,攻击者也就只能搞这一个库,无法波及其他业务。
用 postgres 账号登录 psql 后执行:
CREATE USER myapp WITH PASSWORD '应用专用强密码'; CREATE DATABASE mydb OWNER myapp;这里CREATE DATABASE ... OWNER myapp指定了数据库属主是 myapp,这样 myapp 用户对自己的库有完整权限。如果需要额外授权,可以再执行:
GRANT ALL PRIVILEGES ON DATABASE mydb TO myapp;注意,PostgreSQL 里GRANT ... ON DATABASE只授予数据库级别的权限,比如建 schema、建表的权限,并不包括表级权限。如果应用需要用扩展,还需要在目标库里创建扩展。比如用 myapp 登录后:
psql -h 127.0.0.1 -U myapp -d mydb创建扩展:
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;这种“一应用一库一账号”的模式我用了好几年,最大的感受是排查问题容易。哪个库连接数爆了、哪个库把磁盘写满了,一看就知道是哪个应用的锅,不用一个个查。
3.4 防火墙与安全组放行
CentOS 7 默认使用 firewalld 防火墙,即使数据库配置正确、pg_hba.conf 也放行了,防火墙没开端口一样连不上。执行命令放行 5432 端口:
sudo firewall-cmd --permanent --add-port=5432/tcp sudo firewall-cmd --reload--permanent表示永久生效,--reload让规则立即生效。用firewall-cmd --list-ports可以确认端口是否放行成功。
还有一点经常被人忽略:如果你的数据库部署在云服务器上,光改服务器内部防火墙没用,云平台的安全组也必须放行 5432 端口。安全组相当于云服务器外层的流量关卡,里面的防火墙层层放行后外面才能进来。很多时候远程连不上,排查到最后发现是安全组没配,这个坑踩一次就长记性了。
4. 常见安装与连接问题排查实录
4.1 systemctl 启动失败:Data directory 不存在
这是 CentOS 7 上最经典的起步问题。安装完直接systemctl start postgresql-15,报错信息里会提到data directory "/var/lib/pgsql/15/data" does not exist。
原因就是前面强调的:CentOS 7 的 RPM 包装完不会自动初始化数据库目录。解决办法就是先执行初始化命令:
sudo /usr/pgsql-15/bin/postgresql-15-setup initdb初始化完成后再次启动服务即可。如果你在非默认路径建了 data 目录,然后直接pg_ctl start -D /你的目录启动,systemd 里是能起,但重启服务器后服务拉不起来,因为 systemd 服务单元依然指向默认路径。所以非必要不要自定义 data 目录,即使自定义也要同步修改 systemd 单元文件,这个操作对新手来说很容易出问题。
4.2 psql: FATAL: Ident authentication failed for user "postgres"
如果你尝试用psql -U postgres直接登录,在默认配置下很可能看到这个报错。
原因是默认 pg_hba.conf 里本地连接走的是ident或peer认证,要求当前 Linux 系统用户和 PostgreSQL 用户名一致。你当前是 root 或者普通用户,数据库里却想以 postgres 身份登录,认证就失败了。
解决办法有两种。第一,按我之前写的,用sudo -i -u postgres切换到 postgres 系统用户再执行psql,这是最稳妥的方式。第二,把 pg_hba.conf 中local all all和host all all 127.0.0.1/32的认证方式改成scram-sha-256,然后 reload,之后用密码登录。无论哪种方式,都建议设置好 postgres 用户的数据库密码,避免密码为空时带来的安全隐患。
4.3 远程连接超时或 Connection refused
这个问题排在所有 PostgreSQL 远程访问故障第一位。我建议按以下顺序排查:
# 第一步:确认数据库进程是否在运行 systemctl status postgresql-15 # 第二步:确认监听地址和端口 ss -lntp | grep 5432如果 ss 输出里显示的是127.0.0.1:5432,说明listen_addresses没改或者没重启服务。如果显示0.0.0.0:5432,说明监听没问题。
# 第三步:确认 pg_hba.conf 是否放行了客户端网段你可以先用psql -h 127.0.0.1 -U myapp -d mydb在本机测一下,本机能连说明数据库侧配置正常。接下来就是防火墙:
sudo firewall-cmd --list-ports最后确认云安全组有没有放行 5432。我遇到过一个案例,所有配置都检查了两遍,最后发现是云平台安全组只放行了 80 和 443,数据库端口根本没放行。客户端表现为 telnet IP 5432 直接超时,而不是明确的拒绝。
4.4 yum 安装源报错或找不到包
装 PGDG 源后执行yum install报“No package postgresql15-server available”,多数是因为 PG 源没有正确加载。依次检查:
yum repolist | grep pgdg看输出里有没有pgdg15、pgdg-common等仓库。如果为空,重新安装 repo RPM;如果有多个 pgdg 仓库但不确定启用了哪些,可以查看/etc/yum.repos.d/pgdg-redhat-all.repo,把不需要的仓库临时禁用:
yum install --disablerepo=pgdg14 --enablerepo=pgdg15 postgresql15-server还有一个坑,如果你用了第三方源比如 EPEL,可能存在包冲突,安装时加--skip-broken或--setopt=obsoletes=0有时能绕过去,但根本解法还是理清各源的关系。另外,部分内网环境的 yum 代理配置有问题,会导致下载失败,这种时候yum clean all && yum makecache试试,不行就检查/etc/yum.conf里的 proxy 配置。
4.5 SELinux 拦截导致启动或连接异常
CentOS 7 默认开启 SELinux,如果没接触过这个机制,踩坑时会觉得非常莫名其妙:服务起来了,端口也监听了,但外部就是连不上,或者写入某些日志文件时报权限错误。
先用这条命令看有没有被 SELinux 拦截:
sudo ausearch -m avc -ts recent如果输出类似avc: denied { name_connect }的信息,说明是 SELinux 在拦截。一个常见的场景是你把 PostgreSQL 端口改成了 5433 或 5432 以外的自定义端口,SELinux 默认只放行 5432。这时候需要手动添加端口规则:
sudo semanage port -a -t postgresql_port_t -p tcp 5433semanage命令在policycoreutils-python-utils包里,如果没有可以先yum install -y policycoreutils-python-utils。我不建议直接setenforce 0关闭 SELinux,除非你确认这台机器不跑重要业务。同样的配置在开启 SELinux 的机器上没问题,到了另一个环境不行,多半就是 SELinux 策略差异,按这个思路排查不会错。
4.6 常见问题速查表
为了便于日常参考,我把安装和连接阶段常见问题汇总成一张速查表:
| 现象 | 可能原因 | 快速解决办法 |
|---|---|---|
| systemctl start 失败,data directory does not exist | 未初始化数据库 | 执行 postgresql-15-setup initdb |
| psql 登录报 Ident authentication failed | pg_hba.conf 认证方式不匹配 | 使用 sudo -i -u postgres 后再 psql,或改认证方式为 scram-sha-256 |
| 远程连接超时 | 防火墙/安全组未放行 | firewall-cmd 放行 5432,并检查云安全组 |
| 远程连接拒绝 | 未监听外部地址 | 修改 listen_addresses = '*' 并重启服务 |
| yum 找不到包 | PGDG 源未启用 | 检查 pgdg repolist,用 --enablerepo 指定 |
| 自定义端口连不上 | SELinux 拦截 | semanage port -a -t postgresql_port_t -p tcp 自定义端口 |
5. 安装之后:参数调优与日常维护
5.1 几个值得改的内存参数
安装完成不代表就能高枕无忧,默认参数更偏向“在任何机器上都能跑起来”,而不是“跑得最好”。刚上线时可以先用默认参数,但建议在压测前调整几个关键参数。
shared_buffers是 PostgreSQL 自己管理的内存缓冲区,官方建议通常设为物理内存的 25% 左右。比如 16G 内存的机器,可以设为 4GB:
shared_buffers = 4GBeffective_cache_size是给查询优化器参考的“操作系统文件缓存大小”估算值,可以设为物理内存的 75% 左右,比如:
effective_cache_size = 12GB注意这个参数不是真正分配内存,只是告诉优化器大概有多少缓存可以用,设置太高或太低会影响索引扫描和排序策略的选择,但对内存本身没有实质性占用压力。
maintenance_work_mem影响 VACUUM、CREATE INDEX、ADD FOREIGN KEY 这类维护操作的排序内存,默认 64MB 确实偏小。做一次大表索引重建,内存太小就得多写磁盘临时文件。建议调到 1GB 左右:
maintenance_work_mem = 1GBmax_connections默认 100,对大多数中小业务够用。但要注意,PostgreSQL 每个连接都需要独立进程,连接数越多消耗的内存越大。如果业务确实需要大量连接,优先考虑应用侧加 PgBouncer 连接池,而不是无限调大这个参数。
调整这些参数后需要重启服务:
sudo systemctl restart postgresql-15然后用EXPLAIN ANALYZE或者监控面板对比优化前后的查询表现。参数调优没有一劳永逸的方案,最终要以实际业务场景为准。
5.2 开启查询日志和 pg_stat_statements
排查慢 SQL 是数据库日常维护里最频繁的工作之一。PostgreSQL 本身提供了log_min_duration_statement参数,设置执行时间超过阈值的 SQL 会被记录到日志,快速定位慢查询:
log_min_duration_statement = 1000单位是毫秒,这里表示超过 1 秒的 SQL 都会写入日志。还可以开启日志收集器:
logging_collector = on log_directory = 'log' log_filename = 'postgresql-%a.log'这样每天一个日志文件,按周循环,方便排查历史问题。线上遇到性能异常时,先打开日志看有没有大量慢语句,往往能直接定位到问题 SQL。
pg_stat_statements是另一个必须启用的扩展。它记录每条 SQL 的总执行次数、总耗时、平均耗时、缓冲命中情况,是性能分析的一大利器。启用方式是在 postgresql.conf 里加:
shared_preload_libraries = 'pg_stat_statements'然后重启服务,在需要监控的数据库里执行:
CREATE EXTENSION pg_stat_statements;查询 Top N 慢 SQL:
SELECT query, calls, total_exec_time, mean_exec_time FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 10;有了这个扩展,你就不需要靠猜来定位问题了,直接看数据。
5.3 备份与恢复的基本套路
备份这件事,等出事了再想就晚了。PostgreSQL 最常用的两种备份方式是逻辑备份和物理备份。
逻辑备份用pg_dump,适合备份单个数据库或部分表。比如:
pg_dump -h 127.0.0.1 -U myapp -d mydb -F c -f mydb.dump-F c是自定义格式,支持压缩和选择性恢复。恢复时用pg_restore:
pg_restore -h 127.0.0.1 -U myapp -d mydb mydb.dump物理备份用pg_basebackup,适合备份整个实例,做流复制备库时也用它。比如:
pg_basebackup -h 主库IP -p 5432 -U replicator -D /backup/base -X stream物理备份的好处是恢复快,适合大数据量场景,但对配置要求更高。我个人的习惯是:日常定时用 pg_dump 做逻辑备份,重要时刻再结合物理备份做整体恢复演练。很多公司数据库挂了才想起备份,测试恢复时才发现备份文件是坏的,这种事见过太多次了。
5.4 日常巡检的几个要点
安装完数据库只是第一步,日常巡检能帮你把隐患消灭在早期。我总结了几个必须定期看的指标:服务状态、磁盘空间、连接数、慢查询日志大小、备份执行结果。
systemctl status postgresql-15 df -h这两个命令基本上每次登录服务器我都会顺手敲一下。pg_stat_activity可以查看当前活跃连接:
SELECT pid, usename, state, query_start, query FROM pg_stat_activity WHERE state = 'active';如果连接数长期逼近max_connections,或者磁盘使用率超过 80%,我的经验是不要拖,尽早处理。数据库服务不像应用服务可以随时重启,磁盘写满后服务直接不可用,恢复起来非常被动。
写在最后的一点经验
安装 PostgreSQL 本身不是难事,难点在于装完之后知不知道下一步该干什么。我在实际项目里见过太多装完就丢在一边的数据库,半年后因为连接数耗尽、磁盘满了、慢查询拖垮业务才被人想起来。所以不管是学习还是生产使用,装完库之后的第一时间就要把密码设置、远程访问控制、备份策略这三件事做掉,这三件事能坚持做下来,数据库的稳定性至少提升一大截。
最后再分享一个细节:CentOS 7 上如果同时用 PGDG 源和系统 base 源,有时候执行yum update会把系统自带的 PostgreSQL 9.2 相关包也升级一遍。这不是大问题,但别让它们抢占 5432 端口即可。安装前先确认系统里有没有已经存在的 PostgreSQL 残留,有的话要么yum remove postgresql*清干净,要么改掉新实例的端口,避免端口冲突这种低级问题。数据库这行,很多大故障都是从低级问题开始的。