1. 读写分离&读写分离 简介

  • 主从同步延迟
  • 分配机制
  • 解决单点故障
  • 总结

2. 主从复制&读写分离 搭建

  • 搭建主从复制(双主)
  • 搭建读写分离

1. 读写分离&读写分离 简介

随着用户和数据的增多,单机的数据库往往支撑不住快速发展的业务,所以数据库集群就产生了!

读写分离顾名思义就是读和写分离,对应到数据库集群一般都是一主一从(一个主库,一个从库)或者一主多从(一个主库,多个从库),业务服务器把需要写的操作都写到主数据库中,读的操作都去从库查询。主库会同步数据到从库保证数据的一致性。

这种集群方式的本质是把访问的压力从主库转移到从库也就是在单机数据库无法支撑并发读写,并且读的请求很多的情况下适合这种读写分离的数据库集群。如果写的操作很多的话不适合这种集群方式,因为你的数据库压力还是在写操作上,即使主从了之后压力还是在主库上,这样和单机的区别就不大了。

在单机的情况下,一般我们做数据库优化都会加索引,但是加了索引对查询有优化,但会影响写入,因为写入数据会更新索引。所以做了主从之后,我们可以单独地针对从库(读库)做索引上的优化,而主库(写库)可以减少索引而提高写的效率。

还有两点要注意:主从同步延迟、分配机制的考虑。

主从同步延迟

主库有数据写入之后,同时也写入在binlog(二进制日志文件)中,从库是通过 binlog 文件来同步数据的,这期间会有一定时间的延迟,可能是 1 秒,如果同时有大量数据写入的话,时间可能更长。

这会导致什么问题呢?比如有一个付款操作,你付款了,主库是已经写入数据,但是查询是到从库查,从库里还没有你的付款记录,所以页面上查询的时候你还没付款。那可不急眼了啊,吞钱了这还了得!打电话给客服投诉!

所以为了解决主从同步延迟的问题有以下几个方法:

1)二次读取

二次读取的意思就是读从库没读到之后再去主库读一下,只要通过对数据库访问的 API 进行封装就能实现这个功能。很简单,并且和业务之间没有耦合。但是有个问题,如果有很多二次读取相当于压力还是回到了主库身上,等于读写分离白分了。而且如有人恶意攻击,就一直访问没有的数据,那主库就可能爆了。

2)写之后的马上的读操作访问主库

也就是写操作之后,立马的读操作指定为访问主库,之后的读操作则访问从库。这就等于写死了,和业务强耦合了。

3)关键业务读写都由主库承担,非关键业务读写分离

类似付钱的这种业务,读写都到主库,避免延迟的问题,但是例如改个头像啊,个人签名这种比较不重要的就读写分离,查询都去从库查,毕竟延迟一下影响也不大,不会立马打客服电话投诉。

分配机制

分配机制的考虑也就是怎么制定写操作是去主库写,读操作是去从库读。

一般有两种方式:代码封装、数据库中间件。

1)代码封装

代码封装的实现很简单,就是抽出一个中间层,让这个中间层来实现读写分离和数据库连接。讲白点就是搞个 provider 封装了 save、select 等通常数据库操作,内部 save 操作的 dataSource 是主库的,select 操作的 dataSource 是从库的。

优点:

  1. 实现简单。
  2. 可以根据业务定制化变化,随心所欲。

缺点:

  1. 如果哪个数据库宕机了,发生主从切换了之后,就得修改配置重启。
  2. 如果系统很大,一个业务可能包含多个子系统,一个子系统是 java 写的,一个子系统用 go 写的,这样的话得分别为不同语言实现一套中间层,重复开发。

2)数据库中间件

就是有一个独立的系统,专门来实现读写分离和数据库连接管理,业务服务器和数据库中间件之间是通过标准的 SQL 协议交流的,所以在业务服务器看来数据库中间件其实就是个数据库。

