读写分离设置
概述
用户连接 Coordinator,执行 SQL 语句,最终数据的修改和查询都会访问 Datanode。一般情况下 Datanode 有同步或者异步备节点。如果是同步备节点,则数据与主节点实时一致,因此备节点可以提供数据查询的功能。但是当主节点正常工作时,备节点只提供数据备份的功能,造成机器资源的浪费。
AntDB 从 内核层面 实现了读写分离,打开读写分离的开关,就可以实现,执行的读操作访问备节点,写操作访问主节点,对应用层完全透明,有效提升主从机器资源的使用率,增加数据库的吞吐量。
读写分离控制参数
读写分离涉及的开关有两个,在 adbmgr 上通过参数设置的方式开启读写分离功能,如下:
有同步节点的情况下:
SET COORDINATOR all(enable_readsql_on_slave = on);
没有同步节点,只有异步节点,并希望异步节点提供读的功能的情况下:
SET COORDINATOR all(enable_readsql_on_slave = on);
SET COORDINATOR all( enable_readsql_on_slave_async = on);
- enable_readsql_on_slave:读写分离总开关。
- enable_readsql_on_slave_async:允许异步节点提供读的功能开关。
二者关系如下:
有同步 datanode | 没有同步,只有异步 datanode | |
---|---|---|
enable_readsql_on_slave = on | 访问同步节点 | 先设置 enable_readsql_on_slave_async = on,访问异步节点 |
enable_readsql_on_slave = off | 不提供读写分离功能 | 不提供读写分离功能 |
注意:在并发读写的场景中,如果异步节点提供读的功能,可能出现由于数据同步时间差的问题,导致刚写入的数据查询不到。
某些场景下,开启读写分离且 master 流复制为同步的时候,在 master 节点上执行了 DML 操作,备节点立即查询的时候,发现查不到对应的数据。原因是 master 节点的 DML 操作在 slave 节点还没 apply,导致发送到 slave 节点的查询操作读不到最新的数据。如果想避免这种情况的出现,可以设置 datanode 的 synchronous_commit
参数为 remote_apply
,确保 master 的操作在 slave 上 apply 之后,才给客户端返回消息。
登录到 mgr 上,执行以下命令,并重启。
SET DATANODE all(synchronous_commit = 'remote_apply');
需要注意的是:设置为 remote_apply
后,会有一定的性能损失。
检测读写分离功能
读写分离启动之前,pgxc_node
表中的信息:
antdb=# SELECT oid, node_name, node_type FROM pgxc_node;
oid | node_name | node_type
-------+-----------+-----------
16384 | gcn1 | C
11955 | cn1 | C
16385 | cn2 | C
16386 | cn3 | C
16387 | cn4 | C
16388 | dn1_1 | D
16389 | dn2_1 | D
16390 | dn3_1 | D
16391 | dn4_1 | D
(9 rows)
没有 slave 节点信息,所以读操作发到 master 节点上:
antdb=# EXPLAIN (analyze,verbose) SELECT * FROM t_demo WHERE id =10;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
Data Node Scan on "__REMOTE_FQS_QUERY__" (cost=0.00..0.00 rows=0 width=0) (actual time=10.700..10.705 rows=1 loops=1)
Output: t_demo.id, t_demo.name
Node/s: dn2_1
Remote query: SELECT id, name FROM public.t_demo t_demo WHERE (id = 10)
Planning Time: 0.267 ms
Execution Time: 10.745 ms
(6 rows)
dn2_1
为 master 节点。
读写分离启用后,在 coord 的 pgxc_node
表中,会有 slave 节点信息:
antdb=# SELECT oid, node_name, node_type FROM pgxc_node;
oid | node_name | node_type
-------+-----------+-----------
16384 | gcn1 | C
11955 | cn1 | C
16385 | cn2 | C
16386 | cn3 | C
16387 | cn4 | C
16388 | dn1_1 | D
16389 | dn2_1 | D
16390 | dn3_1 | D
16391 | dn4_1 | D
16402 | dn1_2 | E
16403 | dn2_2 | E
16404 | dn3_2 | E
16405 | dn4_2 | E
(13 rows)
上述结果中,E
类型的节点即是 slave 节点。
读操作发到 slave 节点上:
antdb=# EXPLAIN (analyze,verbose) SELECT * FROM t_demo WHERE id =10;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
Data Node Scan on "__REMOTE_FQS_QUERY__" (cost=0.00..0.00 rows=0 width=0) (actual time=17.571..17.576 rows=1 loops=1)
Output: t_demo.id, t_demo.name
Node/s: dn2_2
Remote query: SELECT id, name FROM public.t_demo t_demo WHERE (id = 10)
Planning Time: 0.319 ms
Execution Time: 17.636 ms
(6 rows)
dn2_2
为 slave 节点。