更多"C/C++、PostgreSQL、编译原理、计算机原理、TCP/IP、数据结构&算法、Linux编程”等技术文章更新于公众号: 君子黎
1. 简述postmaster.pid文件与pg_control文件间区别
我们曾在 postmaster.pid文件都存储了什么 和 详谈pg_control文件的作用 两文中对各自文件的内容以及内部原理做了比较详细的描述。但是,对这两个文件之间的差异,在该系列文章中还没有进进行讲解过,因此,本文将讲述它们间的区别,以及各自对整个PostgreSQL系统服务的影响和约束,同时重点剖析若运行中的PostgreSQL服务遇到postmaster.pid文件被删除或是文件内容被修改会发生声明?
首先可以肯定的是,这两个文件对于PostgreSQL数据库来说,都是至关重要的。但是它们之间还是有着很大的差异,即各自负责的功能不同,所谓各司其职。对于pg_control,它是PostgreSQL数据库的控制文件,是在第一次安装数据库(initdb)时候生成的,文件中存储的是当前数据库目录(PGDATA)的版本、初始化配置参数、系统唯一标识、CRC校验码等等,该文件是在initdb之后就一直存在的,PostgreSQL服务的启停不影响该文件的存在状态,也就是说这个文件只要该PGDATA数据蔟目录是有效的,那么就会一直存在。如果这个文件被删除,那么PostgreSQL数据库服务就永远起不来了。它保证了数据库的安全,同时通过读取该文件内容并进行逻辑校验,能保证不同版本的程序命令无法进行非法操作。
而postmaster.pid文件则不一样,它是随着PostgreSQL数据库服务的每次启动而创建,停止而被删除,也就是说,该文件的存在与否永远受到服务状态的影响。该文件的读取是在pg_control文件之后,而且该文件中存储的数据和系统的配置参数这些没有关系,它只记录当前启动的postmaster服务的进行PID、进程启动时间戳、数据蔟目录位置、socket套接字目录位置、共享内存key等信息,当PostgreSQL被停止后,该文件将立刻被删除,从而保证下一次的PostgreSQL服务能够正常启动。
pg_control是PostgreSQL服务能够启动的必要条件。
2. PostgreSQL服务的正常运行离不开postmaster.pid文件
当PostgreSQL服务正常启动之后,会在ServerLoop()函数中负责管理各后端辅助进程、后台进程以及和系统有关的控制文件pg_control、锁文件postmaster.pid,以及等待接收客户端的连接处理等等。该函数内部是死循环,只要PostgreSQL服务运行正常,则该函数将永远不会返回;若返回,则表明当前服务出现了异常情况,默认采取的措施是立刻停止当前的PostgreSQL服务。
在ServerLoop()函数中,会每隔1分钟去检测一次postmaster.pid文件的状态,以确认该文件没有被覆盖或是被删除。
#define SECS_PER_MINUTE 60 for( ; ; ) { // . . . . . . 省略其余部分代码 if (now - last_lockfile_recheck_time >= 1 * SECS_PER_MINUTE) { if (!RecheckDataDirLockFile()) { ereport(LOG, (errmsg("performing immediate shutdown because data directory lock file is invalid"))); kill(MyProcPid, SIGQUIT); } last_lockfile_recheck_time = now; } //. . . . . . 省略其余部分代码 }
如果有,则立刻强制关闭服务。这样就避免了postmaster守护进程和子进程在它们的数据库消失之后仍然挂起的问题。如果在相同的地方创建(initdb)新的数据库集群,可能会导致该问题。同时还提供了一些保护,即防止数据库管理员(Database Administrator, DBA)不理智地去删除postmaster.pid文件并手动启动一个新的postmaster。
那么这里会有两种情况,第一种是直接删除postmaster.pid文件;第二种是修改该文件中的内容,但是文件依然存在。下面将分别详细进行讲解这两种情形下的PostgreSQL数据库服务的采取措施是什么。
2.1 postmaster.pid文件被删除
对应postmaster.pid文件的检测,主要由RecheckDataDirLockFile()函数负责处理。首先函数尝试打开该文件,若成功,则继续下面的流程判断处理;反之,若文件打开失败,则对open()函数返回的错误码进行判断, 若该错误码是ENOTDIR,则立刻停止该数据库服务。若为其他错误码,则继续下一次的检测逻辑。其部分代码如下:
bool RecheckDataDirLockFile(void) { int fd; int len; long file_pid; char buffer[BLCKSZ]; fd = open(DIRECTORY_LOCK_FILE, O_RDWR | PG_BINARY, 0); if (fd < 0) { switch (errno) { case ENOENT: case ENOTDIR: /* disaster */ ereport(LOG, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m", DIRECTORY_LOCK_FILE))); return false; default: /* non-fatal, at least for now */ ereport(LOG, (errcode_for_file_access(), errmsg("could not open file \"%s\": %m; continuing anyway", DIRECTORY_LOCK_FILE))); return true; } } // . . . . . . 省略若干业务代码 }
附:ENOTDIR(open)
不是一个目录。给定的路径虽然存在,但不是一个目录。
其具体内部业务逻辑处理流程图如下所示:
结论:若运行中的PostgreSQL服务,当检测到postmaster.pid文件不存在时,则立刻停止服务。如下图所示:
2.2 postmaster.pid文件内容被修改
从2.1节中指导,若postmaster.pid文件被删除掉,则服务将在本次检测时候,立刻停止运行中的postmaster服务。 那么postmaster.pid文件不被删除,但是修改了其中的内容又会怎样呢? 下面我们将继续分析这个问题。
这部分的业务代码如下所示:
bool RecheckDataDirLockFile(void) { // . . . . . . 省略若干业务代码 len = read(fd, buffer, sizeof(buffer) - 1); pgstat_report_wait_end(); if (len < 0) { ereport(LOG, (errcode_for_file_access(), errmsg("could not read from file \"%s\": %m", DIRECTORY_LOCK_FILE))); close(fd); return true; /* treat read failure as nonfatal */ } buffer[len] = '\0'; close(fd); file_pid = atol(buffer); if (file_pid == getpid()) return true; /* all is well */ /* Trouble: someone's overwritten the lock file */ ereport(LOG, (errmsg("lock file \"%s\" contains wrong PID: %ld instead of %ld", DIRECTORY_LOCK_FILE, file_pid, (long) getpid()))); return false; }
当文件成功打开之后,将返回一个指向当前内核中可用的最小文件描述符fd。然后从中读取一行数据,我们在 postmaster.pid文件都存储了什么 中介绍过,postmaster.pid文件中的第一行数据是当前运行的postmaster守护进程的PID。
因此通过判断该PID的值和getpid()函数获取的结果进行比对即可得知这个PostgreSQL服务是否正常。若正常,则getpid()和从postmaster.pid文件中获取的PID值相同,反之,则不相同。所以若该文件中,除第一行数据外,其余行数据被修改或是删除时,PostgreSQL服务仍然能够运行;反之若第一行数据被修改,那么服务也会立刻停止运行。其内部逻辑处理流程图如下所示:
当修改了第一行数据之后,PostgreSQL服务立刻停止并打印相关的日志信息。
3. 总结
本文比较详细地介绍了pg_control控制文件与postmaster.pid锁文件两者之间的区别,包括但不限于文件的生成时间、生命周期、规则以及文件大致中大致内容。同时对postmaster.pid锁文件的存在与否,以及文件中内容修改、怎么修改对PostgreSQL服务造成的不同影响进行了详细分析说明。通过文字、代码并结合流程图的方式,使文章阅读起来的效率事半功倍。