iis服务器助手广告
返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中Old Master节点分析
  • 360
分享到

PostgreSQL中Old Master节点分析

2024-04-02 19:04:59 360人浏览 安东尼
摘要

本篇内容介绍了“postgresql中Old Master节点分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有

本篇内容介绍了“postgresql中Old Master节点分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

基于streaming replication搭建的Postgresql HA环境,如出现网络访问/硬件故障等原因导致Standby节点升级为Master节点,但Old Master节点数据库并未损坏,在排除故障后Old Master节点可以通过pg_rewind工具而不需要通过备份的方式成为New Master节点的Standby节点.
在执行命令pg_rewind时,到底做了什么?

零、原理

在PostgreSQL HA环境中,Standby节点升级为Master节点后,时间线会切换为新的时间线,比如从1变为2.而Old Master节点的时间线仍然为原来的时间线,比如仍为1,那么使用pg_rewind工具,Old Master节点如何从New Master节点读取相关的数据成为新的Standby节点?
简单来说,有以下几步:
1.确定New Master和Old Master数据一致性的Checkpoint位置.在该位置上,New Master和Old Master数据完全一致.这可以通过读取新Old Master节点时间线历史文件可以获得,该文件位于$PGDATA/pg_wal/目录下,文件名称为XX.history
2.Old Master节点根据上一步获取的Checkpoint读取本机日志文件WAL Record,获取在此Checkpoint之后出现变化的Block,并以链表的方式存储Block编号等信息
3.根据第2步获取的Block信息从New Master节点拷贝相应的Block,替换Old Master节点相应的Block
4.拷贝New Master节点上除数据文件外的所有其他文件,包括配置文件等(如果拷贝数据文件,与备份方式搭建区别不大)
5.Old Master启动数据库,应用从Checkpoint开始后的WAL Record.

在执行主备切换后,New Master节点的时间线切换为n + 1,通过pg_rewind可使Old Master在分叉点开始与New Master同步,成为New Standby节点.

一、数据结构

XLogRecPtr
64bit的WAL Record寻址空间地址.


typedef uint64 XLogRecPtr;

TimeLineID
时间线ID

typedef uint32 TimeLineID;

二、源码解读

pg_rewind的源码较为简单,详细请参考注释.

int
main(int arGC, char **argv)
{
    static struct option long_options[] = {
        {"help", no_argument, NULL, '?'},
        {"target-pgdata", required_argument, NULL, 'D'},
        {"source-pgdata", required_argument, NULL, 1},
        {"source-server", required_argument, NULL, 2},
        {"version", no_argument, NULL, 'V'},
        {"dry-run", no_argument, NULL, 'n'},
        {"no-sync", no_argument, NULL, 'N'},
        {"progress", no_argument, NULL, 'P'},
        {"debug", no_argument, NULL, 3},
        {NULL, 0, NULL, 0}
    };//命令选项
    int         option_index;//选项编号
    int         c;//字符ASCII码
    XLogRecPtr  divergerec;//分支点
    int         lastcommontliIndex;
    XLogRecPtr  chkptrec;//checkpoint Record位置
    TimeLineID  chkpttli;//时间线
    XLogRecPtr  chkptredo;checkpoint REDO位置
    size_t      size;
    char       *buffer;//缓冲区
    bool        rewind_needed;//是否需要rewind
    XLogRecPtr  endrec;//结束点
    TimeLineID  endtli;//结束时间线
    ControlFileData ControlFile_new;//新的控制文件
    set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_rewind"));
    progname = get_progname(argv[0]);
    
    //处理命令行参数
    if (argc > 1)
    {
        if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
        {
            usage(progname);
            exit(0);
        }
        if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
        {
            puts("pg_rewind (PostgreSQL) " PG_VERSION);
            exit(0);
        }
    }
    while ((c = getopt_long(argc, argv, "D:nNP", long_options, &option_index)) != -1)
    {
        switch (c)
        {
            case '?':
                fprintf(stderr, _("Try \"%s --help\" for more infORMation.\n"), progname);
                exit(1);
            case 'P':
                showprogress = true;
                break;
            case 'n':
                dry_run = true;
                break;
            case 'N':
                do_sync = false;
                break;
            case 3:
                debug = true;
                break;
            case 'D':           
                datadir_target = pg_strdup(optarg);
                break;
            case 1:             
                datadir_source = pg_strdup(optarg);
                break;
            case 2:             
                connstr_source = pg_strdup(optarg);
                break;
        }
    }
    if (datadir_source == NULL && connstr_source == NULL)
    {
        fprintf(stderr, _("%s: no source specified (--source-pgdata or --source-server)\n"), progname);
        fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
        exit(1);
    }
    if (datadir_source != NULL && connstr_source != NULL)
    {
        fprintf(stderr, _("%s: only one of --source-pgdata or --source-server can be specified\n"), progname);
        fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
        exit(1);
    }
    if (datadir_target == NULL)
    {
        fprintf(stderr, _("%s: no target data directory specified (--target-pgdata)\n"), progname);
        fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
        exit(1);
    }
    if (optind < argc)
    {
        fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
                progname, argv[optind]);
        fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
        exit(1);
    }
    
