1. 程式人生 > 資料庫 >PostgreSQL pg_ctl start啟動超時例項分析

PostgreSQL pg_ctl start啟動超時例項分析

一、問題

pg_ctl start啟動時報錯退出:pg_ctl:server did not start in time。超時時間是多少?從什麼時候到哪個階段算超時?

二、分析:該資訊列印位置,從後面程式碼段do_start函式中可以看出

1、pg_ctl start呼叫start_postmaster啟動PG的主程序後,每隔0.1ms檢查一次postmaster.pid檔案,是否已寫入ready/standby

2、總共會檢查600次,即從啟動主程序後,最多等待60s,如果沒有寫入ready/standby則列印上述日誌並退出

3、預設等待時間是60s,如果pg_ctl start -t指定等待時間,則等待時間為該指定時間

三、什麼時候postmaster.pid檔案寫入ready/standby

1、如果是主機不管有沒有設定hot standby

1)當startup程序恢復完成退出時,呼叫proc_exit函式向主程序傳送SIGCHLD訊號並退出

2)主程序接收到訊號後,signal處理函式reaper呼叫AddToDataDirLockFile向postmaster.pid檔案寫入ready

2、如果是備機即data目錄下有recovery.cnf檔案,且設定了hot standby,在實際恢復前沒有到達一致性位置

1)startup程序向主程序傳送PMSIGNAL_RECOVERY_STARTED訊號,主程序呼叫訊號處理函式sigusr1_handler,將pmState=PM_RECOVERY

2)每次讀取下一個xlog前都會呼叫CheckRecoveryConsistency函式進行一致性檢查:

2.1 進入一致性狀態,starup程序向主程序傳送PMSIGNAL_BEGIN_HOT_STANDBY訊號,主程序接收到訊號後呼叫sigusr1_handler->AddToDataDirLockFile向postmaster.pid檔案寫入ready

3、如果是備機即data目錄下有recovery.cnf檔案,且設定了hot standby,在實際恢復前沒有到達一致性位置

1)startup程序向主程序傳送PMSIGNAL_RECOVERY_STARTED訊號,主程序呼叫訊號處理函式sigusr1_handler,將pmState=PM_RECOVERY

2)每次讀取下一個xlog前都會呼叫CheckRecoveryConsistency函式進行一致性檢查。如果沒有進入一致性狀態

3)本地日誌恢復完成,切換日誌源時同樣呼叫CheckRecoveryConsistency函式進行一致性檢查

3.1 進入一致性狀態,starup程序向主程序傳送PMSIGNAL_BEGIN_HOT_STANDBY訊號,主程序接收到訊號後呼叫sigusr1_handler->AddToDataDirLockFile向postmaster.pid檔案寫入ready

4、如果是備機即data目錄下有recovery.cnf檔案,且設定了hot standby,在實際恢復前到達一致性位置

1)startup程序向主程序傳送PMSIGNAL_RECOVERY_STARTED訊號,主程序呼叫訊號處理函式sigusr1_handler,將pmState=PM_RECOVERY

2)CheckRecoveryConsistency函式進行一致性檢查,向主程序傳送PMSIGNAL_BEGIN_HOT_STANDBY訊號,主程序接收到訊號後呼叫sigusr1_handler->AddToDataDirLockFile向postmaster.pid檔案寫入ready

5、如果是備機即data目錄下有recovery.cnf檔案,沒有設定hot standby

1)startup程序向主程序傳送PMSIGNAL_RECOVERY_STARTED訊號

2)主程序接收到訊號後,向postmaster.將pmState=PM_RECOVERY

四、程式碼分析

1、pg_ctl start流程

do_start->
 pm_pid = start_postmaster();
 if (do_wait){
  print_msg(_("waiting for server to start..."));
  switch (wait_for_postmaster(pm_pid,false)){
   case POSTMASTER_READY:
    print_msg(_(" done\n"));
    print_msg(_("server started\n"));
    break;
   case POSTMASTER_STILL_STARTING:
    print_msg(_(" stopped waiting\n"));
    write_stderr(_("%s: server did not start in time\n"),progname);
    exit(1);
    break;
   case POSTMASTER_FAILED:
    print_msg(_(" stopped waiting\n"));
    write_stderr(_("%s: could not start server\n" "Examine the log output.\n"),progname);
    exit(1);
    break;
  }
 }else
  print_msg(_("server starting\n"));
