高性能架构模式-读写分离

原理

将对数据库的读写请求分散到不同的节点, master节点处理写请求,slave节点处理读请求。

实现

以MySQL为例子,在单机环境下使用docker搭建一主一从的集群。

1. 配置准备

master

保存到./master/my.cnf

[mysqld]
## 设置server_id,一般设置为IP,注意要唯一
server_id=100  
## 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
binlog-ignore-db=mysql  
## 开启二进制日志功能,可以随便取,最好有含义(关键就是这里了)
log-bin=replicas-mysql-bin  
## 为每个session分配的内存,在事务过程中用来存储二进制日志的缓存
binlog_cache_size=1M  
## 主从复制的格式(mixed,statement,row,默认格式是statement)
binlog_format=mixed  
## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days=7  
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
salve

保存到./salve/my.cnf

[mysqld]
## 设置server_id,一般设置为IP,注意要唯一
server_id=101  
## 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
binlog-ignore-db=mysql  
## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
log-bin=replicas-mysql-slave1-bin  
## 为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存
binlog_cache_size=1M  
## 主从复制的格式(mixed,statement,row,默认格式是statement)
binlog_format=mixed  
## 二进制日志自动删除/过期的天数。默认值为0,表示不自动删除。
expire_logs_days=7  
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062  
## relay_log配置中继日志
relay_log=replicas-mysql-relay-bin  
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1  
## 防止改变数据(除了特殊的线程)
read_only=1  
docker-compose.yml

需要多从可以继续追加

version: '3'
services:
  mysql-master:
    image: mysql:5.7
    volumes:
    - ./master/my.cnf:/etc/mysql/my.cnf
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "MYSQL_DATABASE=replicas_db"
    links:
      - mysql-slave
    ports:
      - "33065:3306"
    restart: always
    hostname: mysql-master
  mysql-slave:
    image: mysql:5.7
    volumes:
    - ./slave/my.cnf:/etc/mysql/my.cnf
    environment:
      - "MYSQL_ROOT_PASSWORD=root"
      - "MYSQL_DATABASE=replicas_db"
    ports:
      - "33066:3306"
    restart: always
    hostname: mysql-slave

2. 启动服务(节点)

docker-compose up -d

3. 查看master状态

mysql> show master status\G
*************************** 1. row ***************************
             File: replicas-mysql-bin.000003
         Position: 154
     Binlog_Do_DB: 
 Binlog_Ignore_DB: mysql
Executed_Gtid_Set: 
1 row in set (0.00 sec)

4. salve关联master

访问salve节点
  • sudo docker exec -it mysql_mysql-slave_1 bash
  • mysql -uroot -proot
关联

change master to MASTER_HOST='mysql-master', MASTER_USER='root', MASTER_PASSWORD='root', MASTER_LOG_FILE='replicas-mysql-bin.000003', MASTER_LOG_POS=154;

5. 重启salve节点

sudo docker restart mysql_mysql-salve_1

6. 验证

在master节点创建一张表,并插入一条数据
use replicas_db;

create table test(
    id int auto_increment primary key,
    title varchar(255) not null
);

insert into test values(default, 'Hombio');
salve节点查询
use replicas_db;

show tables;

select * from test;

复杂度

读写分离的实现逻辑并不复杂,但有两个细节点将引入设计复杂度:主从复制延迟和分配机制。

1. 主从复制延迟

常见有以下三种解决方案

  • 写操作后的读操作指定发给数据库主服务器
    缺点:业务侵入性强
  • 读从机失败后再读一次主机
    缺点:二次读取,增加读压力
  • 关键业务读写操作全部指向主机,非关键业务采用读写分离

2. 分配机制

将读写操作区分开来,然后访问不同的数据库服务器,一般有两种方式:程序代码封装和中间件封装。

代码
  • 实现简单
  • 通用性差,每个编程语言都要实现一次
  • 如果发生主从切换,则所有的系统都要修改配置

开源方案:TDDL

中间件

中间件封装指的是独立一套系统出来,实现读写操作分离和数据库服务器连接的管理。对于业务服务器来说,访问中间件和访问数据库没有区别。

开源方案:MySQL Proxy, MySQL Router, Atlas

小结

读写分离适用单机并发无法支撑并且读的请求更多的情形。在单机数据库情况下,表上加索引一般对查询有优化作用却影响写入速度,读写分离后可以单独对读库进行优化,写库上减少索引,对读写的能力都有提升,且读的提升更多一些。如果并发写入特别高,单机写入无法支撑或者通过缓存技术或者程序优化能够满足要求,读写分离就不太适用了。

本例中的一主一从都存在单点故障问题,如果业务需要保证高可用,还需要分别冗余主从,主服务器可以采用主备结构,从服务器比较简单,多开几个从服务器即可,演变成一主多从。

参考

  1. https://time.geekbang.org/column/article/8269
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值