跳转至

读写分离集群

读写分离 / 负载均衡集群

集群框图

cluster

  • 在集群中,数据库部分有一主一备,当主下线时,备自动切换为主。数据库支持读写分离, 主库负责读写任务,备库负责只读任务,他们之间通过某种方式同步。

  • Coordinator对外负责提供对外一个虚拟IP,用来和客户端连接,对内负责管理数据库,主要负责负载均衡,读写分离以及主备数据库的高可用切换。 Coordinator本身也有一主一备,当主下线时,备自动切换为主,并接管虚拟IP。

数据库的读写分离

数据库集群由主数据库和热备数据库组成。

热备是指除了高可用外,还可以处理读请求的数据库;而温备是指平时不可读,只负责处理高可用。

主备之间通过复制WAL来实现同步,以达到读写分离的要求。

  • WAL同步

为了保证数据不丢失,数据库的写操作分两步:

* 先写事务日志,即write ahead log(WAL)

* 再更新数据库

主备之间通过复制WAL来实现同步,备收到WAL后通过回放日志来实现更新数据库。

同步时有多种同步方式选择:

synchronous_commit 适用性
off wal缓存 异步 如果主下线,集群会丢部分事务
local wal落盘 异步 如果备下线,备会丢失部分事务
remtoe_write wal落盘 wal缓存 如果备下线,备会丢失部分事务
on wal落盘 wal落盘 主备都不会丢事务,但从备读到的数据不一定最新
remote_apply wal落盘 wal落盘,数据回放完毕 主备都不会丢事务,并可以保证备读到的数据最新

可见如果需要读写分离集群,需要把synchronous_commit设为 remote_apply 方式。

  • 读写分离设置

在主数据库上,需要设置 seaboxsql.conf

synchronous_commit = remote_apply
synchronous_standby_names = 'some_name'

在备数据库,需要设置recovery.conf

standby_mode = on
primary_conninfo = 'application_name=some_name host=主库IP port=主库端口'
Coordinator实现负载均衡

客户端通过coordinator提供的虚拟IP连接到集群,coordinator收到sql后会先解析,如果是写sql只发给主数据库,如果是读sql则按一定权重分配给主、备数据库以实现负载均衡。

  • 虚拟IP

编辑coordinator.conf,指定一个虚拟IP, 如

delegate_IP = '192.168.1.1'
  • 哪些sql可以负载均衡

为了使查询达到负载平衡,必须是只读查询,需要满足以下所有要求

* 必须是以 SELECT / COPY TO STDOUT / EXPLAIN 开头的sql

* 不能是/* NO LOAD BALANCE */ 开头

* 不能是一个显示声明的事务块内(如BEGIN...COMMIT包围)的SQL   (但如果下面的情况都满足,则可算作只读查询)
  事务的隔离级别不是SERIALIZABLE
  事务尚未发出写查询(非SELECT DML或DDL)时的SELECT 查询
  不在白名单/黑名单内的SELECT查询
  • 不能是SELECT FOR UPDATE/SHARE

  • 不能是SELECT INFO

  • 不能使用临时表/unlogged表

  • 不能使用系统表

  • 负载均衡参数设置

load_balance_mode = on                     # 启用
ignore_leading_white_space = on            # 忽略sql前的空格
white_function_list = 逗号分隔的字符串      # 仅包含在白名单内的sql算只读,支持正则,如 'select_.*',
                                           # 如果为空,按默认规则
black_function_list = 逗号分隔的字符串      # 与白名单互斥,只能有一个生效, 黑名单优先级高
black_query_pattern_list = 分号分隔的字符串 # 语句级别的黑名单,如禁止SELECT * FROM table_name1; 负载均衡
                                           # 可以写作 SELECT \ * FROM table_name1 \ ;
allow_sql_comments = on|off                # 如果是off,则带注释的一律视为写请求,如果是on可以将只读查询负载均衡
disable_load_balance_on_write = on|off     # 如果是on,则写查询后面的所有操作都不再负载均衡,
                                           # 如果是off,对只读查询可以负载均衡
  • 查看负载平衡点

配置完毕后,可以通过命令来查看实际的情况,select_cnt 表示实际在节点上执行的select次数

test=# show coordinator_nodes;
node_id|hostname| port|status|lb_weight| role  |select_cnt|load_balance_node|replication_delay|replication_state|replication_sync_state|last_status_change  
-------+--------+-----+------+---------+-------+----------+-----------------+-----------------+-----------------+----------------------+-------------------
0      | /tmp   |11002| up   |0.500000 |primary| 0        |false            | 0               |                 |                      |2019-04-22 16:13:46
1      | /tmp   |11003| up   |0.500000 |standby| 0        |true             | 0               | streaming       | async                |2019-04-22 16:13:46
(2 rows)