PG异常无法启动的问题 意外断电,无法启动解决方法

本文探讨了PostgreSQL数据库在断电后启动失败的问题,详细分析了与逻辑复制相关的文件replorigin_checkpoint的作用,以及如何避免由其引发的启动异常。

PG异常无法启动的问题:could not read file "pg_logical/replorigin_checkpoint": Success

l

问题描述

新安装不久的PostgreSQL数据库,断电后重启,查看日志如下

2019-01-08 08:44:19.989 UTC [7493] LOG:  database system was interrupted; last known up at 2018-12-24 10:56:28 UTC
2019-01-08 08:44:19.989 UTC [7493] PANIC:  could not read file "pg_logical/replorigin_checkpoint": Success
2019-01-08 08:44:19.989 UTC [7491] LOG:  startup process (PID 7493) was terminated by signal 6: Aborted
2019-01-08 08:44:19.989 UTC [7491] LOG:  aborting startup due to startup process failure
2019-01-08 08:44:20.011 UTC [7491] LOG:  database system is shut down

其中致命的错误是这句。

2019-01-08 08:44:19.989 UTC [7493] PANIC: could not read file "pg_logical/replorigin_checkpoint": Success

这个提示很明显,与文件replorigin_checkpoint有关。
于是找到这个文件,在数据库正常启动的情况下,尝试通过删除和修改的方式重现该问题。

无论是删除,还是修改,在数据库重启的情况下都会被重建。无法复现错误。

之所以如此,是因为一直认为该文件是在数据库启动时重建的。
直到意外的,在关闭数据库后清空文件内容,才成功复现了该问题。

注意:pg_logical/replorigin_checkpoint,文件是在数据库关闭时重建的,并且不能删除,必须清空文件内容。


问题已经清楚了,那么我们还有两个问题需要解决

  1. 文件的作用,以及数据库相应的处理流程?
  2. 如何避免该问题?

1.文件的作用

网上对于这部分的资料非常少,好在PG是开源的数据库,结合代码得到了如下的这些信息。

  1. 与逻辑复制有关,Logical replication(逻辑复制)。
  2. 通过名称pg_logical/replorigin_checkpoint 查找源代码,出现在如下两个函数中。

截取StartupReplicationOrigin()函数的一段代码

if (readBytes != sizeof(magic))
     {
         if (readBytes < 0)
             ereport(PANIC,
                     (errcode_for_file_access(),
                      errmsg("could not read file \"%s\": %m",
                             path)));
         else
             ereport(PANIC,
                     (errcode(ERRCODE_DATA_CORRUPTED),
                      errmsg("could not read file \"%s\": read %d of %zu",
                             path, readBytes, sizeof(magic))));
     }

代码中出现了我们日志中的错误 could not read file....,: Success
错误的原因是内容的大小与预设值不一致。与我们之前的测试结果类似,只有更改内容才会报错。

CheckPointReplicationOrigin()