wait_for_postmaster->
 for (i = 0; i < wait_seconds * WAITS_PER_SEC; i++){
  if ((optlines = readfile(pid_file,&numlines)) != NULL && numlines >= LOCK_FILE_LINE_PM_STATUS){
   pmpid = atol(optlines[LOCK_FILE_LINE_PID - 1]);
   pmstart = atol(optlines[LOCK_FILE_LINE_START_TIME - 1]);
   if (pmstart >= start_time - 2 && pmpid == pm_pid){
    char  *pmstatus = optlines[LOCK_FILE_LINE_PM_STATUS - 1];
    if (strcmp(pmstatus,PM_STATUS_READY) == 0 || strcmp(pmstatus,PM_STATUS_STANDBY) == 0){
     /* postmaster is done starting up */
     free_readfile(optlines);
     return POSTMASTER_READY;
    }
   }
  }
  free_readfile(optlines);
  if (waitpid((pid_t) pm_pid,&exitstatus,WNOHANG) == (pid_t) pm_pid)
   return POSTMASTER_FAILED;
  pg_usleep(USEC_PER_SEC / WAITS_PER_SEC);
 }
 /* out of patience; report that postmaster is still starting up */
 return POSTMASTER_STILL_STARTING;

2、server主程序及訊號處理函式

PostmasterMain->
 pqsignal_no_restart(SIGUSR1,sigusr1_handler); /* message from child process */
 pqsignal_no_restart(SIGCHLD,reaper); /* handle child termination */
 ...
 StartupXLOG();
 ...
 proc_exit(0);//exit函式向主程序傳送SIGCHLD訊號
reaper->//程序終止或者停止的訊號
 AddToDataDirLockFile(LOCK_FILE_LINE_PM_STATUS,PM_STATUS_READY);
postmaster程序接收訊號:
sigusr1_handler->
 if (CheckPostmasterSignal(PMSIGNAL_RECOVERY_STARTED) &&
  pmState == PM_STARTUP && Shutdown == NoShutdown){
  CheckpointerPID = StartCheckpointer();
  BgWriterPID = StartBackgroundWriter();
  if (XLogArchivingAlways())
   PgArchPID = pgarch_start();
  //hot_standby在postgresql.conf檔案中配置TRUE
  //表示在恢復的時候允許連線
  if (!EnableHotStandby){
   //將standby寫入postmaster.pid檔案,表示up但不允許連線
   AddToDataDirLockFile(LOCK_FILE_LINE_PM_STATUS,PM_STATUS_STANDBY);
  }
  pmState = PM_RECOVERY;
 }
 if (CheckPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY) &&
  pmState == PM_RECOVERY && Shutdown == NoShutdown){
  PgStatPID = pgstat_start();
  //將ready寫入postmaster.pid檔案,允許連線
  AddToDataDirLockFile(LOCK_FILE_LINE_PM_STATUS,PM_STATUS_READY);
  pmState = PM_HOT_STANDBY;
 }
 ...

3、Startup程序

StartupXLOG->
 ReadCheckpointRecord
 if (ArchiveRecoveryRequested && IsUnderPostmaster){//有recovery.conf檔案則ArchiveRecoveryRequested為TRUE
  //有recovery.conf檔案則ArchiveRecoveryRequested為TRUE
  PublishStartupProcessInformation();
  SetForwardFsyncRequests();
  //向master程序傳送PMSIGNAL_RECOVERY_STARTED訊號
  SendPostmasterSignal(PMSIGNAL_RECOVERY_STARTED);
  bgwriterLaunched = true;
 }
 CheckRecoveryConsistency();-->...
 |-- if (standbyState == STANDBY_SNAPSHOT_READY && !LocalHotStandbyActive &&
 |  reachedConsistency && IsUnderPostmaster){
 |  SpinLockAcquire(&XLogCtl->info_lck);
 |  XLogCtl->SharedHotStandbyActive = true;
 |  SpinLockRelease(&XLogCtl->info_lck);
 |  LocalHotStandbyActive = true;
 |  SendPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY);
 |-- }
 ...
 回放一個record後,每次讀取下一個record前都會呼叫CheckRecoveryConsistency

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對我們的支援。