读写分离集群
读写分离 / 负载均衡集群¶
集群框图¶
-
在集群中,数据库部分有一主一备,当主下线时,备自动切换为主。数据库支持读写分离, 主库负责读写任务,备库负责只读任务,他们之间通过某种方式同步。
-
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)