#ifndef WIN32
    if (geteuid() == 0)
    {
        //root用户
        fprintf(stderr, _("cannot be executed by \"root\"\n"));
        fprintf(stderr, _("You must run %s as the PostgreSQL superuser.\n"),
                progname);
        exit(1);
    }
#endif
    get_restricted_token(progname);
    
    //根据PGDATA的权限设置权限mask
    if (!GetDataDirectoryCreatePerm(datadir_target))
    {
        fprintf(stderr, _("%s: could not read permissions of directory \"%s\": %s\n"),
                progname, datadir_target, strerror(errno));
        exit(1);
    }
    umask(pg_mode_mask);
    
    //连接到远程服务器
    if (connstr_source)
        libpqConnect(connstr_source);
    
    //读取目标控制文件
    buffer = slurpFile(datadir_target, "global/pg_control", &size);
    digestControlFile(&ControlFile_target, buffer, size);
    pg_free(buffer);
    //读取源控制文件
    buffer = fetchFile("global/pg_control", &size);
    digestControlFile(&ControlFile_source, buffer, size);
    pg_free(buffer);
    sanityChecks();
    
    if (ControlFile_target.checkPointCopy.ThisTimeLineID == ControlFile_source.checkPointCopy.ThisTimeLineID)
    {
        printf(_("source and target cluster are on the same timeline\n"));
        rewind_needed = false;
    }
    else
    {
        //找到分叉点
        findCommonAncestorTimeline(&divergerec, &lastcommontliIndex);
        printf(_("servers diverged at WAL location %X/%X on timeline %u\n"),
               (uint32) (divergerec >> 32), (uint32) divergerec,
               targetHistory[lastcommontliIndex].tli);
        
        if (ControlFile_target.checkPoint >= divergerec)
        {
            //如果目标的checkpoint > 分叉点,则需要rewind
            rewind_needed = true;
        }
        else
        {
            //目标的checkpoint <= 分叉点
            XLogRecPtr  chkptendrec;
            
            //读取目标的checkpoint记录,检查在哪结束?
            chkptendrec = readOneRecord(datadir_target,
                                        ControlFile_target.checkPoint,
                                        targetNentries - 1);
            
            if (chkptendrec == divergerec)
                rewind_needed = false;
            else
                rewind_needed = true;
        }
    }
    if (!rewind_needed)
    {
        //不需要rewind,退出
        printf(_("no rewind required\n"));
        exit(0);
    }
    //找到目标cluster最后的checkpoint点
    findLastCheckpoint(datadir_target, divergerec,
                       lastcommontliIndex,
                       &chkptrec, &chkpttli, &chkptredo);
    printf(_("rewinding from last common checkpoint at %X/%X on timeline %u\n"),
           (uint32) (chkptrec >> 32), (uint32) chkptrec,
           chkpttli);
    
    //创建filemap
    filemap_create();
    pg_log(PG_PROGRESS, "reading source file list\n");
    fetchSourceFileList();
    pg_log(PG_PROGRESS, "reading target file list\n");
    traverse_datadir(datadir_target, &process_target_file);
    
    //构造filemap
    pg_log(PG_PROGRESS, "reading WAL in target\n");
    extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
                   ControlFile_target.checkPoint);
    filemap_finalize();
    if (showprogress)
        calculate_totals();
    
    //如为debug模式,则打印filemap
    if (debug)
        print_filemap();
    
    if (showprogress)
    {
        pg_log(PG_PROGRESS, "need to copy %lu MB (total source directory size is %lu MB)\n",
               (unsigned long) (filemap->fetch_size / (1024 * 1024)),
               (unsigned long) (filemap->total_size / (1024 * 1024)));
        fetch_size = filemap->fetch_size;
        fetch_done = 0;
    }
    
    //
    executeFileMap();
    progress_report(true);
    //创建backup_label文件并更新控制文件
    pg_log(PG_PROGRESS, "\ncreating backup label and updating control file\n");
    createBackupLabel(chkptredo, chkpttli, chkptrec);
    
    //更新控制文件
    memcpy(&ControlFile_new, &ControlFile_source, sizeof(ControlFileData));
    if (connstr_source)
    {
        //获取源WAL插入的位置
        endrec = libpqGetCurrentXlogInsertLocation();
        //获取时间线
        endtli = ControlFile_source.checkPointCopy.ThisTimeLineID;
    }
    else
    {
        endrec = ControlFile_source.checkPoint;
        endtli = ControlFile_source.checkPointCopy.ThisTimeLineID;
    }
    //更新控制文件
    ControlFile_new.minRecoveryPoint = endrec;
    ControlFile_new.minRecoveryPointTLI = endtli;
    ControlFile_new.state = DB_IN_ARCHive_RECOVERY;
    update_controlfile(datadir_target, progname, &ControlFile_new, do_sync);
    pg_log(PG_PROGRESS, "syncing target data directory\n");
    //同步数据目录(除数据文件之外)
    syncTargetDirectory();
    printf(_("Done!\n"));
    return 0;
}

