PostgreSQL的守护进程PostMaster

守护进程也称为精灵进程,它在系统自举时启动,在系统关闭时才终止。因为它没有控制终端,所以说他们是在后台运行的。笔记记录了PostgreSQL的守护进程PostMaster进程的主要职责与它的基本流程。简单的了解了PostmasterMain函数以及PostgreSQL的内存初始化形式。
在完成Database Cluster的初始化之后,用户可以启动一个数据库实例。PostgreSQL在多用户模式下,实例是由Postmaster守护进程来管理。

一、Postmaster的主要职责

  • 数据库的启停;
  • 监听客户端连接;
  • 为每个客户端连接fork单独的Postgres服务进程;
  • 当服务进程出错时进行修复;
  • 管理数据文件;
  • 管理与数据库运行相关的辅助进程;

Postmaster的主要源文件:src/backend/postmaster/postmaster.c
Postmaster进程的入口函数为PostmasterMain,在PostgreSQL启动时,由main函数中调用。

二、PostmasterMain流程概述

1.为Globals.c中定义的全局变量赋值

如Postmaster的进程标识号(pid)、开始运行时间等;

2.组织内存上下文;

PostgreSQL自V7.0后实现了自己的内存管理机制MemoryContext,系统中的内存分配操作在各种语义(类型)的MemoryContext中进行,它的内部机制类似于操作系统的内存分配机制。MemoryContext为每个进程分配了进程执行环境,每个进程环境之间不相互影响,每个子进程都拥有多个私有的MemoryContext,每个子进程的MemoryContext组成了一个树形结构,根节点为TopMemoryContext。
MemoryContext负责对这些进程环境进行切换,同时,每个进程可以在其进程环境中调用操作系统库函数进行内存分配操作,如malloc,realloc,free。,但因为PostgreSQL对内存的分配,释放等操作都是在MemoryContext中进行,因此不再使用C语言的标准库函数malloc,realloc,free来操作,而是重新实现了palloc,replloc和pfree分别对应C语言标准库的三个内存管理函数。
这三个函数的定义在mcxt.c中

void * palloc(Size size);
void * repalloc(void *pointer, Size size);
void pfree(void *pointer)

具体的实现可以通过查看源码来了解。

源码中定义MemoryContext的类型是MemoryContextData,它的数据结构定义如下:

{ 
    NodeTag     type;           /* 标识MemoryContext的具体类型 */
    MemoryContextMethods *methods;      /* 内存处理函数指针 */
    MemoryContext parent;       /* 父节点指针,若是TopMemoryContext则为NULL */
    MemoryContext firstchild;   /* head of linked list of children */
    MemoryContext nextchild;    /* next child of same parent */
    char       *name;           /* 节点名称 (just for debugging) */
    bool        isReset;        /* T = no space alloced since last reset */
} MemoryContextData;

各种MemoryContext的定义在mcxt.c中

MemoryContext CurrentMemoryContext = NULL;
MemoryContext TopMemoryContext = NULL;
MemoryContext ErrorContext = NULL;
MemoryContext PostmasterContext = NULL;
MemoryContext CacheMemoryContext = NULL;
MemoryContext MessageContext = NULL;
MemoryContext TopTransactionContext = NULL;
MemoryContext CurTransactionContext = NULL;
MemoryContext PortalContext = NULL;

这些MemoryContext的默认值都是NULL,在使用他们之前首先需要对其进行初始化。
其中

CurrentMemoryContext

CurrentMemoryContext是分配给当前进程的缺省的MemoryContext,在任何时候都有一个“当前”的MemoryContext记录在全局变量CurrentMemoryContext,在需要转换MemoryContext时使用MemoryContextSwitchTo方法将CurrentMemoryContext指向其他类型的MemoryContext;

PostmasterContext

PostmasterContext是Postmaster进程正常工作时的内存环境,由它通过fork函数产生的子进程创建成功后将会回头来删除它,子进程过河拆桥,而PostmasterContext则是照亮别人,燃烧自己;

TopMemoryContext

TopMemoryContext是所有MemoryContext的根,由它分配的内存直到系统退出才会释放;ErrorContext是用于错误处理的内存环境,在PostgreSQL系统启动时它一直存在。
回到Postmaster进程PostmasterMain的源码:在Postmaster进程启动的时候,MemoryContext将首先实例化根TopMemoryContext,并将“当前”的内存上下文指向PostmasterContext。

PostmasterContext = AllocSetContextCreate(TopMemoryContext,
                                              "Postmaster",
                                              ALLOCSET_DEFAULT_MINSIZE,
                                              ALLOCSET_DEFAULT_INITSIZE,
                                              ALLOCSET_DEFAULT_MAXSIZE);
MemoryContextSwitchTo(PostmasterContext);

3.配置参数

初始化内存上下文之后,配置Postmaster运行所需的各种参数。PostmasterMain源码中InitializeGUCOptions方法中的GUC是Grand Unified Configuration。
GUC以及如何自定义GUC选项的笔记:《在postgresql.conf中增加自定义配置项》

4.验证数据目录的合法性,并且将工作空间切换到数据目录;

5.初始化SSL库(如果启用SSL)

6.预装载SharedLibraries;

7.建立监听

8.注册信号处理函数

9.实例化日志子进程(如果Logging_collector配置为on,SysLogger_Start())

10.实例化状态收集子进程(pgstat_init())

11.实例化AUTOVOCUUM子进程(autovac_init())

12.加载pg_hba.conf文件load_hba()

13.删除临时文件(RemovePgTempFiles())

14.启动数据库

/*
 * We're ready to rock and roll...
*/

这里不知道是哪位大神,和我一样喜爱摇滚吗?
设置pmState的状态为PM_STARTUP

15.启动bgwriter子进程(maybe_start_bgworker())

16.无限循环等待客户端的连接

src/backend/main/main.c
line:201
不使用–single-step和–single-line参数时,启动一个新的postgres进程。

if (argc > 1 && strcmp(argv[1], "--single") == 0)
{
    PostgresMain(argc, argv, NULL, get_current_username(progname));
}

在PostgresMain中,启动一个无限循环等待客户端的连接。
src/backend/tcop/postgres.c(line:3898)

{
    // Wait for a connection request to arrive.
    // New connection pending on any of our sockets? if so,fork a child process to deal with it
    // 检查log collector,background writer process,walwriter process,autovacuum launcher这些进程是否运行,没有运行会重新启动它们。并且在这里开始checkpoint
        if (pmState == PM_RUN || pmState == PM_RECOVERY ||
            pmState == PM_HOT_STANDBY)
        {
            if (CheckpointerPID == 0)
                CheckpointerPID = StartCheckpointer();
            if (BgWriterPID == 0)
                BgWriterPID = StartBackgroundWriter();
        }
    // waiting client message.
    ReadyForQuery......
}

StartCheckpointer–>StartChildProcess–>AuxiliaryProcessMain–>CheckpointerMain

17.如果Serverloop没有返回状态码则退出PostmasterMain

还没有评论,快来抢沙发!

发表评论

  • 😉
  • 😐
  • 😡
  • 😈
  • 🙂
  • 😯
  • 🙁
  • 🙄
  • 😛
  • 😳
  • 😮
  • emoji-mrgree
  • 😆
  • 💡
  • 😀
  • 👿
  • 😥
  • 😎
  • ➡
  • 😕
  • ❓
  • ❗
  • 69 queries in 0.451 seconds