1

postgresql架构简介

postgresql是一种C/S架构,postgres server process(或称postmaster)是主进程,负责启动各个常驻进程,以及监听client端的请求,为每个client端会创建一个postgres backend process。详细介绍见下面链接。
postgresql进程和内存介绍

image.png

postgresql进程例

postgresql/10371的进程,postmaster是postgres server process。logger/10372,checkpointer/10374等是常驻后台进程。mydb [local] idle/17300是client端对应的backend process。

\# pstree -pa 10371
postmaster,10371 -D /usr/local/pgsql/data4
  |-10372,postgres: logger
  |-10374,postgres: checkpointer
  |-10375,postgres: background writer
  |-10376,postgres: walwriter
  |-10377,postgres: autovacuum launcher
  |-10378,postgres: stats collector
  |-10379,postgres: logical replication launcher
  |-17300,postgres: postgres mydb [local] idle
  `-18542,postgres: postgres mydb [local] idle

在psql中可以获取其backend process的pid17300

mydb=# select pg_backend_pid();
-[ RECORD 1 ]--+------
pg_backend_pid | 17300

启动过程简介

下面分析postgresql的启动过程,大体流程为postmaster启动,启动常驻进程,进入主循环,监听client的请求。其中还包含配置文件读取,全局设置,信号处理函数注册,share memory初始化等等。

函数调用关系图

image

启动过程简要分析

postmaster主入口
PostmasterMain
  // 解析command-line options
  // 比如-o 选项的option,暂存于ExtraOptions
  while ((opt = getopt(argc, argv, "B:bc:C:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:W:-:")) != -1)
  {
    case 'o':
      snprintf(ExtraOptions + strlen(ExtraOptions),
         sizeof(ExtraOptions) - strlen(ExtraOptions)," %s", optarg);
    case 'D':
        // 数据目录,来自于命令行参数的-D选项
        userDoption = strdup(optarg);
    case '-':
        //直接传入GUC选项,如--config_file,保存到变量ConfigFileName
        ParseLongOption(optarg, &name, &value);
        SetConfigOption(name, value, PGC_POSTMASTER, PGC_S_ARGV);
   }
   
  // 设置data目录,
  // load 配置文件,postgresql.conf
  SelectConfigFiles(userDoption, progname)

  checkDataDir();
  checkControlFile();
  ChangeToDataDir();

  // 检查,创建postmaster.pid锁文件
  CreateDataDirLockFile(true);
  InitializeMaxBackends();

  // share memory init
  reset_shared
  // 对clientsocket开始listen
  // socket保存在ListenSocket[MAXLISTEN]
  StreamServerPort
  // load pg_hba.conf
  load_hba
  // ???待分析
  StartupDataBase
  // postmaster的主循环
  ServerLoop
设置数据目录,配置文件

如下可见,data目录有以下几个来源,按照优先级高到低分别为:
. postgres.conf中的data_directory配置项
. 启动postmaster程序时的命令行参数-D
. 环境变量PGDATA

SelectConfigFiles(const char *userDoption, const char *progname)
    // data dir来自于上面的-D命令行参数,或者来自于环境变量PGDATA
    if (userDoption)
        configdir = make_absolute_path(userDoption);
    else
        configdir = make_absolute_path(getenv("PGDATA"));

    // configure 文件来自于命令行参数,或者data目录下的postgres.conf
    if (ConfigFileName)
        fname = make_absolute_path(ConfigFileName);
    else if (configdir)
    {
        fname = guc_malloc(FATAL,
                                                   strlen(configdir) + strlen(CONFIG_FILENAME) + 2);
        sprintf(fname, "%s/%s", configdir, CONFIG_FILENAME);
    }


    SetConfigOption("config_file", fname, PGC_POSTMASTER, PGC_S_OVERRIDE);

    // 读取配置文件
    ProcessConfigFile(PGC_POSTMASTER);

    // data目录来自于配置文件
    // 或者上面解析命令行参数或者环境变量PGDATA
    if (data_directory)
        SetDataDir(data_directory);
    else if (configdir)
        // 写入全局变量DataDir后续使用
        // 比如,写入postmaster.pid文件
        SetDataDir(configdir);

    SetConfigOption("data_directory", DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE);
postmaster主循环
ServerLoop
  // 检查,处理socket,详细见下面 "socket处理"部分
  // log collector 检查,启动
  SysLogger_Start
  // walwriter 检查,启动
  StartWalWriter
  // autovacuum launcher 检查,启动
  StartAutoVacLauncher
  // stats collector 检查,启动
  pgstat_start
  // archiver 检查,启动
  pgarch_start
  // WAL receiver 检查,启动
  MaybeStartWalReceiver
  // other worker processes 检查,启动
  maybe_start_bgworkers
socket处理
// 初始化fd_set readmask
nSockets = initMasks(&readmask);
select(nSockets, &rmask, NULL, NULL, &timeout);
for (i = 0; i < MAXLISTEN; i++)
{
    if (ListenSocket[i] == PGINVALID_SOCKET)
        break;

    // socket有数据
    if (FD_ISSET(ListenSocket[i], &rmask))
    {
        Port       *port;

        // 创建连接,accept
        port = ConnCreate(ListenSocket[i]);
        if (port)
        {
            // 创建backend process
            BackendStartup(port);
            // postmaster中关闭socket
            StreamClose(port->sock);
            ConnFree(port);
        }
    }
}

黑暗森林
12 声望2 粉丝

弱小和无知不是生存的障碍,傲慢才是!