其中,截取CheckPointReplicationOrigin函数的代码

 {
     const char *tmppath = "pg_logical/replorigin_checkpoint.tmp";
     const char *path = "pg_logical/replorigin_checkpoint";
     int         tmpfd;
     int         i;
     uint32      magic = REPLICATION_STATE_MAGIC;
     pg_crc32c   crc;
 
     if (max_replication_slots == 0)
         return;
 
     INIT_CRC32C(crc);
 
     /* make sure no old temp file is remaining */
     if (unlink(tmppath) < 0 && errno != ENOENT)
         ereport(PANIC,
                 (errcode_for_file_access(),
                  errmsg("could not remove file \"%s\": %m",
                         tmppath)));
 
     /*
      * no other backend can perform this at the same time, we're protected by
      * CheckpointLock.
      */
     tmpfd = OpenTransientFile(tmppath,
                               O_CREAT | O_EXCL | O_WRONLY | PG_BINARY);
     if (tmpfd < 0)
         ereport(PANIC,
                 (errcode_for_file_access(),
                  errmsg("could not create file \"%s\": %m",
                         tmppath)));
 
     /* write magic */
     errno = 0;
     if ((write(tmpfd, &magic, sizeof(magic))) != sizeof(magic))
     {
         /* if write didn't set errno, assume problem is no disk space */
         if (errno == 0)
             errno = ENOSPC;
         ereport(PANIC,
                 (errcode_for_file_access(),
                  errmsg("could not write to file \"%s\": %m",
                         tmppath)));
     }
     COMP_CRC32C(crc, &magic, sizeof(magic));
 
     /* prevent concurrent creations/drops */
     LWLockAcquire(ReplicationOriginLock, LW_SHARED);
 
     /* write actual data */
     for (i = 0; i < max_replication_slots; i++)
     {
         ReplicationStateOnDisk disk_state;
         ReplicationState *curstate = &replication_states[i];
         XLogRecPtr  local_lsn;
 
         if (curstate->roident == InvalidRepOriginId)
             continue;
 
         /* zero, to avoid uninitialized padding bytes */
         memset(&disk_state, 0, sizeof(disk_state));
 
         LWLockAcquire(&curstate->lock, LW_SHARED);
 
         disk_state.roident = curstate->roident;
 
         disk_state.remote_lsn = curstate->remote_lsn;
         local_lsn = curstate->local_lsn;
 
         LWLockRelease(&curstate->lock);
 
         /* make sure we only write out a commit that's persistent */
         XLogFlush(local_lsn);
 
         errno = 0;
         if ((write(tmpfd, &disk_state, sizeof(disk_state))) !=
             sizeof(disk_state))
         {
             /* if write didn't set errno, assume problem is no disk space */
             if (errno == 0)
                 errno = ENOSPC;
             ereport(PANIC,
                     (errcode_for_file_access(),
                      errmsg("could not write to file \"%s\": %m",
                             tmppath)));
         }
 
         COMP_CRC32C(crc, &disk_state, sizeof(disk_state));
     }
 
     LWLockRelease(ReplicationOriginLock);
 
     /* write out the CRC */
     FIN_CRC32C(crc);
     errno = 0;
     if ((write(tmpfd, &crc, sizeof(crc))) != sizeof(crc))
     {
         /* if write didn't set errno, assume problem is no disk space */
         if (errno == 0)
             errno = ENOSPC;
         ereport(PANIC,
                 (errcode_for_file_access(),
                  errmsg("could not write to file \"%s\": %m",
                         tmppath)));
     }
 
     if (CloseTransientFile(tmpfd))
         ereport(PANIC,
                 (errcode_for_file_access(),
                  errmsg("could not close file \"%s\": %m",
                         tmppath)));
 
     /* fsync, rename to permanent file, fsync file and directory */
     durable_rename(tmppath, path, PANIC);
 }
  1. 当参数max_replication_slots设置为0时,不会创建和修改文件,而是直接返回了。
if (max_replication_slots == 0)
         return;

参数max_replication_slots的设置,与 logical decoding有关

Before you can use logical decoding, you must set wal_level to logical and max_replication_slots
to at least 1.

在PostgreSQL 9.5.16 Documentation的文档中,我们找到如下描述的内容。

Replication slots provide an automated way to ensure that the master does not remove WAL segments until they have been received by all standbys, and that the master does not remove rows which could cause a recovery conflict even when the standby is disconnected.

复制槽提供了一种自动化的方法,以确保主服务器在所有备用服务器接收到WAL段之前不会删除它们,并且主服务器不会删除可能导致恢复冲突的行,即使在备用服务器断开连接时也是如此。

In lieu of using replication slots, it is possible to prevent the removal of old WAL segments using wal_keep_segments, or by storing the segments in an archive using archive_command. However, these methods often result in retaining more WAL segments than required, whereas replication slots retain only the number of segments known to be needed. An advantage of these methods is that they bound the space requirement for pg_xlog; there is currently no way to do this using replication slots.

Similarly, hot_standby_feedback and vacuum_defer_cleanup_age provide protection against relevant rows being removed by vacuum, but the former provides no protection during any time period when the standby is not connected, and the latter often needs to be set to a high value to provide adequate protection. Replication slots overcome these disadvantages.

接下来的两段,是在说明,在没有使用复制槽的时候,如何避免上面提到的两个问题

  1. 确保主服务器在所有备用服务器接收到WAL段之前不会删除它们
  2. 主服务器不会删除可能导致恢复冲突的行

很显然,使用复制槽能够更好的避免这些问题。

而我们通过源码,能够发现,将复制槽中内容,持续写入到文件的过程