优点:

  1. 因为是通过 SQL 协议的所以可以兼容不同的语言不需要单独写一套。
  2. 由中间件来实现主从切换,业务服务器不需要关心这点。

缺点:

  1. 多了一个系统其实就等于多了一个关心,比如数据库中间件挂了。
  2. 多了一个系统就等于多了一个瓶颈,所以对中间件的性能要求也高,因为所有的数据库操作都要先经过它。
  3. 中间件实现较为复杂,难度比代码封装高多了。

常用的开源数据库中间件有 Mysql Proxy、Atlas、LVS 等。

为什么使用 MySQL-Proxy 而不是 LVS?

  • LVS:分不清读还是写;不支持事务。
  • MySQL-Proxy:自动区分读操作和写操作;支持事务(注意在 MySQL-Proxy 中不要使用嵌套查询,否则会造成读和写的混乱)。

解决单点故障

解决 Proxy 单点故障问题

MySQL-Proxy 实际上非常不稳定,在高并发或有错误连接的情况下,进程很容易自动关闭,因此打开 --keepalive 参数让进程自动恢复是个比较好的办法,但还是不能从根本上解决问题,通常最稳妥的做法是在每个应用服务器(如 Tomcat)上安装一个 MySQL-Proxy 供自身使用(解决 Proxy 单点故障问题),虽然比较低效但却能保证稳定性。

双(多)主机制

Proxy 之后搭 LVS,LVS 为两台主数据库做负载均衡,从数据库从两台主数据库同步。此方案旨在解决:

  • 主数据库的单点故障问题(服务不可用、备份问题)
  • 分担写操作的访问压力。

不过多主需要考虑自增长 ID 问题,这个需要特别设置配置文件,比如双主可以使用奇偶。总之,主之间设置自增长 ID 相互不冲突就能解决自增长 ID 冲突问题。

总结

读写分离相对而言是比较简单的,比分表分库简单,但是它只能分担访问的压力,分担不了存储的压力,也就是你的数据库表的数据逐渐增多,但是面对一张表海量的数据,查询还是很慢的,所以如果业务发展的快数据暴增,到一定时间还是得分库分表。

正常情况下,只有当单机真的顶不住压力了才会集群,不要一上来就集群,没这个必要。有关于软件的东西都是越简单越好,复杂都是形势所迫。

一般我们是先优化单机,如优化一些慢查询,优化业务逻辑的调用或者加入缓存等。如果真的优化到没东西优化了,然后才上集群。先读写分离,读写分离之后顶不住就再分库分表。

2. 主从复制&读写分离 搭建

主从同步的方式也分很多种,一主多从、链式主从、多主多从,根据你的需要来进行设置。

搭建主从复制(双主)

1)服务器二台:分别安装 MySQL 数据库

  1. 安装命令:yum -y install mysql-server
  2. 配置登录用户的密码:mysqladmin -u root password '密码'
  3. 配置允许第三方机器访问本机 MySQL:
delete from user where password = '';
update user set host='%';
flush privileges;

2)分别修改 MySQL 配置

配置 masterA:

[root@adailinux ~]# vim /etc/my.cnf
[mysqld]
datadir = /data/mysql
socket = /tmp/mysql.sock
server_id = 1 # 指定server-id,必须保证主从服务器的server-id不同
auto_increment_increment = 2 # 设置主键单次增量
auto_increment_offset = 1 # 设置单次增量中主键的偏移量:奇数
log_bin = mysql-bin # 创建主从需要开启log-bin日志文件
log-slave-updates # 把更新的日志写到二进制文件(binlog)中,台服务器既做主库又做从库此选项必须要开启

配置 masterB:

[root@adailinux ~]# vim /etc/my.cnf
[mysqld]
datadir = /data/mysql
socket = /tmp/mysql.sock
server_id = 2 # 指定server-id,必须保证主从服务器的server-id不同
auto_increment_increment = 2 # 设置主键单次增量
auto_increment_offset = 2 # 设置单次增量中主键的偏移量:偶数
log_bin = mysql-bin # 创建主从需要开启log-bin日志文件
log-slave-updates = True # 把更新的日志写到二进制文件(binlog)中

