PostgreSQL 12.0源码编译安装实战:CentOS 7.9从依赖到systemd管理
1. 部署前想清楚的三件事版本、方式、目录PostgreSQL 12.0是2019年10月发布的版本放在今天看并不算新最新社区版已经迭代到17甚至更高。但现实中需要部署它的项目一点不少很多国产化数据库改造项目、存量业务系统的迁移验收、以及技术方案里明确写着“数据库版本采用PostgreSQL 12.0”的场景都得老老实实把这套版本装起来。这篇文章不是纯理论讲解而是我最近在一台CentOS 7.9服务器上做Linux下PostgreSQL 12.0安装部署的完整复盘把每一步命令、参数含义、踩过的坑都摊开讲清楚。如果你是运维工程师、DBA或者是需要自己搭建数据库环境的后端开发这篇内容可以直接拿来当操作手册。即使你用的是Ubuntu、Debian等系统整体思路也完全通用差异只在依赖安装命令和个别路径上。1.1 为什么12.0这个版本值得单独梳理PostgreSQL 12.0最大的变化是引入了原生分区表改进、并行查询增强、通用表达式CTE的性能优化等当时社区的反馈是“大版本里综合体验提升最明显的一代”。对生产环境来说它最大的价值在于稳定性和兼容性很多业务系统在12.0上跑了好多年应用层和中间件的适配早就完成项目组自然不会为了追新版本去承担回归风险。我实际接触过的情况是甲方验收文档明确写了数据库版本范围部署方没得选只能按指定版本执行。所以这篇文章虽然以12.0为例里面的部署思路、配置参数、排错手法对PostgreSQL其他版本同样适用。学会这一套往后换版本只是换源码包的事情。另外多说一句如果你没有版本锁定需求直接用当前最新的稳定版通常更合适毕竟新版本的性能和安全性都在提升。但如果是“非12.0不可”的项目这篇文章能帮你少走很多弯路。1.2 三种安装方式怎么选源码编译、RPM包、Docker部署PostgreSQL的方式大致有三种我通常这样取舍方式优点缺点适合场景源码编译可自定义编译参数、指定安装路径适用于任意Linux发行版便于后续扩展模块步骤多、编译耗时长依赖需要手动解决内网服务器、指定版本、生产环境可控性要求高RPM/Yum安装安装快、依赖自动处理系统服务管理方便版本通常不是最新的源里没有就麻烦和操作系统发行版绑定标准环境、对版本没有特殊要求Docker容器一条命令启动隔离性好开发环境切换版本最快生产环境要额外维护容器运行网络和存储映射需要规划性能有一定损耗本地开发、测试环境、快速体验这次部署我选的是源码编译原因很实际服务器在内网无法直接访问外网Yum源项目还锁定了12.0这个具体版本官方Yum源里维护的版本未必正好匹配后续可能还要编译contrib扩展源码编译的方式最灵活。而且说实话源码编译并没有想象中那么耗时在四核服务器上大概三五分钟就能编完生产服务器的性能完全够用。编译安装看起来多敲几条命令但每一步都在掌握之中对数据库二进制文件的位置、依赖关系也更清楚。2. 准备工作先看清楚机器再动手装依赖很多部署失败问题不是出在安装命令本身而是准备工作没做扎实。我习惯在动任何安装包之前先把系统状态摸清楚再安装编译依赖。2.1 四条命令确认系统状态部署之前我一般会依次执行这几条命令cat /etc/os-release # 查看系统发行版和版本号 uname -m # 查看CPU架构通常是x86_64 free -g # 查看内存总量规划shared_buffers时要参考 df -h /data # 确认数据目录所在分区的剩余空间为什么先做这一步因为操作系统发行版不同依赖安装命令完全不同CentOS/RHEL用yumUbuntu/Debian用apt如果不看系统类型就去装依赖很可能第一步就卡住。另外PostgreSQL的数据目录建议放在单独挂载的磁盘上不要和系统盘挤在一起至少预留几十GB的空间因为后续还有WAL日志、归档文件需要占用空间。我这次的环境是CentOS 7.9x86_64架构机器内存4GB/data分区剩余200GB左右足够承载一个中型业务库的初始部署。磁盘空间这点多说一句很多人部署初期觉得够用就行结果跑了大半年才发现空间告急再迁移数据就非常痛苦。2.2 编译依赖到底需要哪些包源码编译PostgreSQL时最关键的是这几个依赖包gcc编译C代码的编译器没有它什么都编不了make执行Makefile构建流程的工具readline-develpsql命令行交互、上下翻历史、Tab补全都依赖readline库不装的话psql用起来非常难受zlib-devel数据库备份和恢复时的压缩功能依赖zlib不装的话相关功能会有编译限制flex、bison用于生成SQL语法解析器缺了它们会在编译阶段报错在CentOS 7.9上安装这些依赖就一条命令yum install -y gcc make readline-devel zlib-devel flex bison如果是在内网离线环境需要提前准备好这些RPM包或是本地Yum仓库否则第一次configure就会因为找不到readline报错。我遇到过几次“configure: error: readline library not found”的情况基本都是因为依赖没装全补上readline-devel就顺利通过了。还有一点值得说明如果你计划使用PL/Perl、PL/Python这类过程语言扩展需要额外安装对应的开发包比如perl-ExtUtils-Embed、python3-devel。这部分不在基础依赖里等确实需要时再按项目需求补装即可一是减少不必要的编译负担二是避免无用的Python/Perl环境被系统安全扫描判定为多余组件。2.3 创建专用用户和目录结构PostgreSQL出于安全设计不允许以root身份运行数据库服务必须使用独立的系统用户。这一步很多人会忘或者嫌麻烦直接用root启动结果系统日志里一堆权限警告。标准做法是创建postgres用户useradd postgres然后规划目录结构。我习惯把数据目录、日志目录、归档目录分开mkdir -p /data/pgdata # 数据库数据文件主目录 mkdir -p /data/pglog # 服务运行日志目录 mkdir -p /data/archived # WAL归档目录后续做备份时用 chown -R postgres:postgres /data/目录属主这一步极其关键如果不把/data目录的属主改成postgresinitdb初始化时会出现“could not change permissions of directory”这类报错。因为initdb会检查数据目录的权限和属主不允许其他用户拥有数据目录这是PostgreSQL默认的安全机制。我之前踩过一个坑只创建了目录忘了chown然后以postgres用户执行initdb结果一直报目录权限问题浪费了大概十分钟才反应过来。目录结构建议一开始就规划好不要图省事全堆在/var/lib/pgsql下面宁可多敲几条命令后面维护时省心得多。3. 源码编译configure参数怎么选、踩了哪些坑依赖装好、用户建好之后就进入正题下载源码包并编译安装PostgreSQL 12.0。这一步是整个部署流程的核心也是网上各种教程最容易写得含糊的地方。3.1 下载源码包并校验完整性我一般把源码包下载到/usr/local/src目录方便统一管理cd /usr/local/src wget https://ftp.postgresql.org/pub/source/v12.0/postgresql-12.0.tar.gz如果服务器无法访问外网可以在本地电脑下载后通过scp或内网传输工具上传到服务器再用sha256校验一下文件完整性sha256sum postgresql-12.0.tar.gz校验这个步骤不是形式主义源码包下载中断或者文件损坏后后续编译会出现各种莫名其妙的报错而且很难定位。确认校验值无误后解压tar -xzf postgresql-12.0.tar.gz cd postgresql-12.0顺便说一句内网环境很多团队选择搭个本地HTTP/FTP源或者直接拷包分发这都很常见。关键是别跳过后面的校验步骤。3.2 configure参数逐条拆解进入源码目录后最重要的一步就是执行configure。我这次的配置命令是./configure --prefix/usr/local/pgsql12 \ --with-pgport5432 \ --with-perl \ --with-python \ --enable-nls每个参数都需要理解用途再决定加不加不要照着别人的文档无脑复制--prefix/usr/local/pgsql12指定安装路径。我习惯带上版本号作为子目录这样同一台机器上如果还有PostgreSQL 14或16二进制文件不会相互覆盖升级回滚也方便。--with-pgport5432指定编译进数据库的默认端口号。PostgreSQL默认就是5432显式写出来的意义在于把端口定死避免有人后续误改编译默认值。--with-perl和--with-python启用PL/Perl和PL/Python过程语言支持。不确定项目是否会用到这些存储过程语言时我建议先加上成本很低且不影响日常使用。--enable-nls启用国际化消息翻译让PostgreSQL的错误提示支持多语言。对于国内项目这个参数按需添加其实默认英文日志反而更容易在网上搜到解决方案。configure过程中最常见的报错就是缺少依赖库比如找不到readline、zlib等。如果遇到这类报错不要慌看报错信息里明确提示缺什么包装好之后重新configure就行。configure成功后会输出一长串配置摘要包括“config.status: creating GNUmakefile”等字样看到这个就说明配置阶段通过了。3.3 编译安装make -j参数怎么定configure通过后执行编译make -j$(nproc)-nproc参数会自动把并发编译数设置成机器的CPU核数能明显缩短编译时间。如果机器内存特别小比如1GB内存还开了8核并发有可能把内存占满导致编译失败这时候保守一点直接用make不加-j参数虽然慢一些但很稳妥。编译完成后再执行make install这条命令会把二进制文件、库文件、头文件、文档安装到--prefix指定的目录下。安装完成后确认一下bin目录内容ls /usr/local/pgsql12/bin/正常情况下能看到initdb、pg_ctl、psql、pg_dump、pg_basebackup等核心工具都齐了。这套源码包的基础安装就算完成。如果后续需要用PostgreSQL自带的contrib扩展模块比如pg_stat_statements、postgres_fdw等还可以在源码目录下执行make world和make install-world。我一般不会一次性全安装等确实需要哪个扩展时再进入源码目录单独编译这样安装目录更干净。3.4 环境变量配置LD_LIBRARY_PATH的坑安装完成后还需要配置环境变量否则postgres用户执行psql时找不到命令initdb时也可能因为找不到动态库而报错。我给postgres用户的~/.bash_profile添加了以下内容export PATH/usr/local/pgsql12/bin:$PATH export LD_LIBRARY_PATH/usr/local/pgsql12/lib:$LD_LIBRARY_PATH配置PATH的目的很直观让initdb、psql等命令可以直接执行不需要每次敲完整路径。LD_LIBRARY_PATH则是为了告诉系统去哪里找PostgreSQL自带动态库比如libpq.so.5。我见过最典型的一个报错就是initdb执行时提示“error while loading shared libraries: libpq.so.5: cannot open shared object file”受影响的机器往往就是没设置LD_LIBRARY_PATH。设置完成后重新登录postgres用户或者执行source ~/.bash_profile让环境变量生效。这里有个小技巧环境变量最好只写在postgres用户下不要写到全局的/etc/profile里避免影响系统其他软件对动态库的加载顺序。一些PostgreSQL版本自带的动态库名字和系统其他软件重复全局LD_LIBRARY_PATH容易引发不必要的冲突。4. 初始化数据目录和第一次启动编译安装只是把可执行文件放到了服务器上真正让数据库“有数据可存”的步骤是initdb。这一步相当于给数据库划分一块干净的数据地盘生成初始的系统表、配置文件、事务日志等。4.1 initdb参数详解和初始化原理先切换到postgres用户再执行初始化su - postgres initdb -D /data/pgdata -E UTF8 --localeen_US.UTF-8 -U postgres --authscram-sha-256每个参数都有明确作用我逐个说一下-D /data/pgdata指定数据目录。这里必须和前面创建目录时保持一致。-E UTF8指定数据库默认字符集。国内业务系统基本都用UTF8避免中文乱码问题。--localeen_US.UTF-8指定本地化规则。选择UTF8的locale是为了让字符串排序和大小写处理符合通用习惯如果不需要本地化规则也可以直接用--localeC。-U postgres指定数据库超级用户的用户名。这里沿用系统账号的名字方便记忆也符合常见运维习惯。--authscram-sha-256指定本地socket连接的默认认证方式这个参数很重要下面单独展开。initdb执行过程中会创建三个初始数据库template0、template1和postgres还会生成核心配置文件postgresql.conf和pg_hba.conf。这一步的本质是把PostgreSQL内置的初始数据填充到我们指定的数据目录中让数据库系统具备启动条件。执行成功后末尾会明确显示“Success. You can now start the database server”这行提示看到它才算初始化成功。4.2 认证方式scram-sha-256还是md5PostgreSQL 12.0开始默认的密码认证方式已经从md5切换为scram-sha-256。这是安全性上的重要升级scram-sha-256比md5更抗暴力破解和重放攻击连接过程中的密码传输不易被截获还原。我在规划认证方式时的原则是只要客户端和中间件支持scram-sha-256就用它不倒退回md5。但如果遇到很老的应用客户端只支持md5协议连接时报认证失败再针对性调整。调整方式是把pg_hba.conf里对应的认证方法改成md5然后重置一次用户密码让数据库里存的是md5加密的密码。不过要提醒一点从scram-sha-256切换回md5属于兼容性妥协除非项目强约束不建议长期在生产环境使用md5。4.3 用pg_ctl启动并确认进程初始化和配置完成后可以手动启动数据库mkdir -p /data/pglog chown postgres:postgres /data/pglog pg_ctl -D /data/pgdata -l /data/pglog/server.log start-l参数指定了运行日志的输出文件。这一步有个容易被忽略的细节日志文件路径的目录必须让postgres用户有写权限否则启动会直接失败错误信息还比较隐晦。启动后我习惯用下面两条命令确认状态ps -ef | grep postgres pg_isreadyps的输出会显示postmaster主进程以及一堆辅助子进程比如background writer、walwriter、checkpointer、stats collector等。看到这些进程就说明数据库核心进程已经正常起来了。pg_isready如果显示“accepting connections”说明数据库正在监听连接请求。5. 核心配置调整、systemd注册和远程访问数据库能启动只是第一步生产使用还需要调整内存参数、配置远程访问权限、注册开机自启。这步骤做不好前期的安装工作就白费了一半。5.1 postgresql.conf里的关键参数怎么调编辑配置文件vi /data/pgdata/postgresql.conf我通常会优先调整这几个参数listen_addresses * port 5432 shared_buffers 1GB max_connections 200 max_prepared_transactions 0 wal_level replica effective_cache_size 3GBlisten_addresses默认值是localhost意味着只能本机访问数据库。如果应用服务器和数据库服务器是分开的必须改成*或者指定内网IP否则从其他机器永远连不上。shared_buffersPostgreSQL的内存缓冲区大小官方建议设为物理内存的25%左右。这台机器是4GB内存所以设1GB比较合理。这个参数不是越大越好给操作系统留足内存做文件缓存整体性能反而更好。生活里类比一下shared_buffers就像餐厅的前厅前厅堆了太多菜后厨就没地方干活了。max_connections最大连接数。默认值是100小业务够用如果并发量高要提前调大。注意这个参数改得太大也会占用更多共享内存。wal_levelWAL日志级别。默认replica即可能支持热备和归档。如果没有特殊需求不需要改成logical。effective_cache_size这个值告诉优化器系统可用缓存有多大一般设为物理内存的50%~75%4GB内存的机器设3GB没什么问题。它不做真正的缓存分配只影响查询执行计划的选择。修改完postgresql.conf后需要区分一下哪些参数只需要reload就能生效哪些必须重启。像listen_addresses、max_connections这些参数需要重启shared_buffers更是必须重启wal_level也需要重启。如果不想中断业务可以先执行pg_ctl reload让部分参数生效再在维护窗口重启让全部参数生效。5.2 pg_hba.conf的访问控制规则数据库的网关注册文件是pg_hba.conf它决定了谁可以通过什么方式连接数据库。打开这个文件常见配置如下# TYPE DATABASE USER ADDRESS METHOD local all all scram-sha-256 host all all 127.0.0.1/32 scram-sha-256 host all all 0.0.0.0/0 scram-sha-256格式从左到右依次是连接类型、数据库名、用户名、客户端地址、认证方法。含义分别是local本地Unix域套接字连接只适用于本机psql连接。hostTCP/IP连接。127.0.0.1/32表示仅允许本机回环地址连接0.0.0.0/0表示允许任意IP连接生产环境如果这么写会暴露在风险中建议改成业务网段比如192.168.1.0/24。认证方法建议统一用scram-sha-256不要用trust。trust意味着不需要密码就能登录这在数据库场景基本等于把数据裸奔在局域网里。如果只是内部开发环境临时用trust调试可以上线前一定要改回来。修改pg_hba.conf后不需要重启数据库执行pd_ctl reload或者运行SQL语句SELECT pg_reload_conf();即可让配置生效。5.3 用systemd管理PostgreSQL服务手动启动数据库的方式适合首次安装验证生产环境还是得注册成systemd服务这样开机自动启动、宕机自动拉起、运维统一管理。我在/etc/systemd/system/目录下新建了一个unit文件postgresql-12.service[Unit] DescriptionPostgreSQL 12 database server Afternetwork.target [Service] Typeforking Userpostgres Grouppostgres EnvironmentPGDATA/data/pgdata ExecStart/usr/local/pgsql12/bin/pg_ctl start -D ${PGDATA} -l /data/pglog/server.log ExecStop/usr/local/pgsql12/bin/pg_ctl stop -D ${PGDATA} -m fast ExecReload/usr/local/pgsql12/bin/pg_ctl reload -D ${PGDATA} TimeoutSec120 [Install] WantedBymulti-user.target解释一下几个关键点Typeforking因为pg_ctl启动时postmaster进程会fork出后台进程并返回systemd通过这个模式来判定服务已经成功启动。ExecStop里的-m fast表示快速关闭模式会回滚未完成的事务并断开连接。如果需要更平滑的关闭可以用smart模式它会让数据库等当前连接都结束后再关闭适合计划维护场景。TimeoutSec120防止大库关闭时间过长被systemd误判为超时杀掉。注册并启用服务systemctl daemon-reload systemctl enable --now postgresql-12执行后确认状态systemctl status postgresql-12看到“Active: active (running)”字样就说明服务已经被systemd管起来了开机自动启动的配置也全部到位。如果你所在环境必须用sysVinit也可以使用源码包里contrib/start-scripts/linux脚本但能上systemd还是上systemd日志聚合和服务管理都方便得多。5.4 防火墙放行和远程连通测试内网机器通常开着firewalld如果不放行5432端口即使数据库监听了一切地址其他机器也连不进来。CentOS 7.9上放行端口firewall-cmd --permanent --add-port5432/tcp firewall-cmd --reload然后查看监听状态ss -lntp | grep 5432看到LISTEN状态的5432端口说明TCP监听已经建立。再从另一台机器测试连接psql -h 192.168.1.10 -p 5432 -U postgres -d postgres输入密码后能进入SQL命令行整个部署流程就算真正打通了。如果这一步连不上优先检查三处数据库监听地址是否包含目标IP、pg_hba.conf是否允许该来源IP、防火墙是否放行。排查顺序打乱反而容易越整越乱。6. 常见问题与排查技巧实录部署过程中总会遇到或大或小的问题。我把实际操作中频率最高的故障整理成了一张速查表按照“现象-原因-处理”的思路来走处理效率会高很多。6.1 高频故障对照速查表现象根本原因排查与处理initdb报libpq.so.5找不到LD_LIBRARY_PATH环境变量未设置在postgres用户的bash_profile中添加export LD_LIBRARY_PATH/usr/local/pgsql12/lib然后重新sourcepsql连接提示role “root” does not exist用root用户直接执行psqlPostgreSQL不知道root这个角色先切换su - postgres再执行psql远程连接超时或拒绝连接防火墙未放行5432端口或postgresql.conf未监听指定IP检查ss -lntp确认监听再firewall-cmd放行端口最后用pg_hba.conf确认来源IP是否被允许密码认证失败FATAL: password authentication failed密码错误或者客户端认证方式与pg_hba.conf不一致重置用户密码ALTER USER postgres PASSWORD 新密码并将pg_hba.conf认证方法对齐为scram-sha-256启动时提示could not bind to address端口被占用通常是装了其他数据库或旧版PostgreSQL用ss -lntp查看谁占用5432要么停掉占用进程要么改当前数据库端口数据目录权限报错目录属主不是postgres用户检查ls -ld /data/pgdata执行chown -R postgres:postgres /data/这些问题是初学者到进阶使用者最容易卡的几关尤其是认证失败和防火墙问题占了部署咨询量的一半以上。6.2 排错先看日志不要瞎猜和乱重启我的排错习惯始终是一切以运行日志为准先看日志再做判断。PostgreSQL的运行日志在初始化时通过-l参数指定也就是/data/pglog/server.log。用下面的命令跟踪最新日志tail -f /data/pglog/server.log日志里会明确写出启动失败的具体原因。比如权限不足、端口占用、数据目录损坏、认证错误等大多数时候日志已经告诉我们答案就差静下心来读一行。配合日志再做两个快速检查pg_isready -h 127.0.0.1 -p 5432 ss -lntp | grep 5432pg_isready负责确认数据库进程是否在接受连接ss负责确认端口监听状态。这两个命令加起来能快速判断问题出在“数据库没启动”还是“网络不可达”。切忌一上来就执行systemctl restart或者pg_ctl restart重启只会掩盖现象并不能解决根因重度业务数据库更不能随意重启。6.3 容易被忽略的权限与路径细节有几个细节在常规文档里不会专门强调但实际部署中非常容易踩我总结一下数据目录所在的父目录各级都要有足够权限让postgres用户进入。比如/data目录如果属主是root且权限是700postgres用户即使能操作/data/pgdata也会被父目录挡住。使用相对路径执行initdb时如果环境变量没生效会提示command not found。要么用绝对路径/usr/local/pgsql12/bin/initdb要么先确认PATH变量包含安装目录。修改postgresql.conf后shared_buffers这类参数不会因为reload而生效必须在维护窗口重启数据库。很多人改完配置执行了reload就以为参数生效了实际并没有。systemd服务文件如果命名不当或者包含语法错误systemctl daemon-reload会报错。写完后可以先执行systemd-analyze verify postgresql-12.service检查一下语法避免反复调试。如果不是用root安装编译tar包时产生的源码目录属主是root后续想用postgres用户再次编译contrib扩展会没权限直接chown -R postgres:postgres源码目录即可。6.4 几个提升效率的小技巧最后分享几个实际使用中的小技巧都是常规文档不会写的内容第一部署完成后立刻给postgres用户设置一个可靠的密码。初始化数据库时虽然指定了超级用户名但并没有设置密码如果不设置连接时会因为密码为空而无法通过认证。用ALTER USER postgres PASSWORD 强密码;在psql里执行一次这一步一定不要忘。第二把常用命令包装成shell别名比如alias pgstartsystemctl start postgresql-12、alias pglogtail -f /data/pglog/server.log放到root和postgres用户的环境变量中。数据库运维虽然不算复杂但高频操作能少敲几下键盘心情也会好很多。第三备份配置文件是运维的基本素养。我习惯在配置完成后执行一次cp /data/pgdata/postgresql.conf /data/pgdata/postgresql.conf.bak无论后面参数怎么调都能快速回滚。同理pg_hba.conf也建议留一份原始备份。最后再说一个习惯每次部署完成后我都会把安装过程中用到的命令、参数改动和关键截图整理成一份部署记录存到团队的运维文档里。很多操作当时觉得清清楚楚过半年再看就全忘光了尤其是initdb那几条参数不同项目之间变来变去没有记录就是隐患。这套流程在CentOS 7.9、Ubuntu 18.04上都实测跑过逻辑完全一致区别只是依赖安装把yum换成apt。如果你在部署中遇到这篇文章没覆盖到的问题不妨按“日志→权限→端口→参数”的顺序排查绝大多数问题都能快速定位到根因。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →