1 物理复制及逻辑复制对比
前文做了PostgreSQL物理复制的部署,其有如下主要优点
  • 物理层面完全一致,是主要的复制方式,其类似于Oracle的DG
  • 延迟低,事务执行过程中产生REDO record,实时的在备库apply,事务结束时,备库立马能见到数据
  • 物理复制的一致性、可靠性高,不必担心数据逻辑层面不一致
但是其又在实际使用的场景中存在一些无法满足的需求,例如:
  • 无法满足指定库或部分表的复制需求
  • 将多个数据库实例的数据汇聚到同一个目标库或将一个库的数据分发到多个不同的库
  • 不同的版本之间的复制
  • 不同库名之间的表同步
对于以上场景,物理复制时无法满足的,因此逻辑复制应运而生了。
逻辑复制的复制架构图如下:

 

图片来源于《PostgreSQL实战》

逻辑复制是基于逻辑解析,其核心原理是逻辑主库将Publication中表的WAL日志解析成一定格式并发送给逻辑备库,逻辑备库Subscription接收到解析后的WAL日志后进行重做,从而实现表数据同步。
 
2. 逻辑复制的部署
PS: 以下的逻辑从库可以在新的机器上部署,如在原先的从库上修改,需停止原实例,并将recovery.conf文件删除或重命名(如修改为recovery.conf.done)
2.1 修改主库的postgresql.conf
可以基于原先的物理复制的配置文件进行修改,配置逻辑复制主要需调整如下参数
  1. wal_level = logical
  2. max_wal_senders = 10
  3. max_replication_slots = 8
参数简要说明如下
  • wal_level:设置成logical才支持逻辑复制
  • max_wal_senders:由于每个订阅节点和流复制备库在主库上都会占用主库上一个WAL发送进程,因此此参数设置值需大于max_replication_slots参数值加上物理备库数量
  • max_replication_slots:设置值需大于订阅节点的数量
2.2 修改逻辑从库的postgresql.conf
逻辑从库的postgresql.conf也可以在物理复制的基础上修改,与主库不同的是主要修改如下参数
  1. wal_level = logical
  2. max_replication_slots = 8
  3. max_logical_replication_workers = 8
参数简要说明
  • wal_level:设置成logical才支持逻辑复制,逻辑从库可以视情况设置
  • max_replication_slots:设置数据库复制槽数量,应大于订阅节点的数量
  • max_logical_replication_workers:设置逻辑复制进程数,应大于订阅节点的数量,并且给表同步预留一些进程数量,此参数默认值为4
2.3 创建逻辑复制账号
  1. postgres=# CREATE USER logical_repl REPLICATION LOGIN CONNECTION LIMIT 8 ENCRYPTED PASSWORD 'logical_repl';
  2.  
  3. CREATE ROLE
逻辑复制用户需要REPLICATION权限即可,可以不需要SUPERUSER权限,之后需要在发布节点上将需要同步的表赋权给logical_repl用户,使logical_repl账号具有对这些表的读权限。
2.4 在逻辑主库上创建库及表
  1. /** 创建用于逻辑复制的主库 */
    [postgres@PG32 data]$ createdb sourcedb
    [postgres@PG32 data]$ psql -d sourcedb
    psql (11.4)
    Type "help" for help.
    sourcedb=# create table logical_tb1(id int primary key,name varchar(20));
2.5 逻辑从库上创建库及表
  1. /** 在逻辑从库上创建不同的库 */
    [postgres@PG33 data]$ createdb desdb
    [postgres@PG33 data]$ psql -d desdb
    psql (11.4)
    Type "help" for help.
    desdb=# create table logical_tb1(id int primary key,name varchar(20));
    CREATE TABLE
    desdb=#
注:逻辑复制的表结构需要手动在从库创建
2.6 在逻辑主库上创建发布
  1. /** 在发布主库上创建发布pub1,注意实在sourcedb库下执行 */
  2. sourcedb=# CREATE PUBLICATION pub1 FOR TABLE logical_tb1;
    CREATE PUBLICATION

如果需发布多张表 则表名间用逗号(,)分割,如果需发布所有库,则将FOR TABLE 调整为FOR ALL TABLES。

此时可以查看到如下信息
  1. sourcedb=# SELECT * FROM pg_publication;
  2. pubname | pubowner | puballtables | pubinsert | pubupdate | pubdelete | pubtruncate
  3. ---------+----------+--------------+-----------+-----------+-----------+-------------
  4. pub1 | 10 | f | t | t | t | t
  5. (1 row)
 
字段说明如下:
  • pubname: 指发布的名称
  • pubowner: 指发布的属主,可以和pg_user视图的usesysid字段关联查询得到属主具体信息
  • puballtables:是否发布数据库中的所有表,t表示发布数据库中所有已存在的表和以后新建的表
  • pubinsert: t表示仅发布表上的INSERT操作
  • pubupdate: t表示仅发布表上的UPDATE操作
  • pubdelete: t表示仅发布表上的DELETE操作
2.7 在逻辑从库上创建订阅
  1. desdb=# CREATE SUBSCRIPTION sub1 CONNECTION 'host=192.168.56.32 port=5432 user=logical_repl dbname=sourcedb password=logical_repl' PUBLICATION pub1;
  2. NOTICE: created replication slot "sub1" on publisher
  3. CREATE SUBSCRIPTION
创建成功后,可以在逻辑主库上查询到如下信息:
  1. sourcedb=# SELECT slot_name,plugin,slot_type,database,active,restart_lsn FROM pg_replication_slots where slot_name='sub1';
  2. slot_name | plugin | slot_type | database | active | restart_lsn
  3. -----------+----------+-----------+----------+--------+-------------
  4. sub1 | pgoutput | logical | sourcedb | t | 0/6022D30
  5. (1 row)
在逻辑从库上可以查询到如下信息:
  1. desdb=# SELECT * FROM pg_subscription;
  2. subdbid | subname | subowner | subenabled | subconninfo | subslotname | subsynccommit | subpublications
  3. ---------+---------+----------+------------+---------------------------------------------------------------------------------------+-------------+---------------+-----------------
  4. 24995 | sub1 | 10 | t | host=192.168.56.32 port=5432 user=logical_repl dbname=sourcedb password=logical_repl | sub1 | off | {pub1}
  5. (1 row)

2.8 给复制账号授权
因为步骤2.3中只创建了复制账号并未对需要复制的表进行授权,因此,此时逻辑从库的日志中有如下错误
  1. 2019-10-10 15:57:21.847 CST [] ERROR: could not start initial contents copy for table "public.logical_tb1": ERROR: permission denied for table logical_tb1
  2. 2019-10-10 15:57:21.848 CST [] LOG: background worker "logical replication worker" (PID 27443) exited with exit code 1
因此 ,现在需要对复制用户授权。
  1. sourcedb=# GRANT USAGE ON SCHEMA public TO logical_repl;
  2. GRANT
  3. sourcedb=# GRANT SELECT ON logical_tb1 TO logical_repl;
  4. GRANT
授权后,显示正常
  1. 2019-10-10 16:00:25.959 CST [] LOG: logical replication table synchronization worker for subscription "sub1", table "logical_tb1" has started
  2. 2019-10-10 16:00:25.967 CST [] LOG: logical replication table synchronization worker for subscription "sub1", table "logical_tb1" has finished
2.9 测试数据同步
在逻辑主库插入数据
  1. /** 在主库插入数据 */
  2. sourcedb=# insert into logical_tb1(id,name) values(1,'a'),(2,'bca');
  3. INSERT 0 2
在逻辑从库查看结果
  1. /** 查看数据是否同步完成 */
  2. desdb=# select * from logical_tb1;
  3. id | name
  4. ----+------
  5. 1 | a
  6. 2 | bca
  7. (2 rows)
由此可见数据已同步完成。
2.10 添加复制所需的表
在逻辑主库和逻辑从库均添加一张新表,并添加到发布列表中
  1. /** 主库上创建表结构 */
  2. sourcedb=# create table logical_tb2(id int primary key ,addr varchar(100));
    CREATE TABLE
  3. sourcedb=#
  4. /** 从库上创建表结构 */
  5. desdb=# create table logical_tb2(id int primary key ,addr varchar(100));
    CREATE TABLE
  6. /** 在主库上给逻辑复制账号授权 */
  7. sourcedb=# GRANT SELECT ON logical_tb2 TO logical_repl;
  8. GRANT
  9. /** 添加新表至发布列表 */
  10. sourcedb=# ALTER PUBLICATION pub1 ADD TABLE logical_tb2;
  11. ALTER PUBLICATION
  12. /** 在主库查看发布列表中的表名 */
  13. sourcedb=# SELECT * FROM pg_publication_tables;
  14. pubname | schemaname | tablename
  15. ---------+------------+-------------
  16. pub1 | public | logical_tb1
  17. pub1 | public | logical_tb2
  18. (2 rows)
此时已加入一张表进入发布列表中。
此时在主库写入数据,查看从库情况如下:
  1. /** 主库插入一条记录 */
  2. sourcedb=# insert into logical_tb2(id,addr) values(1,'beijing');
  3. INSERT 0 1
  4. /** 此时在逻辑从库查看,结果却没有数据 */
  5. desdb=# select * from logical_tb2;
  6. id | addr
  7. ----+------
  8. (0 rows)

因为还需要在从库刷新一下订阅

  1. /** 此时在从库刷新订阅 */
  2. desdb=# ALTER SUBSCRIPTION sub1 REFRESH PUBLICATION;
  3. /** 刷新完成后再查数据已经有数据了 */
  4. ALTER SUBSCRIPTION
  5. desdb=# select * from logical_tb2;
  6. id | addr
  7. ----+---------
  8. 1 | beijing
  9. (1 row)
至此,PostgreSQL的逻辑复制也部署完毕。
 
3. 物理复制与逻辑复制特点和应用场景
PostgreSQL的逻辑复制与物理复制的差异比较突出,在使用中可以根据其特点选择使用哪种复制方式。
  • 逻辑订阅,适合于发布端与订阅端都有读写的情况。
  • 逻辑订阅,更适合于小事务,或者低密度写(轻度写)的同步。如果有大事务、高密度写,逻辑订阅的延迟相比物理复制更高。
  • 逻辑订阅,适合于双向,多向同步。
  • 物理复制,适合于单向同步。
  • 物理复制,适合于任意事务,任意密度写(重度写)的同步。
  • 物理复制,适合于HA、容灾、读写分离。
  • 物理复制,适合于备库没有写,只有读的场景。

想进一步沟通或想了解其他文章的同学可以关注我的微信公众号进行交流

 