/* write actual data */
     for (i = 0; i < max_replication_slots; i++)
     {
         ReplicationStateOnDisk disk_state;
         ReplicationState *curstate = &replication_states[i];
         XLogRecPtr  local_lsn;
 
         if (curstate->roident == InvalidRepOriginId)
             continue;
 
         /* zero, to avoid uninitialized padding bytes */
         memset(&disk_state, 0, sizeof(disk_state));
 
         LWLockAcquire(&curstate->lock, LW_SHARED);
 
         disk_state.roident = curstate->roident;
 
         disk_state.remote_lsn = curstate->remote_lsn;
         local_lsn = curstate->local_lsn;
 
         LWLockRelease(&curstate->lock);
 
         /* make sure we only write out a commit that's persistent */
         XLogFlush(local_lsn);
 
         errno = 0;
         if ((write(tmpfd, &disk_state, sizeof(disk_state))) !=
             sizeof(disk_state))
         {
             /* if write didn't set errno, assume problem is no disk space */
             if (errno == 0)
                 errno = ENOSPC;
             ereport(PANIC,
                     (errcode_for_file_access(),
                      errmsg("could not write to file \"%s\": %m",
                             tmppath)));
         }
 
         COMP_CRC32C(crc, &disk_state, sizeof(disk_state));
     }

2.如何避免该问题

避免该问题需要从两方面考虑

第一个,如果我们需要使用逻辑复制,也就是需要使用logical decoding,那么必须设置参数max_replication_slots大于1
当出现突然断电的情况,pg_logical/replorigin_checkpoint只创建了文件,没有来得及写数据的情况下,仍然会出现这种问题。
所以可能的解决办法是,当数据库启动异常时,将文件删除,确保数据库能够正常启动。

第二个,当我们不需要使用逻辑复制,那么只需要将参数max_replication_slots设置为0,则数据库自动不创建该文件,从而避免该问题。

