postgresql架构简介
postgresql是一种C/S架构,postgres server process(或称postmaster)是主进程,负责启动各个常驻进程,以及监听client端的请求,为每个client端会创建一个postgres backend process。详细介绍见下面链接。
postgresql进程和内存介绍
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初始化等等。
函数调用关系图
启动过程简要分析
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);
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。