暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

openGauss 归档

原创 huan 2024-12-24
365

openGauss 归档

日志归档是指将数据库中的日志数据进行备份和存储的过程。

一、归档的目的

归档的主要目的是为了保留历史数据,防止数据丢失,确保数据的一致性和完整性,同时为数据恢复提供一定的支持。

  1. 数据恢复、备份

    通过归档日志,可以创建数据库的备份,并在有需要时使用这些备份进行数据恢复。这是 PITR (Point-In-Time-Recovery) 的基础,它允许数据恢复到其运行历史中的任意一个有记录的时间点。

  2. 保证数据一致性

    归档日志可以保证数据库在崩溃或重启时,所有已经提交的事务都得到了持久的保存,从而保证数据的一致性。

  3. 监控和审计

    归档日志可以用于监控和审计数据库的活动,例如记录所有的 DDL 和 DML 操作,以便更好的了解数据的变动情况。

二、归档参数

# - Archiving -

#archive_mode = off		# allows archiving to be done
                        # (change requires restart)
#archive_command = ''	# command to use to archive a logfile segment
                        # placeholders: %p = path of file to archive
                        #               %f = file name only
                        # e.g. 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f'
#archive_timeout = 0	# force a logfile segment switch after this
                        # number of seconds; 0 disables
#archive_dest = ''		# path to use to archive a logfile segment
  1. archive_mode

    该参数用于控制数据库是否启用归档模式。在归档模式下,数据库会将所有的日志数据写入到归档日志文件中,而不是直接写入到主日志文件中。

    archive_mode 默认为 off,需要手动开启,若更改为 on 开启后,需要重启。当 wal_level = minimal 时,归档功能无法使用,如果将 archive_mode 设置为 true,将会导致重启集群失败。

  2. archive_command

    该参数用于指定归档日志文件的写入命令。该命令可以是一个脚本,也可以是一个外部程序。在归档模式下,数据库会将日志数据写入到归档日志文件中,然后执行该命令,将归档日志文件复制到指定的位置。

    archive_command 默认为空,需要手动指定归档文件的写入命令。

  3. archive_timeout

    该参数用于指定归档日志文件的写入超时时间。如果在指定的时间内没有完成归档日志文件的写入,数据库会自动停止归档操作。

    archive_timeout 默认为 0,需要手动指定归档文件的写入超时时间,若设置为 0 表示禁用这个功能,即不根据时间强制切换日志文件段。

    如果在一个不繁忙的系统可能需要很长时间才能写满一个日志,而如果将归档超时设置的过于频繁,会导致产生大量的空白的归档日志文件,从而影响系统的性能。

  4. archive_dest

    该参数用于指定归档日志文件的存储路径。在归档模式下,数据库会将日志数据写入到归档日志文件中,然后执行 archive_command 命令,将归档日志文件复制到指定的位置。

    archive_dest 默认为空,需要手动指定归档文件的存储路径。当archive_dest和archive_command同时配置时,WAL日志优先保存到archive_dest所设置的目录中,archive_command配置的命令不生效。

三、WAL日志参数

#------------------------------------------------------------------------------
# WRITE AHEAD LOG
#------------------------------------------------------------------------------

# - Settings -

wal_level = hot_standby			# minimal, archive, hot_standby or logical
					            # (change requires restart)
#fsync = on				        # turns forced synchronization on or off
#synchronous_commit = on		# synchronization level;
					            # off, local, remote_receive, remote_write, or on
					            # It's global control for all transactions
					            # It could not be modified by gs_ctl reload, unless use setsyncmode.

#wal_sync_method = fsync		# the default is the first option
                                # supported by the operating system:
                                #   open_datasync
                                #   fdatasync (default on Linux)
                                #   fsync
                                #   fsync_writethrough
                                #   open_sync
#full_page_writes = on			# recover from partial page writes
#wal_buffers = 16MB			    # min 32kB
					            # (change requires restart)
#wal_writer_delay = 200ms		# 1-10000 milliseconds