“PostgreSQL中Old Master节点分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL中Old Master节点分析

本文链接: https://www.lsjlt.com/news/64130.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • PostgreSQL中Old Master节点分析
    本篇内容介绍了“PostgreSQL中Old Master节点分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有...
    99+
    2024-04-02
  • kubernetes中Master节点如何安装与配置
    这篇文章主要介绍kubernetes中Master节点如何安装与配置,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一:简介1.kubernetes master节点包含以下组件:kube-apiserver,kube...
    99+
    2023-06-04
  • Redis集群中新增节点(master、slave)(实验)
    新增master节点的配置文件:    # vim /usr/local/redis-3.0.6-6379/redis.conf        daemonize yes                  ...
    99+
    2024-04-02
  • Mybatis中SQL节点实例分析
    这篇文章主要讲解了“Mybatis中SQL节点实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mybatis中SQL节点实例分析”吧!一、文章引出原因某天在完成项目中的一个小功能后进行...
    99+
    2023-06-29
  • JQuery中DOM节点的示例分析
    小编给大家分享一下JQuery中DOM节点的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!具体如下:Jquery中DOM...
    99+
    2024-04-02
  • HTML中DOM节点的示例分析
    小编给大家分享一下HTML中DOM节点的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!  在HTML DOM中,所有事物...
    99+
    2024-04-02
  • PostgreSQL中StartLogStreamer分析
    本篇内容主要讲解“PostgreSQL中StartLogStreamer分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中StartLog...
    99+
    2024-04-02
  • redis单节点实例分析
    这篇文章主要讲解了“redis单节点实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“redis单节点实例分析”吧!1.安装jdk1.8[root@sht-sgmhadoopdn-04 ...
    99+
    2023-06-03
  • PostgreSQL中REDO point分析
    这篇文章主要介绍“PostgreSQL中REDO point分析”,在日常操作中,相信很多人在PostgreSQL中REDO point分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望...
    99+
    2024-04-02
  • Java 详解分析链表的中间节点
    目录1.题目描述2.解法3.复杂度1.题目描述 给定一个头结点为 head 的非空单链表,返回链表的中间结点。 如果有两个中间结点,则返回第二个中间结点。 题目...
    99+
    2024-04-02
  • React DOM-diff节点源码分析
    本篇内容介绍了“React DOM-diff节点源码分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!单节点单节点的dom-dif...
    99+
    2023-07-05
  • PostgreSQL中vacuum过程分析
    本篇内容主要讲解“PostgreSQL中vacuum过程分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中vacuum过程分析”吧!一、数...
    99+
    2024-04-02
  • 分析PostgreSQL中的tuple locks
    这篇文章主要介绍“分析PostgreSQL中的tuple locks”,在日常操作中,相信很多人在分析PostgreSQL中的tuple locks问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方...
    99+
    2024-04-02
  • PostgreSQL中match_unsorted_outer函数分析
    这篇文章主要讲解了“PostgreSQL中match_unsorted_outer函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL...
    99+
    2024-04-02
  • PostgreSQL中make_rel_from_joinlist函数分析
    这篇文章主要介绍“PostgreSQL中make_rel_from_joinlist函数分析”,在日常操作中,相信很多人在PostgreSQL中make_rel_from_joinlist函数分析问题上存在...
    99+
    2024-04-02
  • PostgreSQL中hash_inner_and_outer函数分析
    这篇文章主要讲解了“PostgreSQL中hash_inner_and_outer函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL...
    99+
    2024-04-02
  • PostgreSQL中sort_inner_and_outer函数分析
    这篇文章主要讲解了“PostgreSQL中sort_inner_and_outer函数分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“PostgreSQL...
    99+
    2024-04-02
  • JavaScript的节点操作实例分析
    今天小编给大家分享一下JavaScript的节点操作实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一...
    99+
    2024-04-02
  • PostgreSQL中的ProcessRepliesIfAny函数分析
    本篇内容主要讲解“PostgreSQL中的ProcessRepliesIfAny函数分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PostgreSQL中的P...
    99+
    2024-04-02
  • PostgreSQL中PlannedStmt的跟踪分析
    这篇文章主要为大家展示了“PostgreSQL中PlannedStmt的跟踪分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“PostgreSQL中Planne...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作