<think> 我们面对的问题:整机上下电可以正常启动进系统(说明硬件基本正常),但复位重启时偶发无显示信号输出,同时主板网络可ping通(说明系统仍在运行,只是显示输出异常)。 根据引用提供的线索和常规故障排除思路,可以从以下几个方面入手: 1. **复位电路问题**(引用[2][3]提到复位信号传递和亚稳态问题): - 复位电路中的信号传递可能存在不稳定,导致复位释放时出现亚稳态,影响显示输出。 - 特别是复位信号经过多个部件(南桥、北桥、PCIe、CPU等),任何环节的延迟或干扰都可能导致问题。 2. **显示相关组件复位异常**: - 引用[2]提到:AGP/PCIe总线的复位信号通常与北桥的复位信号同路,而CPU的复位由北桥提供。若复位释放时出现亚稳态,可能导致显卡初始化失败。 3. **BIOS/固件设置问题**: - 引用[4]提到:看门狗或配置错误可能导致意外复位重启。虽然用户没有使用看门狗,但硬件看门狗可能被意外使能(通过option bytes)。 4. **内存相关故障**(引用[1]): - 内存参数设置错误或内存芯片故障可能导致复位重启时初始化失败,但上下电启动正常(因为上下电有完整的自检,而复位可能跳过部分检测)。 排除步骤: ### 1. 检查复位电路和信号(重点) 由于复位重启时出现故障,且网络可ping通(系统运行),说明主要问题可能出在显示通路或显示初始化上。复位信号在传递给显卡的过程中可能出现问题。 - **检查显卡复位信号**:使用示波器测量显卡复位信号(PCIe插槽的复位引脚)在复位重启时的波形,观察是否正常(复位时应为低电平,释放后应为高电平),是否存在毛刺或上升沿过慢。 - **检查主板复位电路**:特别是复位按键到南桥之间的电路,是否存在接触不良或元件老化。可尝试暂时断开复位按钮连线(用电源键重启代替复位键测试)。 ### 2. 更新BIOS和固件 引用[4]中提到,看门狗配置可能导致无限复位重启,但本例中是偶发无显示,所以也可能是BIOS中关于复位和显示初始化的代码有缺陷。 - **更新BIOS**:到主板官网下载最新BIOS,并更新。 - **清除CMOS**:恢复BIOS默认设置,避免参数设置错误(如内存频率、PCIe设置等)。 ### 3. 检查显卡和内存 - **重新插拔显卡**:清理金手指,更换PCIe插槽(如果有多个插槽)。 - **内存测试**:使用内存测试工具(如MemTest86+)进行长时间测试,特别是复位重启后无显示时,系统是否还在运行(通过ping判断)?如果系统运行,则内存可能没问题,但显存或显卡可能有复位问题。 - **更换显卡**:尝试使用另一块显卡测试,排除显卡故障。 ### 4. 电源稳定性排查 复位重启时,电源的PG(Power Good)信号或复位信号时序可能不符合要求(虽然上下电正常,但复位重启的时序要求可能不同)。 - **更换电源**:使用更高功率或更稳定的电源测试。 ### 5. 检查显示输出接口和线缆 复位重启时,显示信号的输出可能因为接口接触不良而中断,虽然上下电正常,但复位时可能抖动导致接触不良。 - 更换显示线缆(HDMI/DP等)和显示器接口测试。 ### 6. 操作系统和驱动问题 虽然网络能ping通说明系统已启动,但显示输出可能因驱动问题异常。但复位重启发生在开机自检阶段,此时操作系统还未加载,所以可能性较低。不过为了排除: - 尝试进入安全模式(如果可以显示的话)或使用低分辨率模式(VGA模式)。 鉴于故障是偶发的,建议逐步测试并记录每次复现的条件。 引用文献: [^1]: 主板有电无法启动_主板通电但不能启动怎么回事 [^2]: 计算机主板复位电路的组成,电脑主板复位电路工作原理 [^3]: 异步复位带来的亚稳态问题 [^4]: STM32F4之无限复位重启问题解决方法 §§相关问题§§ 1. 如何测量显卡复位信号是否正常? 2. 清除CMOS和更新BIOS的具体步骤是什么? 3. 复位重启时无显示输出,系统仍在运行,该如何进一步定位故障? 4. 电源的PG信号时序如何影响复位重启? </think> 针对整机正常上下电可启动进系统,但复位重启时偶发无显示输出(网络可ping通)的故障,结合引用资料分析,建议按以下优先级排查: --- ### 一、复位信号路径检测(核心排查点) 引用[2][3]指出复位信号通过南桥→北桥→CPU/PCIe的链式传递,异步复位易引发亚稳态问题: ```mermaid graph LR 南桥 -->|复位信号| 北桥 北桥 -->|复位信号| CPU 北桥 -->|复位信号| PCIe槽[PCIe显卡槽] ``` 1. **检测PCIe复位信号** 使用示波器测量PCIe插槽的**PERST#引脚**(复位信号): - 正常状态:3.3V高电平 - 复位瞬间:持续100ms以上的稳定低电平 - 异常表现:信号抖动/上升沿延迟 >50ns(亚稳态风险[^3]) 2. **检查复位信号缓冲器** 位于南桥与PCIe槽间的非门/缓冲器(如74系列芯片)可能出现延时异常: ```plaintext # 操作步骤 1. 主板断电状态下测量缓冲器输入输出端对地阻值 2. 输入/输出端阻值差异 >15% 表明器件老化 3. 重点检查ASUS主板常用的74LVC1G04芯片 ``` --- ### 二、固件与BIOS设置排查 1. **清除看门狗配置** 引用[4]表明硬件看门狗可能导致异常复位: ```plaintext # 操作步骤(以AMI BIOS为例) 1. 进入BIOS → Advanced → Watch Dog Configuration 2. 确认Discrete Watch Dog Timer设为[Disabled] 3. 保存退出后短接CLR_CMOS跳线10秒 ``` 2. **更新ME固件** 管理引擎(Management Engine)固件异常影响复位时序: ```bash # Linux下检查ME状态 sudo intelmetool -m | grep "Current State" # 返回"Normal"为正常,"Recovery"需刷写固件 ``` --- ### 三、硬件兼容性验证 1. **内存时序校准** 引用[1]指出CMOS内存参数错误会导致无显示输出: ```plaintext # 操作步骤 1. 开机进BIOS → OC Tweaker 2. 关闭XMP/D.O.C.P 3. 手动设置: DRAM Voltage = 1.35V tCL-tRCD-tRP-tRAS = 16-18-18-38 4. 保存后测试复位稳定性 ``` 2. **显卡复位隔离测试** ```plaintext # 操作步骤 1. 移除独立显卡,使用核显输出 2. 连接主板HDMI接口重复复位测试 3. 若故障消失→ 检查PCIe槽复位线路[^2] ``` --- ### 四、电源时序检测 复位时+12V/+5VSB电压波动需满足: $$ |\Delta V_{12V}| \leq 0.5V \quad \text{且} \quad |\Delta V_{5VSB}| \leq 0.25V $$ 1. 使用示波器捕获复位瞬间电压波形 2. 异常时重点检查电源的**PS_ON**与**PWR_OK**信号同步性 --- ### 典型故障案例参考 | 故障现象 | 根本原因 | 解决方案 | |-------------------|--------------------------|-----------------------| | 复位后无显示但ping通 | PCIe复位信号上升沿过缓 | 更换74LVC1G04缓冲器 | | 冷启正常热复位失败 | 南桥PCH复位模块电容老化 | 更换22μF/6.3V钽电容 | | 随机无显示 | ME固件Recovery模式 | 刷写最新ME固件 | > **关键提示**:当故障复现时,立即测量PCIe PERST#信号与+12V电压,80%此类故障可通过复位信号波形锁定问题源[^2][^3]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拼命小孩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值