#commit_delay = 0			    # range 0-100000, in microseconds
#commit_siblings = 5			# range 1-1000
  1. wal_level

    该参数为写入 WAL 信息量的级别:

    • minimal:这个级别只写入从崩溃中恢复或立即关闭所需的信息。它跳过一些重要操作(如创建表、创建索引等),操作更快但无法用 WAL 归档日志恢复数据。
    • archive: 这个级别增加了 WAL 归档所需的日志记录,支持数据库的归档恢复。
    • hot_standby: 这个级别进一步增加了在备机上运行只读查询所需的信息,它只能在数据库服务重新启动后生效,用于在备机上开启只读查询。
    • logical: 这个级别添加了支持逻辑解码所需的信息,适用于逻辑复制场景。

    wal_level 默认为 hot_standby,需要手动指定,更改后需要重启。

  2. fsync

    该参数用于控制数据库的同步写入操作,默认为 on,即开启同步写入。当设置为 on 时,fsync 会确保更新被物理地写入到磁盘,通过调用 fsync() 系统调用或使用其他等价方法(WAL同步法)。这保证了数据库能够在操作系统或硬件崩溃后恢复到一致的状态。

  3. synchronous_commit

    该参数用于控制数据库的提交操作的同步级别,默认为 on。在 PostgreSQL 中,synchronous_commit 可以设置为以下值:

    • off:不进行同步,提交操作会尽快返回,数据可能会丢失。
    • local:只对本地提交进行同步,提交操作会等待本地磁盘的写入完成。
    • remote_receive:等待远程主机接收提交操作。
    • remote_write:等待远程主机写入提交操作。
    • on:对提交操作进行同步,等待本地磁盘和远程主机的写入完成。
  4. wal_sync_method

    该参数用于指定 WAL 日志的写入方式,默认为 fdatasync。在 PostgreSQL 中,wal_sync_method 可以设置为以下值:

    • open_datasync:只在macOS上支持。使用O_DSYNC标志打开文件,确保所有写入操作都同步到磁盘。
    • fdatasync:使用fdatasync()系统调用,仅同步文件数据,不同步文件的元数据。
    • fsync:使用fsync()系统调用,同步文件数据和元数据。
    • fsync_writethrough:类似fsync,但确保写入操作直接发送到磁盘,不经过缓存。
    • open_sync:使用O_SYNC标志打开文件,所有对该文件的写入操作都将被同步。
  5. full_page_writes

    该参数用于控制数据库是否在 WAL 中记录完整的页面写入操作,默认为 on。

  6. wal_buffers

    该参数用于指定 WAL 缓冲区的大小,默认为 16MB,最小值为32KB,更改此参数后需要重启数据库生效。

  7. wal_writer_delay

    该参数用于设置 WAL 写入器的延迟时间,默认为 200ms,范围为1-10000毫秒。增加延迟可用减少磁盘I/O,但可能会增加 WAL 缓冲区中数据的延迟。

  8. commit_delay

    该参数用于设置提交延迟时间,默认为 0,范围为 0-100000 微秒。增加延迟可以减少 WAL 写入操作的频率,从而减少磁盘I/O,但是会增加事务的响应时间。

  9. commit_siblings

    该参数用于设置事务提交的批次大小,默认为 5,范围为 1-1000。增加批次大小可以减少 WAL 写入操作的次数,从而减少磁盘I/O,但是可能会增加事务的响应时间。

四、归档的进程

归档交互流程图如下

归档交互流程图.png

归档进程函数流程图如下