以上为同步配置的核心参数。

server_id 有两个用途:

  1. 用来标记 binlog event 的源产地,就是 SQL 语句最开始源自于哪里。
  2. 用于 IO_thread 对主库 binlog 的过滤。如果没有设置 replicate-same-server-id=1 ,那么当从库的 IO_thread 发现 event 的源与自己的 server-id 相同时,就会跳过该 event,不把该 event 写入到 relay log 中。从库的 sql_thread 自然就不会执行该 event。这在链式或双主结构中可以避免 sql 语句的无限循环。

注意:如果设置多个从服务器,每个从服务器必须有一个唯一的 server-id 值,且与主服务器的以及其它从服务器的都不相同。

分别重启 masterA 和 masterB 并查看主库状态:

[root@adailinux ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS!
Starting MySQL. SUCCESS! masterA:
[root@adailinux ~]# mysql -uroot
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 419 | TSC | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec) masterB:
[root@adailinux ~]# mysql -uroot
mysql> show master status
-> ;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 419 | TSC | mysql | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

3)配置同步信息

masterA:

[root@adailinux ~]# mysql -uroot
mysql> change master to master_host='192.168.8.132',master_port=3306,master_user='repl',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=419;
#注:IP为masterB的IP(即,从服务器的IP)
mysql> start slave;
Query OK, 0 rows affected (0.05 sec) mysql> show slave status\G;
在此查看有如下状态说明配置成功:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

masterB:

[root@adailinux ~]# mysql -uroot
mysql>change master to master_host='192.168.8.131',master_port=3306,master_user='repl',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=419;
Query OK, 0 rows affected, 2 warnings (0.06 sec) mysql> start slave;
Query OK, 0 rows affected (0.04 sec) mysql> show slave status\G
在此查看有如下状态说明配置成功:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

4)测试主从同步

在 masterA 上创建一个库,验证 masterB 是否同步创建了该库。

搭建读写分离

场景描述:

  • 数据库 Master 主服务器
  • 数据库 Slave 从服务器
  • MySQL-Proxy 调度服务器

以下操作,均是在 MySQL-Proxy 调度服务器上进行的。

1)MySQL 服务器安装

2)检查/安装系统所需软件包

yum -y install gcc* gcc-c++* autoconf* automake* zlib* libxml* ncurses-devel* libmcrypt* libtool* flex* pkgconfig* libevent* glib* readline*

3)编译安装 lua

MySQL-Proxy 的读写分离主要是通过 rw-splitting.lua 脚本实现的,因此需要安装 lua。

方式 1:一般系统自带。

方式 2:手工安装。

这里我们建议采用源码包进行安装:

  1. cd /opt/install
  2. wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
  3. tar zvfxlua-5.2.3.tar.gz
  4. cd lua-5.1.4
  5. vi src/Makefile
  6. 在CFLAGS= -O2 -Wall $(MYCFLAGS) 这一行记录里加上-fPIC,更改为 CFLAGS= -O2 -Wall -fPIC$(MYCFLAGS) 来避免编译过程中出现错误。
  7. make linux(编译到内存)
  8. make install

4)安装 Mysql-Proxy

MySQL-Proxy 可通过此网址获得:http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/

推荐采用已经编译好的二进制版本,因为采用源码包进行编译时,最新版的 MySQL-Proxy 对 automake、glib 以及 libevent 的版本都有很高的要求,而这些软件包都是系统的基础套件,不建议强行进行更新。

并且这些已经编译好的二进制版本在解压后都在统一的目录内,因此建议选择以下版本:

  • 32 位 RHEL5 平台:http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.4-linux-rhel5-x86-32bit.tar.gz
  • 64 位 RHEL5 平台:http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.4-linux-rhel5-x86-64bit.tar.gz