postgresql从库搭建--逻辑复制的更多相关文章

  1. postgresql从库搭建

    1 复制类型 PostgreSQL支持物理复制(流复制)及逻辑复制2种.通过流复制技术,可以从实例级复制出一个与主库一模一样的实例级的从库.流复制同步方式有同步.异步两种. 另一种复制方式为逻辑复制, ...

  2. PostgreSQL逻辑复制之pglogical篇

    PostgreSQL逻辑复制之slony篇 一.pglogical介绍 pglogical 是 PostgreSQL 的拓展模块, 为 PostgreSQL 数据库提供了逻辑流复制发布和订阅的功能. ...

  3. Windows 环境搭建 PostgreSQL 逻辑复制高可用架构数据库服务

    本文主要介绍 Windows 环境下搭建 PostgreSQL 的主从逻辑复制,关于 PostgreSQl 的相关运维文章,网络上大多都是 Linux 环境下的操作,鲜有在 Windows 环境下配置 ...

  4. PostgreSQL逻辑复制解密

    在数字化时代的今天,我们都认同数据会创造价值.为了最大化数据的价值,我们不停的建立着数据迁移的管道,从同构到异构,从关系型到非关系型,从云下到云上,从数仓到数据湖,试图在各种场景挖掘数据的价值.而在这 ...

  5. PostgreSQL逻辑复制使用记录

    之前逻辑复制刚刚出来的时候就使用过,但是没有进行整理,这次一个项目需要逻辑复制的自动迁移,再次拾起逻辑复制. 在此之前有两个疑问: 1)同一个表,既有流复制,又有逻辑复制,这样数据会有两份吗? --不 ...

  6. 跨 PostgreSQL 大版本复制怎么做?| 逻辑复制

    当需要升级PostgreSQL时,可以使用多种方法.为了避免应用程序停机,不是所有升级postgres的方法都适合,如果避免停机是必须的,那么可以考虑使用复制作为升级方法,并且根据方案,可以选择使用逻 ...

  7. PostgreSQL逻辑复制之slony篇

    Slony是PostgreSQL领域中最广泛的复制解决方案之一.它不仅是最古老的复制实现之一,它也是一个拥有最广泛的外部工具支持的工具,比如pgAdmin3.多年来,Slony是在PostgreSQL ...

  8. PostgreSQL逻辑复制槽

    Schema | Name | Result data type | Argument data types | Type ------------+------------------------- ...

  9. MySQL复制--最快的从库搭建方法(tar包) -转

    最快的从库搭建方法0,准备从库第一次数据备份,临时锁所有表开启窗口1 mysql> flush tables with read lock; Query OK, 0 rows affected  ...

随机推荐

  1. CodeForces 283C World Eater Brothers

    World Eater Brothers 题解: 树DP, 枚举每2个点作为国家. 然后计算出最小的答案. 首先我们枚举根, 枚举根了之后, 我们算出每个点的子树内部和谐之后的值是多少. 这样val[ ...

  2. 玲珑杯”ACM比赛 Round #18 A -- 计算几何你瞎暴力(瞎暴力)

    题目链接:http://www.ifrog.cc/acm/problem/1143?contest=1020&no=0 题解:就是瞎暴力具体多暴力看一下代码就知道了. #include < ...

  3. Codefroces 366 D Dima and Trap Graph (最短路)

    Dima and Trap Graph 题意:Dima和Inna越来越喜欢对方,但是Dima的室友缺很没有热情出去玩,然后Dima就把他室友Seryozha骗进了陷阱里.现在Seryozha想要从陷阱 ...

  4. lightoj 1037 - Agent 47(状压dp)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1037 #include <iostream> #include & ...

  5. Spring Boot与Spring MVC集成启动过程源码分析

    开源项目推荐 Pepper Metrics是我与同事开发的一个开源工具(https://github.com/zrbcool/pepper-metrics),其通过收集jedis/mybatis/ht ...

  6. springboot使用jdbcTemplate连接数据库

    springboot使用jdbcTemplate连接数据库 1.pom.xml: <?xml version="1.0" encoding="UTF-8" ...

  7. FreeSql (十七)联表查询

    FreeSql在查询数据下足了功能,链式查询语法.多表查询.表达式函数支持得非常到位. IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnect ...

  8. jinfo Java配置信息工具

    jinfo(Configuration info for Java) jinfo的作用是实时地查看和调整虚拟机各项参数. jinfo 命令格式: jinfo [ option ] pid pid是虚拟 ...

  9. eclipse wifi 连接手机

    参考:http://blog.csdn.net/onlyonecoder/article/details/9121397 首先打开手机的wifi设置,使其连接到网络.然后,需要在手机上对adb连接端口 ...

  10. 即时聊天APP(三) - 注册和登陆

    注册和登陆大多都是一些用户名和密码的验证,所以放在一起写,注册代码: String account = accountEdit.getText().toString().trim(); String ...