1. 为什么要进行(主从复制)读写分离
分布式环境下数据库的读写分离策略是解决数据库读写性能瓶颈的一个关键解决方案,更是最大限度了提高了应用中读取 (Read)数据的速度和并发量。
在进行数据库读写分离的时候,我们首先要进行数据库的主从配置,最简单的是一台Master和一台Slave(大型网站系统的话,当然会很复杂,这里只是分析了最简单的情况)。通过主从配置主从数据库保持了相同的数据,我们在进行读操作的时候访问从数据库Slave,在进行写操作的时候访问主数据库Master。这样的话就减轻了一台服务器的压力。
在进行读写分离案例分析的时候。首先,配置数据库的主从复制,使用mysqlreplicate命令快速搭建 Mysql 主从复制。
2.MySQL主从复制的原理
2.1MySQL主从复制的原理
2.2MySQL主从复制的基本过程
MySQL主从复制的两种情况:同步复制和异步复制,实际复制架构中大部分为异步复制。复制的基本过程如下:
- Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。
- Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置。
- Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”。
- Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。
3.开始MySQL5.7.12的主从复制教程:
3.1 MySQL5.6开始主从复制有两种方式:基于日志(binlog);基于GTID(全局事务标示符)。
需要注意的是:GTID方式不支持临时表!所以如果你的业务系统要用到临时表的话就不要考虑这种方式了,至少目前最新版本MySQL5.6.12的GTID复制还是不支持临时表的。
所以此篇教程主要是告诉大家如何通过日志(binlog)方式做主从复制!
3.2 MySQL官方提供的MySQL Replication教程:
http://dev.mysql.com/doc/refman/5.6/en/replication.html
这个官方教程强烈建议大家阅读。
3.3、准备工作:
- 配置MySQL主从复制(读写分离)之前,需要在主从两台服务器先安装好MySQL5.7。
- 目前最新的MySQL5.7 GA版本是MySQL5.7.12(点此下载MySQL5.7.12源码包)。
- 需要注意如下两点:
(1)如果你需要用于生产环境,安教程安装MySQL时不要急着做mysql启动操作。建议把mysql初始化生成的/usr/local/mysql/mysql.cnf删除,然后把你优化好的mysql配置文件my.cnf放到/etc下。
(2)建议主备两台服务器在同一局域网,主备两台数据库网络需要互通。
- 我的所使用的环境:
主数据库IP:192.168.0.104
从数据库IP:192.168.0.105
3.4 修改主数据库的的配置文件:
|
|
修改之后要重启mysql服务:
3.5、修改从数据库的的配置文件:
注意:(server-id配置为大于主数据库的server-id即可)
|
|
修改之后要重启mysql:
|
|
附一个我已优化过的从数据库配置文件:点此下载
3.6、SSH登录到主数据库:
3.6.1. 在主数据库上创建用于主从复制的账户(192.168.0.104换成你的从数据库IP):
|
|
3.6.2. 主数据库锁表(禁止再插入数据以获取主数据库的的二进制日志坐标):
mysql> FLUSH TABLES WITH READ LOCK;
3.6.3. 然后克隆一个SSH会话窗口,在这个窗口打开MySQL命令行:
在这个例子中,二进制日志文件是mysqlmaster-bin.000001,位置是332,记录下这两个值,稍后要用到。
3.6.4 在主数据库上使用mysqldump命令创建一个数据快照:
mysqldump -uroot -p -h127.0.0.1 -P3306 –all-databases –triggers –routines –events >all.sql
注意:接下来会提示你输入mysql数据库的root密码,输入完成后,如果当前数据库不大,很快就能导出完成。
3.6.5 解锁第2.6.2步主数据的锁表操作:
mysql> UNLOCK TABLES;
3.7、SSH登录到从数据库:
(1)通过FTP、SFTP或其他方式,将上一步备份的主数据库快照all.sql上传到从数据库某个路径,例如我放在了/home/lidong/目录下;
(2)从导入主的快照:
cd /home/lidong
# mysql -uroot -p -h127.0.0.1 -P3306 < all.sql
注意:接下来会提示你输入mysql数据库的root密码,输入完成后,如果当前数据库不大,很快就能导入完成。
(3)给从数据库设置复制的主数据库信息(注意修改MASTER_LOG_FILE和MASTER_LOG_POS的值):
|
|
(4)接下来我们可以在主数据库上创建数据库、表、插入数据,然后看从数据库是否同步了这些操作。
一主一从的主从复制就实现了。
4、实现读写分离的两种方法
- 第一种方式是我们最常用的方式,就是定义2个数据库连接,一个是MasterDataSource,另一个是SlaveDataSource。更新数据时我们读取MasterDataSource,查询数据时我们读取SlaveDataSource。这种方式很简单。
- 第二种方式动态数据源切换,就是在程序运行时,把数据源动态织入到程序中,从而选择读取主库还是从库。主要使用的技术是:Annotation,spring AOP ,反射。
5.Spring AOP 实现MySQL读写分离的具体实现
5.1创建用于配置动态分配的读写的数据源ChooseDataSource.java
|
|
5.2 DataSourceAspect进行具体方法的AOP拦截
|
|
5.3 数据源的Handler类 DataSourceHandler.java
|
|
5.4 spring-db.xml读写数据源配置
|
|
配置了readDataSource和writeDataSource两个数据源,但是交给
SqlSessionFactoryBean进行管理的只有dataSource,使用了com.lidong.util.aspect.ChooseDataSource来进行数据源的选择,默认的数据源是writeDataSource。methodType是定义了方法的关键字,那些是选择读库,那个是写库。
5.5 在Dao层通过切面选择数据源
|
|
注意:通过看com.alibaba.druid.pool.DruidDataSourceStatLoggerImpl 是一分钟发一次心跳,监听写数据源有没有宕机。如果宕机会进行重连。