tar -xzvf mysql-proxy-0.8.3-linux-rhel5-x86-64bit.tar.gz
mv mysql-proxy-0.8.3-linux-rhel5-x86-64bit /opt/mysql-proxy

创建 Mysql-Proxy 服务管理脚本:

cd /opt/mysql-proxy
mkdir scripts
cp share/doc/mysql-proxy/rw-splitting.lua scripts/
chmod +x /opt/mysql-proxy/scripts
mkdir /opt/mysql-proxy/run
mkdir /opt/mysql-proxy/log
mkdir /opt/mysql-proxy/scripts

5)修改读写分离脚本 rw-splitting.lua

修改默认连接,进行快速测试,不修改的话要达到连接数为 4 时才启用读写分离

vi /opt/mysql-proxy/scripts/rw-splitting.lua

-- connection pool
if not proxy.global.config.rwsplitthen
proxy.global.config.rwsplit = {
min_idle_connections = 1, //默认为4
max_idle_connections = 1, //默认为8
is_debug = false
}
end

proxy.conf:

[mysql-proxy]
admin-username=root
admin-password=admin
proxy-read-only-backend-addresses=192.168.188.143,192.168.188.139
proxy-backend-addresses=192.168.188.142
proxy-lua-script=/opt/mysql-proxy/bin/rw-splitting.lua
admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua

bin 目录下执行:

./mysql-proxy --defaults-file=/opt/mysql-proxy/proxy.conf

mysql-proxy 脚本参数详解:

  • --proxy_path=/opt/mysql-proxy/bin:定义 mysql-proxy 服务二进制文件路径。
  • --proxy-backend-addresses=192.168.10.130:3306:定义后端主服务器地址。
  • --proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua:定义 lua 读写分离脚本路径。
  • --proxy-id=/opt/mysql-proxy/run/mysql-proxy.pid:定义 mysql-proxy PID 文件路径。
  • --daemon:定义以守护进程模式启动。
  • --keepalive:使进程在异常关闭后能够自动恢复。
  • --pid-file=$PROXY_PID:定义 mysql-proxy PID 文件路径。
  • --user=mysql:以 mysql 用户身份启动服务。
  • --log-level=warning:定义 log 日志级别,由高到低分别有(error|warning|info|message|debug)。
  • --log-file=/opt/mysql-proxy/log/mysql-proxy.log:定义 log 日志文件路径。

6)测试读写分离 

  1. 登录 Proxy:mysql -u -p -h<proxy_ip> -P4040
  2. stop slave
  3. 在 Proxy 上插数据后,验证主数据库新增数据,而从没有新增数据。

