简介面向数据库运维与实施人员的一份 Oracle 19c RAC 安装手册围绕 Red Hat Linux 7.6 环境下的双节点集群部署展开适合具备一定 Linux 与 Oracle 基础、需要掌握 GNS 配置 SCAN 和 Flex ASM 的中高级读者参考。压缩包内含 1 个 docx 文档大小约 160KB章节编排较完整便于按模块查阅与复用。内容从操作系统环境检查讲起覆盖关闭透明大页与开启大页内存、安装系统及补充软件包、借助 Preinstall RPM 或手工方式配置内核参数、可选 CVU 校验、固定网络与 GNS 加固定网络配置、系统杂项设置和时钟同步等环节。手册还梳理了自 12.2 起独立集群与域服务集群两种模式的差异并结合 Flex ASM、版本演进和配置问题分析给出排错思路与定位方法。已有 719 人学习对理解集群安装前后的检查、配置与验证过程具有参考价值可作为 RAC 搭建及故障排查的案头资料。1. 装 19c RAC 之前为什么九成的失败发生在图形界面之前Oracle 19c RAC 在 Linux 7.6 上起不来的现场通常不在runInstaller的弹窗里。更常见的是gridSetup.sh走到 Prerequisite Checks 停了三分钟扔出一行 INS-13001或者更隐蔽——装完了库起来了AWR 里log file sync每隔十几分钟尖一次翻遍 SQL 层找不到原因最后发现是/sys/kernel/mm/transparent_hugepage/defrag还停在[always]。这份 19c RAC on Linux 安装手册值得逐行看的地方不是它列了多少条命令而是每条命令背后都压着一个不这么配就会在某个凌晨翻车的约束vm.nr_hugepages的页数是从 SGA 反推出来的、limits.conf里的 memlock 必须跟着它走、SCAN 的三个地址只能交给 DNS 而不能进/etc/hosts、GNS 只对你委托给它的那个子域有权威。把这几条因果关系理顺装第二套的时候就不用再抄一遍手册——你会知道哪一步能改、改哪里、改错了看哪个文件验证。2. 内存平面先关 THP 再开 Hugepages顺序和数值都不能错2.1 THP 的两个开关enabled 管分配defrag 管整理透明大页Transparent Huge Pages是内核替应用自动把 4KB 小页合并成 2MB 大页的机制对通用负载是好事对 Oracle 的 SGA 是灾难。根因在于它不可控合并时机由内核决定应用无法预知自己拿到的是 2MB 页还是 4KB 页。要看的不是一个文件是两个# 是否启用透明大页 cat /sys/kernel/mm/transparent_hugepage/enabled # [always] madvise never # 是否启用透明大页碎片整理 cat /sys/kernel/mm/transparent_hugepage/defrag # [always] madvise never方括号表示当前生效值。enabled的三个取值语义不同always是内核尽力给所有匿名内存配大页madvise是只有应用显式调用madvise(MADV_HUGEPAGE)的区域才给never是彻底关掉。很多人以为设成madvise就安全了因为 Oracle 不会主动调madvise。这个判断只对了一半。defrag那一行才是真正的关键问题当它处于always时khugepaged内核线程会在内存碎片化时触发直接内存压缩direct compaction把分散的 4KB 页搬迁、腾挪出连续的 2MB 区域。这个动作会持有内存管理相关的锁停顿从几十毫秒到几百毫秒不等。SGA 动辄几十 GB一旦这段停顿落在数据库进程的提交路径上表现就是周期性的log file sync抖动——SQL 层完全看不出来因为问题不在 SQL。所以正确的目标状态是两个文件都变成 never而不是只关enabled。手册里要求把transparent_hugepagenever追加到内核命令行重启后两个文件都会跟着变成never如果重启完发现defrag还是always说明参数没生效或者机器从另一个启动项引导了这就是后面要排查的第一个坑。2.2 内核参数 transparent_hugepagenever 与 grub2-mkconfig 的两条路径改内核命令行不是编辑/boot/grub2/grub.cfg那个文件是生成出来的手改会在下次内核升级时被覆盖。正确做法是改源文件/etc/default/grubvi /etc/default/grub # 在 GRUB_CMDLINE_LINUX 里追加注意是追加不是替换 GRUB_CMDLINE_LINUXrd.lvm.lvrhel/root rd.lvm.lvrhel/swap ... transparent_hugepagenever # 备份现有配置 cp /boot/grub2/grub.cfg /boot/grub2/grub.cfg.bak # BIOS 引导的机器 grub2-mkconfig -o /boot/grub2/grub.cfg # UEFI 引导的机器输出路径不一样 grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg shutdown -r now这里的关键参数是-o后面的输出文件。BIOS 和 UEFI 的输出路径不同写错路径命令会成功返回、日志也不报错但重启后参数根本没进内核——因为引导加载器读的还是旧文件。判断机器走哪条路径看/sys/firmware/efi目录是否存在即可。重启后验证只能靠一个文件cat /proc/cmdline/proc/cmdline是内核启动时实际收到的参数这是唯一可信的证据。grub.cfg里写了不算数/etc/default/grub里写了更不算数。2.3 Hugepages 页数是从 SGA 反推出来的不是拍脑袋关掉 THP 之后要开 Hugepages这是两个方向相反的动作不能只做一个。THP 是内核替你做主Hugepages 是你自己做主——预先划出一块固定的、锁定的、不参与换页的大页池由 Oracle 通过 System V 共享内存加SHM_HUGETLB标志去取。页数怎么算是这份手册里少数几个必须动笔算的地方# 先确认单个大页多大 grep Hugepagesize /proc/meminfo # Hugepagesize: 2048 kBx86_64 上默认是 2MB。假设这台机器规划的SGA_TARGET是 24GB页数 SGA 字节数 / Hugepagesize 24 * 1024 MB / 2 MB 12288但如果装的是 Domain Service Cluster 并且要配 GIMRGIMR 自己的 SGA 还要额外占 1GB 大页也就是再加 512 页Standalone Cluster 在 19c 里 GIMR 是可选项不装就不用加。这一步漏算实例启动时会报 ORA-27102 或者悄悄退化成用普通页性能直接掉一个档次。写入配置vi /etc/sysctl.conf vm.nr_hugepages 12800 # 12288 512 再留一点余量 sysctl -p然后memlock必须同步放开。Oracle 进程要把大页锁在物理内存里防止被换出这个动作受RLIMIT_MEMLOCK限制vi /etc/security/limits.conf oracle soft memlock 26214400 oracle hard memlock 26214400memlock的单位是 KB。12800 页 × 2MB 25600MB 26214400KB两者必须对得上。如果memlock小于大页总字节数表现不是锁不住而是大页分配直接失败。swap 的计算也和这一步强相关。手册给的原则是物理内存 4GB 到 16GB 之间swap 等于物理内存超过 16GBswap 取 16GB如果启用了 Huge Page计算 swap 要减去分配给 HugePage 的内存。原因是 swap 的容量需求是按可能被换出的匿名内存估算的而大页是锁定不换出的这部分物理内存对 swap 没有需求。举个具体的128GB 物理内存、划了 100GB 大页可换出部分只剩 28GB仍然大于 16GBswap 还是 16GB但如果 32GB 内存划了 24GB 大页可换出只剩 8GB落在 4-16GB 区间swap 就该配 8GB 而不是 16GB。这一步算错CVU 会在 swap 检查项上报错但报的是swap 不足这种让人摸不着头脑的提示。2.4 从 /proc/meminfo 判断大页到底有没有被用上配完之后不能只看sysctl -p有没有报错要看内核实际分配了多少grep -i huge /proc/meminfo四个字段要连起来读字段含义健康状态HugePages_Total内核预留的大页总数等于vm.nr_hugepagesHugePages_Free池中尚未分配的大页数实例启动前等于 TotalHugePages_Rsvd已承诺但尚未实际映射的页数实例启动后上升HugePages_Surp从 surplus 池临时借用的大页数必须为 0判断逻辑很直接实例没启动时Free应该等于Total实例启动后Free下降、Rsvd上升说明大页被真实吃进去了。如果实例起来了但Free几乎没动说明 Oracle 根本没用大页——多半是memlock不够或者use_large_pages参数不是TRUE。Surp大于 0 是另一个信号它表示内核从多余页池里临时借了大页给你通常意味着nr_hugepages设小了实际用量超过了预留量。这种情况不会立刻报错但借来的页在内存压力下可能被回收是个潜伏的雷。3. 预配清单preinstall RPM 到底替你改了哪些内核参数3.1 preinstall RPM 做的事以及它没做的部分Oracle 提供了一个oracle-database-preinstall-19c包把大部分手工配置固化成了脚本。用起来很简单cd /etc/yum.repos.d/ wget http://yum.oracle.com/public-yum-ol7.repo yum repolist yum install -y oracle-database-preinstall-19c它实际做了五件事创建oracle用户创建oinstalloraInventory 属组和dbaOSDBA组写/etc/sysctl.d/下的内核参数文件写/etc/security/limits.d/下的资源限制文件调整与 NUMA 相关的启动参数把numaoff加进去。关于numaoff这一项常见的实现思路是让操作系统层不做 NUMA 亲和性均衡把内存分配策略交给数据库自己控制。Oracle 内部有自己的 NUMA 感知逻辑两层同时干预容易互相打架表现为跨节点远程内存访问比例异常高。这不是绝对的但对安装阶段的稳定性来说关掉更省心。这个包没做的事同样重要不装cvuqdisk、不配 SSH 等价性、不建 ASM 磁盘的 UDEV 规则、不动时钟同步、不管hugepages的具体页数。这些都得手工补。如果不走 preinstall 路线手工配置的内核参数文件长这样# /etc/sysctl.d/97-oracledatabase-sysctl.conf fs.aio-max-nr 1048576 fs.file-max 6815744 kernel.shmall 2097152 kernel.shmmax 4294967295 kernel.shmmni 4096 kernel.sem 250 32000 100 128 net.ipv4.ip_local_port_range 9000 65500 net.core.rmem_default 262144 net.core.rmem_max 4194304 net.core.wmem_default 262144 net.core.wmem_max 1048576生效方式/sbin/sysctl --system # 重新加载所有 sysctl.d 下的文件 /sbin/sysctl -a # 打印全部当前值用于比对注意一个容易出问题的点preinstall 装的可能是99-oracle-database-preinstall-19c.conf手工建的可能是97-oracledatabase-sysctl.conf。sysctl --system按文件名排序加载编号大的后加载、会覆盖前面的。两个文件同时存在且值不一致时最终生效的是 99 那份。要么只留一份要么保证两份的值完全一样。3.2 shmall 与 shmmax一个算页数一个算字节这两个参数名字像、单位完全不同是最容易配反的一对。kernel.shmmax是单个共享内存段的最大字节数单位是字节所以4294967295约等于 4GB 减 1 字节。kernel.shmall是系统范围内可分配的共享内存总页数单位是页所以要乘页大小才是字节数。getconf PAGE_SIZE # 4096按这个页面大小换算2097152 × 4096 8589934592也就是 8GB。这就是系统级共享内存上限shmmax的 4GB 则限制任何单个段不能超过它。关系不能反shmall × PAGE_SIZE必须大于等于你需要的共享内存总量且shmmax不能超过shmall × PAGE_SIZE。配反了的典型症状是ipcs -lm显示max total shared memory小得离谱然后 Oracle 在创建 SGA 时报 ORA-27102。需要说明的是启用大页之后 SGA 走的是 hugetlbfs 路径不再占用常规的 shmget 段所以这两个参数的约束力主要体现在没开大页的场景、PGA 相关的共享段、以及其他依赖 System V 共享内存的组件上。但它们仍然必须配对因为 CVU 会检查而且一旦哪天要临时关掉大页做对比测试没有这两个参数会立刻崩。3.3 kernel.sem 四元组与 fs.aio-max-nr 的真实约束kernel.sem 250 32000 100 128四个数字分别是 SEMMSL、SEMMNS、SEMOPM、SEMMNI含义和约束对象都不一样位置名称含义与 Oracle 的关系1SEMMSL单个信号量集合内的最大信号量数必须 ≥ 单实例的PROCESSES2SEMMNS系统级信号量总数≥ SEMMSL × 实例数多实例共存时容易不够3SEMOPM单次semop调用可操作的最大信号量数一般 100 足够4SEMMNI系统级信号量集合数量上限每个实例至少占一个集合Oracle 用信号量做 enqueue 层的并发协调PROCESSES调大之后 SEMMSL 不跟着调表现是实例启动阶段报 ORA-27154 或者进程创建失败。检查当前值ipcs -lsfs.aio-max-nr 1048576是系统级异步 I/O 请求数上限。Oracle 的 DBWn、LGWR 通过 libaio 提交异步 I/O每个在途 I/O 请求占用一个 aio 上下文槽。这个值不够时的表现很隐蔽I/O 不会报错而是悄悄退化到同步路径然后 db file sequential read 的延迟莫名其妙地涨。查当前用量cat /proc/sys/fs/aio-nr cat /proc/sys/fs/aio-max-nraio-nr接近aio-max-nr就是要调大的信号。fs.file-max 6815744是系统级文件描述符上限和ulimit -n单进程是两个层级两个都要够。3.4 CVU 查不出来的那几项配置Cluster Verification Utility 是安装前最后一次系统级检查用起来是一条命令# 先把 cvuqdisk 包装到每个节点包在 Grid 安装介质的 cv/rpm 目录下 export CVUQDISK_GRPoinstall rpm -iv cvuqdisk-1.0.10-1.rpm # 执行安装前检查-fixup 表示尝试自动修复可修项 ./runcluvfy.sh stage -pre crsinst -fixup -n node1,node2,node3-fixup不是万能的它只能修那些改一个文件就能改对的项比如缺包、参数越界。它查不到的恰好是最容易在安装后爆发的那几类时钟同步。CVU 不检查节点间时间偏差但集群心跳和 OCR 的时间戳对偏差敏感。装之前必须把 chrony 或 ntpd 配好并验证chronyc sources有同步源。SSH 超时。sshd_config里的ClientAliveInterval/ClientAliveCountMax如果设得过短CVU 的 SSH 等价性检查会时好时坏——因为它在多个节点间反复跑远程命令某条连接刚好被踢掉就报失败重跑一次又过了。这类玄学失败几乎都出在这里。X11 Forward。安装时要用图形界面但装完之后应该关掉X11Forwarding这是个纯粹的攻击面收敛动作CVU 不管。I/O Scheduler。ASM 磁盘的调度器选择noop/deadline/cfq直接影响 I/O 延迟分布CVU 完全不看这一项。SSD 上通常选noop机械盘或 SAN 上deadline更稳。查看和修改cat /sys/block/sdb/queue/scheduler # noop [deadline] cfq echo deadline /sys/block/sdb/queue/scheduler这些项 CVU 都放行但它们决定了这套集群是能跑还是跑得稳。4. 网络平面Public、HAIP、SCAN VIP 为什么要分成三层4.1 三个网络平面的职责边界与同子网约束RAC 的网络不是配几个 IP而是三个职责完全不同的平面混在一起的后果是故障域被放大。平面承载什么每节点数量是否漂移解析方式Public主机名、管理访问1否hosts / DNSPrivate集群心跳、Cache Fusion14HAIP 会漂hostsVIP节点故障时的服务地址1是hosts / DNSSCAN VIP客户端统一入口3或 1是只能 DNS手册里有几条硬约束必须一起记要么全 IPv4 要么全 IPv6不能混用Public、VIP、SCAN VIP 必须在同一子网段Public/VIP 名称只能用字母数字和连字符不允许下划线——下划线在 DNS 里是合法字符但在某些解析器和 JDBC 连接串里会出问题直接禁掉省事。从 18c 开始VIP 变成了可选项可以给所有节点配也可以一个都不配但不支持只给部分节点配。这个全有或全无的约束来自 VIP 的故障转移语义——VIP 要在节点间漂移如果集群里一半节点有 VIP 一半没有资源模型就说不清了。不配 VIP 的场景通常是纯 SCAN 访问客户端只认 SCAN不关心落到哪个节点。4.2 HAIP为什么不用 bond 也能保证私有网络高可用私有网络跑的是 Cache Fusion 的块传输和集群心跳对延迟和丢包极度敏感。传统做法是用 OS 层的 bond 做链路聚合但 RAC 有自己的方案HAIPHighly Available IP。规则很明确安装过程中最多可以配四个 private 接口作为 HAIP超过四个的部分自动降级为冗余不承载流量也不需要额外配置。也不需要做 bond 绑定集群软件自己在 IP 层做故障切换。这个设计取舍值得琢磨。bond 工作在链路层它能感知的是网线断了交换机口 down 了但感知不到这个网卡虽然 link up但丢包率 30%。HAIP 工作在 IP 层由集群软件根据实际的通信质量决定把流量切到哪张卡上粒度更细。代价是 HAIP 需要集群软件参与不能脱离 GI 单独存在好处是它天然跟集群的资源模型对齐——节点、网卡、IP 是同一套状态机在管。查看当前配置# 列出集群使用的网络接口 oifcfg getif # ens192 192.168.204.0 global public # ens224 40.40.40.0 global cluster_interconnect # 列出节点上所有可用接口 oifcfg iflistglobal表示这个接口在所有节点上都被使用cluster_interconnect就是私有平面的标记。HAIP 地址本身不在oifcfg里显示要看ifconfig或ip addr里那些169.254.x.x开头的地址——那是 HAIP 的实际形态。4.3 GNS 的子域委托一条 NS 记录决定了 SCAN 能不能自动分配GNSGrid Naming Service是跑在集群里的一个 DNS 服务器它能在集群启动时动态为 VIP、SCAN VIP、甚至私有 IP 分配地址。但它的权力范围是被严格限定的只对父域委托给它的那个子域有权威。这就是配置 GNS 时最容易搞错的地方。假设集群域名是rac.exampleGNS 自己的 VIP 是192.168.204.10要让 GNS 管理 VIP 分配得在父域的 DNS 里做一次 NS 委托# 父域 zone 文件片段关键就在最后两行 scan19.vip.rac.example. IN A 192.168.204.162 scan19.vip.rac.example. IN A 192.168.204.163 scan19.vip.rac.example. IN A 192.168.204.164 vip.rac.example. IN NS gns.rac.example. gns.rac.example. IN A 192.168.204.10vip.rac.example. IN NS gns.rac.example.这一行的意思是以后所有*.vip.rac.example的解析请求都交给gns.rac.example这台服务器回答。gns.rac.example. IN A 192.168.204.10告诉解析器这台服务器在哪。委托关系一旦建立GNS 就能在vip.rac.example这个子域里自由创建vip19-node1.vip.rac.example之类的记录。SCAN 的域名scan19.vip.rac.example必须落在这个子域内——因为 SCAN 地址也要由 GNS 动态分配如果 SCAN 域名挂在rac.example下而不是委托子域下GNS 就没有权限为它写记录安装时会报解析失败。在gridSetup.sh的 GNS 配置页面要填的两个值就对应这两个角色GNS VIP 地址填192.168.204.10subdomain 填vip.rac.example。填错任何一个后面的 SCAN 配置都会连带失败。如果不用 GNS那就是固定配置路线SCAN 只通过 DNS 解析Public、Private、VIP 全部手工在/etc/hosts里写死安装时手工指定。这条路更笨但更好排查。4.4 SCAN 为什么必须走 DNS 而不能写进 hostsSCANSingle Client Access Name是客户端连接集群的唯一入口需要三个 IP 地址也可以只配一个但三个是标准做法能分摊连接并提高可用性。三个地址的分配机制是 DNS 轮询客户端解析 SCAN 名字时DNS 依次返回不同的 A 记录不同客户端拿到不同的 IP连到不同的节点监听器。这是唯一能实现负载分摊的方式任何静态解析都做不到。所以 SCAN 名字必须由 DNS 解析不能写进/etc/hosts。原因有三层第一/etc/hosts里同名多行时glibc 实际只取第一个匹配等于把三个地址压成一个负载分摊没了第二GNS 动态更新地址时不会去改每台机器的/etc/hosts静态配置会和实际状态脱节第三SCAN VIP 会随节点故障漂移写死的解析指向的可能是一台已经挂掉的机器。安装时如果 SCAN 解析检查失败先看/etc/resolv.conf里的nameserver是不是指向了正确的 DNS再看nslookup scan19.vip.rac.example能不能返回全部三个地址。少一个都不行。5. 避坑与排查从 CVU 报错到 gridSetup.sh 卡住的五个现场手册能列出来的都是正确路径真正耗时间的是偏离路径之后怎么定位。下面这几条是从实际安装现场反推出来的。5.1 系统层的三个现场现象一改了 grub 参数重启后/proc/cmdline里没有transparent_hugepagenever。原因几乎总是引导方式判断错了。UEFI 机器上执行的是grub2-mkconfig -o /boot/grub2/grub.cfg命令返回 0、没有任何报错但引导加载器实际读的是/boot/efi/EFI/redhat/grub.cfg两个文件互不相干。解决先ls /sys/firmware/efi确认引导方式UEFI 就走/boot/efi/EFI/redhat/grub.cfg这条输出路径重建后重启用cat /proc/cmdline验证。如果还不对用efibootmgr -v看当前引导项指向哪个文件。现象二vm.nr_hugepages算得没错HugePages_Total也对但实例启动报 ORA-27102或者 AWR 里看不到大页使用。原因通常是两个数没对上要么memlock小于大页总字节数要么页数没算 GIMR 那 1GB。Domain Service Cluster 场景下 GIMR 是必须的它自己的 SGA 额外占 512 个 2MB 页即使装的是 Standalone Cluster如果安装时勾选了配置 GIMR这 512 页同样要加进去。解决先grep -i huge /proc/meminfo看Surp是否为 0再检查limits.conf里 oracle 用户的 memlock 是否 ≥HugePages_Total × 2MB换算成 KB。改完limits.conf必须重新登录 oracle 用户才生效su - oracle在同一会话里不会重读 PAM 配置。**现象三/etc/security/limits.conf本文还有配套的精品资源点击获取