PostgreSQL可通过pg_ctl start -D pgdata
启动节点,我们看一下主节点启动流程。为了便于调试,我们以postgres -D pgdata
命令启动数据库并进行调试分析。
启动主流程
我们分析一下启动的时候,需要做那些工作,数据库启动时,需要先判断版本是否兼容,pg_control文件是否存在,也就是说要判断一些启动的必要条件是否满足。然后启动日志,startup等进程。 在接受客户端连接之前,需要先启动startup进程,进行故障恢复,这是因为系统关闭的时候,不一定是正常关闭的,可能是因为故障而退出,退出的时候,内存中的脏页不一定被刷入磁盘中,这时候就需要启动startup进程,对WAL日志进行回放,回放完后,再进入ServerLoop
,接受客户端的连接并处理SQL请求。
// main.c postgres进程主入口
main()
--> MemoryContextInit() // 初始化内存上下文: TopMemoryContext、ErrorContext
--> PostmasterMain(argc, argv); // Postmaster main entry point--> pqsignal_pm(SIGCHLD, reaper); /* handle child termination */ // 注册信号处理函数--> checkDataDir(); // 检查数据目录--> ValidatePgVersion(DataDir); // 检查PG_VERSION文件,PG实例版本是否与程序兼容--> checkControlFile(); // 检查pg_control文件--> CreateDataDirLockFile(true); // 创建postmaster.pid文件--> LocalProcessControlFile(false); // 读pg_control,到ControlFileData中--> ReadControlFile();--> process_shared_preload_libraries(); // 加载插件--> load_libraries(shared_preload_libraries_string, "shared_preload_libraries", false);--> load_file(filename, restricted);--> internal_load_library(fullname);--> SysLogger_Start(); // 启动日志进程 logger--> RemovePgTempFiles(); --> pgstat_init();--> autovac_init();--> load_hba()--> StartupDataBase(); // 启动startup进程 StartChildProcess--> AuxiliaryProcessMain(ac, av);--> StartupProcessMain()--> StartupXLOG();--> maybe_start_bgworkers();--> ServerLoop();for(;;){// #define PG_SETMASK(mask) sigprocmask(SIG_SETMASK, mask, NULL)// UnBlockSig is the set of signals to block when we don't want to block signals.PG_SETMASK(&UnBlockSig); // 设置/解除阻塞信号, 触发reaper,创建checkpointer, bgwriter,walwriter进程// 等待客户端连接selres = select(nSockets, &rmask, NULL, NULL, &timeout);ConnCreate(ListenSocket[i]);BackendStartup(port);--> canAcceptConnections(BACKEND_TYPE_NORMAL);--> BackendRun(port);--> PostgresMain(ac, av, port->database_name, port->user_name);--> InitPostgr