MySQL 主从复制&读写分离 简介的更多相关文章

  1. mysql主从复制-读写分离

    mysql主从复制+读写分离 环境:mysql主:193.168.1.1mysql从:193.168.1.2amoeba代理:193.168.1.3########################## ...

  2. mysql主从复制-读写分离-原理

    Mysql主从复制和读写分离 在实际的生产环境中,如果对mysql数据库的读和写都在一台数据库服务器中操作,无论是在安全性.高可用性,还是高并发等各个方面都是不能满足实际需求的.因此,一般通过主从复制 ...

  3. Mycat+MySql 主从复制-读写分离 看这一篇就够了

    ​ 通过mycat和mysql的主从复制配合搭建数据库的读写分离,可以实现mysql的高可用性,下面我们来搭建mysql的读写分离. 1.一主一从 1.在node01上修改/etc/my.cnf的文件 ...

  4. mysql主从复制+读写分离 菜鸟入门

    MYsql主从复制 1.mysql主从复制原理: Master将数据变化记录到二进制日志中[binary log] Slave将master的二进制日志[binary log]拷贝到自己的中继日志[r ...

  5. MYSQL 主从复制,读写分离(8)

    Mysql 数据库的主从复制方案,是其自带的功能,并且主从复制并不是复制磁盘上的数据文件,而是通过binlog日志复制到需要同步的服务器上. 一 主从复制的原理实现 原理图解说: 数据库更改 生成数据 ...

  6. Mycat实现mysql主从复制(读写分离)

    数据库性能瓶颈主要原因: 随着用户数的增多,带来的是数据库连接的大幅度增长 随着业务体量的增长,表数据量(空间存储的问题)的大幅增长,其中涉及到索引的优化,mysql默认的索引是硬盘级别的,BTREE ...

  7. Mysql主从复制读写分离

    一.前言:为什么MySQL要做主从复制(读写分离)?通俗来讲,如果对数据库的读和写都在同一个数据库服务器中操作,业务系统性能会降低.为了提升业务系统性能,优化用户体验,可以通过做主从复制(读写分离)来 ...

  8. MySQL主从复制&读写分离&分库分表

    MySQL主从复制 MySQL的主从复制只能保证主机对外提供服务,从机是不提供服务的,只是在后台为主机进行备份数据 首先我们说说主从复制的原理,这个是必须要理解的玩意儿: 理解: MySQL之间的数据 ...

  9. MySQL主从复制读写分离如何提高从库性能-实战

    在做主从读写分离时候,需要注意主从的一些不同参数设置,来提高从库的性能,提高应用读取数据的速度,这样做很有必要的. 做读写分离复制主从参数不同设置如下(需要根据自己应用实际情况来设置): parmet ...

随机推荐

  1. 票据传递攻击(Pass the Ticket,PtT)

    目录 黄金票据 生成票据并导入 查看票据 验证是否成功 黄金票据和白银票据的不同 票据传递攻击(PtT)是一种使用Kerberos票据代替明文密码或NTLM哈希的方法.PtT最常见的用途可能是使用黄金 ...

  2. Win64 驱动内核编程-12.回调监控进线程创建和退出

    回调监控进线程创建和退出 两个注册回调的函数:PsSetCreateProcessNotifyRoutine   进程回调PsSetCreateThreadNotifyRoutine    线程回调分 ...

  3. web php wrong nginx config

    web php wrong nginx config 目录 web php wrong nginx config 题目描述 解题过程 信息收集 robots.txt hint.php Hack.php ...

  4. 简单写个logictic回归

    最近做华为软件精英挑战赛热身赛,给出的demo是使用logistic做的金融风控,比赛要求很严格,如果使用Python 进行训练那么不能使用任何第三方机器学习库,只能使用Python和原生numpy1 ...

  5. 精选Hive高频面试题11道,附答案详细解析(好文收藏)

    1. hive内部表和外部表的区别 未被external修饰的是内部表,被external修饰的为外部表. 区别: 内部表数据由Hive自身管理,外部表数据由HDFS管理: 内部表数据存储的位置是hi ...

  6. C++基于armadillo im2col的实现

    最近学习CNN,需要用到im2col这个函数,无奈网上没有多少使用armadillo的例子,而且armadillo库中似乎也没有这个函数,因此自己写了. im2col的原理网上一大把,我懒得写了. 1 ...

  7. MySQL配置HeartBeat实现心跳监控和浮动IP

    1. 初始化环境配置 /sbin/chkconfig --add mysqld /sbin/chkconfig mysqld on ln -s /usr/local/mysql/bin/mysql / ...

  8. KVM性能优化

    一.KVM为什么要调优 性能的损耗是关键.KVM采用全虚拟化技术,全虚拟化要由一个软件来模拟硬件,故有一定的损耗,特别是I/O,因此需要优化.KVM性能优化主要在CPU.内存.I/O这几方面.当然对于 ...

  9. 配置trunk和access

    配置trunk和access 拓扑图 PC地址设置 PC1 :192.168.1.1 vlan10 PC2 :192.168.1.2 vlan10 交换机配置 LSW3配置 <Huawei> ...

  10. 【Python成长之路】装逼的一行代码:快速共享文件

    [Python成长之路]装逼的一行代码:快速共享文件 2019-10-26 15:30:05 华为云 阅读数 335 文章标签: Python编程编程语言程序员Python开发 更多 分类专栏: 技术 ...