归档进程函数流程图.png

  1. 归档进程主函数 PgArchiverMain

    主要进行一些全局变量的初始化以及初始化信号处理,之后进入主循环函数 pgarch_MainLoop(),最后退出线程。

    PgArchiverMain(knl_thread_arg* arg) { ereport(LOG, (errmsg("PgArchiver started"))); //执行归档主循环函数 pgarch_MainLoop(); //线程退出 gs_thread_exit(0); }
  2. 主循环函数 pgarch_MainLoop

    pgarch_MainLoop(void) { //判断归档目录是否设置,若没有设置则退出归档线程,归档停止 if (XLogArchiveDestSet()) { //验证归档目录是否为空或是否成功创建,若目录创建失败或无法正常访问则退出归档线程,归档停止 VerifyDestDirIsEmptyOrCreate(u_sess->attr.attr_storage.XLogArchiveDest); } do{ //执行归档拷贝循环函数 pgarch_ArchiverCopyLoop(); }while(PostmasterIsAlive() && !time_to_stop && (XLogArchivingActive() || getArchiveReplicationSlot() != NULL)); //1.主进程存活;2.没有被设置为停止;3.还有归档事件(归档仍为活跃状态)或者存在有归档复制槽。这三种条件必须同时满足,才会继续执行归档复制循环函数。 }
  3. 归档拷贝循环函数 pgarch_ArchiverCopyLoop

    pgarch_ArchiverCopyLoop(void) { //获取下一个需要归档的事务日志文件名,将其存储再xlog数组中,返回值为bool值,表示是否成功获取文件名 while (pgarch_readyXlog(xlog, MAX_XFN_CHARS + 1)) { //不断尝试归档当前的事务日志文件,直到归档成功或达到最大重试次数 for(;;) { //1.检查是否接收到SIGTERM信号或主进程是否已经死亡,如果是,则函数立即返回,停止归档操作 //2.检查是否接收到SIGHUP信号,如果是,则ProcessConfigFile(PGC_SIGHUP); //3.检查archive_command和archive_dest是否已设置。若均未设置,则报错并停止归档操作 //4.以上条件都满足则pgarch_archiveXlog(xlog),若归档成功则标记当前事务日志已归档并退出无限循环 //若归档失败,则计数器的值+1,并检查是否达到最大重试次数,如果达到则报错并停止归档操作 //若没有达到最大重试次数,则等待一秒,继续尝试归档 if (t_thrd.arch.got_SIGTERM || !PostmasterIsAlive()) return; if (t_thrd.arch.got_SIGHUP) { ProcessConfigFile(PGC_SIGHUP); if (!XLogArchivingActive()) { return; } t_thrd.arch.got_SIGHUP = false; } if (!XLogArchiveCommandSet() && !XLogArchiveDestSet()) { ereport(WARNING, (errmsg("archive_mode enabled, yet archive_command or archive_dest is not set"))); return; } if (pgarch_archiveXlog(xlog)) { /* successful */ pgarch_archiveDone(xlog); break; /* out of inner retry loop */ } else { if (++failures >= NUM_ARCHIVE_RETRIES) { ereport(WARNING, (errmsg("xlog file \"%s\" could not be archived: too many failures", xlog))); return; /* give up archiving for now */ } pg_usleep(1000000L); /* wait a bit before retrying */ } } } }
  4. 获取需要归档的事务日志文件名 pgarch_readyXlog

    pgarch_readyXlog(char* xlog, int xlog_length) { //打开归档状态目录,并将返回的目录指针赋值给rldir rldir = AllocateDir(XLogArchiveStatusDir); //如果打开失败,则报错并返回 if (rldir == NULL) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open archive status directory \"%s\": %m", XLogArchiveStatusDir))); //进入while循环,不断读取一个目录项,将其存再rlde中,如果失败则退出循环 while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL) { int basenamelen = (int)strlen(rlde->d_name) - 6; //检查当前目录项的文件名是否符合格式要求,包括文件名长度、字符集和后缀名 //如果文件名符合要求,会进一步检查是否找到了更早的事务日志文件 //如果没有找到更早的文件,会将当前的文件名复制到newxlog数组中,并将found标记为true //如果找到了更早的文件,会将当前的文件名与newxlog数组中存储的文件名进行比较, //如果当前文件名更早,则将其复制到newxlog数组中,并将found标记为true if (basenamelen >= MIN_XFN_CHARS && basenamelen <= MAX_XFN_CHARS && strspn(rlde->d_name, VALID_XFN_CHARS) >= (size_t)basenamelen && strcmp(rlde->d_name + basenamelen, ".ready") == 0) { errno_t rc = EOK; if (!found) { rc = strcpy_s(newxlog, MAX_XFN_CHARS + 6 + 1, rlde->d_name); securec_check(rc, "\0", "\0"); found = true; } else { if (strcmp(rlde->d_name, newxlog) < 0) { rc = strcpy_s(newxlog, MAX_XFN_CHARS + 6 + 1, rlde->d_name); securec_check(rc, "\0", "\0"); } } } } FreeDir(rldir); //如果found标记为true,则将newxlog数组中的文件名复制到xlog数组中,并返回true if (found) { errno_t rc = EOK; /* truncate off the .ready */ newxlog[strlen(newxlog) - 6] = '\0'; rc = strcpy_s(xlog, (size_t)xlog_length, newxlog); securec_check(rc, "\0", "\0"); } return found; }
  5. 归档执行函数 pgarch_archiveXlog

    pgarch_archiveXlog(char* xlog) { //判断归档目录是否存在,如果不存在则创建 if (XLogArchiveDestSet()) { return PgarchArchiveXlogToDest(xlog); } //判断筛选一下xlogarchcmd,并执行,若rc不为0则执行失败,返回false,否则返回true rc = gs_popen_security(xlogarchcmd); }
  6. 归档完成函数 pgarch_archiveDone

    //主要是将归档目录下的.ready文件重命名为.done文件,至此完成归档流程 static void pgarch_archiveDone(const char* xlog) { char rlogready[MAXPGPATH]; char rlogdone[MAXPGPATH]; StatusFilePath(rlogready, MAXPGPATH, xlog, ".ready"); StatusFilePath(rlogdone, MAXPGPATH, xlog, ".done"); (void)durable_rename(rlogready, rlogdone, WARNING); }
最后修改时间:2025-02-11 15:54:31
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论