使用Spring AOP实现读写分离(MySql实现主从复制)
1. 背景
我们一般应用对数据库而言都是“读多写少”,也就说对数据库读取数据的压力比较大,有一个思路就是说采用数据库集群的方案,
其中一个是主库,负责写入数据,我们称之为:写库;
其它都是从库,负责读取数据,我们称之为:读库;
那么,对我们的要求是:
1、读库和写库的数据一致;
2、写数据必须写到写库;
3、读数据必须到读库;
2. 实现方案
解决读写分离的方案有两种:应用层解决和中间件解决。
1.应用层
目前的一些解决方案需要在程序中手动指定数据源,比较麻烦,后边我会通过AOP思想来解决这个问题
2,中间件
MySQL-proxy:http://hi.baidu.com/geshuai2008/item/0ded5389c685645f850fab07
Amoeba for MySQL:http://www.iteye.com/topic/188598和http://www.iteye.com/topic/1113437
此处我们介绍一种在应用层的解决方案,通过spring动态数据源和AOP来解决数据库的读写分离。
该方案目前已经在一个互联网项目中使用了,而且可以很好的工作。
该方案目前支持
一读多写;当写时默认读操作到写库、当写时强制读操作到读库。
考虑未来支持
读库负载均衡、读库故障转移等。
使用场景
不想引入中间件,想在应用层解决读写分离,可以考虑这个方案;
建议数据访问层使用jdbc、ibatis,不建议hibernate。
优势
应用层解决,不引入额外中间件;
在应用层支持『当写时默认读操作到写库』,这样如果我们采用这种方案,在写操作后读数据直接从写库拿,不会产生数据复制的延迟问题;
应用层解决读写分离,理论支持任意数据库。
缺点
1、不支持@Transactional注解事务,此方案要求所有读方法必须是read-only=true,因此如果是@Transactional,这样就要求在每一个读方法头上加@Transactional 且readOnly属性=true,相当麻烦。 :oops:
2、必须按照配置约定进行配置,不够灵活
2.1. 应用层解决
优点:
1、源程序不需要做任何改动就可以实现读写分离;
2、动态添加数据源不需要重启程序;
缺点:
1、程序依赖于中间件,会导致切换数据库变得困难;
2、由中间件做了中转代理,性能有所下降;
相关中间件产品使用:
MySQL-proxy:http://hi.baidu.com/geshuai2008/item/0ded5389c685645f850fab07
Amoeba for MySQL:http://www.iteye.com/topic/188598和http://www.iteye.com/topic/1113437
3. 使用Spring基于应用层实现
3.1. 原理
3.2. DynamicDataSource
AbstractRoutingDataSource这个类 是spring2.0以后增加的,我们先来看下AbstractRoutingDataSource的定义:
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {}
3.3. DynamicDataSourceHolder
使用ThreadLocal技术来记录当前线程中的数据源的key
5. 一主多从的实现
6. MySQL主从复制
6.1. 原理
1、master将数据改变记录到二进制日志(binarylog)中,也即是配置文件log-bin指定的文件(这些记录叫做二进制日志事件,binary log events)
2、slave将master的binary logevents拷贝到它的中继日志(relay log)
3、slave重做中继日志中的事件,将改变反映它自己的数据(数据重演)
6.2. 主从配置需要注意的地方
2、主DB server和从DB server数据库数据一致[ 这里就会可以把主的备份在从上还原,也可以直接将主的数据目录拷贝到从的相应数据目录]
3、主DB server开启二进制日志,主DB server和从DB server的server_id都必须唯一
6.3. 主库配置(windows,Linux下也类似)
第一步,主服务器创建用户并清空日志
mysql> show privileges;
mysql> grant replication client, replication slave on *.* to 'larry'@'192.168.1.%' identified by 'larry';
mysql> show binary logs;
mysql> reset master;
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 107 |
+------------------+-----------+
1 row in set (0.00 sec)
第二步,修改从服务器的server-id,把server-id改为2然后重启mysql
[root@serv08 ~]# cat /etc/my.cnf | grep server-id
server-id = 1
#server-id = 2
[root@serv08 ~]# vim /etc/my.cnf
[root@serv08 ~]# cat /etc/my.cnf | grep server-id
server-id = 2
#server-id = 2
[root@serv08 ~]# /etc/init.d/mysqld restart
第三步,从服务器清空日志
mysql> show binary logs;
mysql> reset master;
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 107 |
+------------------+-----------+
1 row in set (0.00 sec) mysql> show slave status;
Empty set (0.00 sec)
第四步,从服务器通过change master to命令修改设置
mysql> change master to
-> master_host='192.168.1.11',
-> master_user='larry',
-> master_password='larry',
-> master_port=3306,
-> master_log_file='mysql-bin.000001',
-> master_log_pos=107;
Query OK, 0 rows affected (0.01 sec)
第五步,开启slave。
mysql> slave start;
mysql>show slave status ;
mysql>show slave status \G;
第六步,从服务器查看是否和主服务器通信成功。如果出现 Slave_IO_Running和Slave_SQL_Running都是yes,则证明配置成功
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.11
Master_User: larry
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 107
Relay_Log_File: serv08-relay-bin.000002
Relay_Log_Pos: 253
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 107
Relay_Log_Space: 410
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 1
1 row in set (0.00 sec) ERROR:
No query specified
第八步,测试
--slave查看数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
+--------------------+
4 rows in set (0.02 sec) --master创建数据库
mysql> create database larrydb;
Query OK, 1 row affected (0.00 sec)
--master查看数据库
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| larrydb |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.01 sec) --slave查看数据库,发现已经同步
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| larrydb |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.00 sec) --master创建表 插入数据
mysql> use larrydb;
Database changed
mysql> create table test(id int(11));
Query OK, 0 rows affected (0.00 sec) mysql> insert into test values(1);
Query OK, 1 row affected (0.00 sec) --slave查看数据是否同步成功,发现数据已经同步
mysql> use larrydb;
Database changed
mysql> show tables;
+-------------------+
| Tables_in_larrydb |
+-------------------+
| test |
+-------------------+
1 row in set (0.00 sec) mysql> select * from test;
+------+
| id |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
第九步,查看进程状态
--master查看进程状态
mysql> show processlist;
+----+-------+--------------------+---------+-------------+------+-----------------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------+--------------------+---------+-------------+------+-----------------------------------------------------------------------+------------------+
| 1 | root | localhost | larrydb | Query | 0 | NULL | show processlist |
| 2 | larry | 192.168.1.18:41393 | NULL | Binlog Dump | 854 | Master has sent all binlog to slave; waiting for binlog to be updated | NULL |
+----+-------+--------------------+---------+-------------+------+-----------------------------------------------------------------------+------------------+
2 rows in set (0.00 sec) --slave查看进程状态
mysql> show processlist;
+----+-------------+-----------+---------+---------+------+-----------------------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+---------+---------+------+-----------------------------------------------------------------------------+------------------+
| 1 | root | localhost | larrydb | Query | 0 | NULL | show processlist |
| 2 | system user | | NULL | Connect | 880 | Waiting for master to send event | NULL |
| 3 | system user | | NULL | Connect | 65 | Slave has read all relay log; waiting for the slave I/O thread to update it | NULL |
+----+-------------+-----------+---------+---------+------+-----------------------------------------------------------------------------+------------------+
3 rows in set (0.00 sec)
备注:如果需要制定同步的数据库,需要修改slave从库 /etc/my.cnf 这个mysql配置文件。
# vim /etc/my.cnf
增加两端语句
binlog-do-db = 同步的数据
binlog-ignore-db = mysql,information_schema
需要注意的地方
1、两个数据库的版本和数据应该保持一致
2、对应的端口,防火墙应该开启
Spring项目源码 https://github.com/jiafuweiJava/MasterSlave
数据库学习地址:http://blog.csdn.net/justdb/article/details/13168569
使用Spring AOP实现读写分离(MySql实现主从复制)的更多相关文章
- Spring AOP 实现读写分离
原文地址:Spring AOP 实现读写分离 博客地址:http://www.extlight.com 一.前言 上一篇<MySQL 实现主从复制> 文章中介绍了 MySQL 主从复制的搭 ...
- spring+mybatis实现读写分离
springmore-core spring+ibatis实现读写分离 特点 无缝结合spring+ibatis,对于程序员来说,是透明的 除了修改配置信息之外,程序的代码不需要修改任何东西 支持sp ...
- LVS+MYCAT+读写分离+MYSQL主备同步部署手册
LVS+MYCAT+读写分离+MYSQL主备同步部署手册 1 配置MYSQL主备同步…. 2 1.1 测试环境… 2 1.2 配置主数据库… 2 1.2.1 ...
- 【转载】LVS+MYCAT+读写分离+MYSQL主备同步部署手册(邢锋)
LVS+MYCAT+读写分离+MYSQL主备同步部署手册 1 配置MYSQL主备同步…. 2 1.1 测试环境… 2 1.2 配置主数据库… 2 1.2.1 ...
- Spring+mybatis 实现aop数据库读写分离,多数据库源配置
在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库.Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询.因为在实际的应用中,数据库都是读多写少 ...
- 基于spring的aop实现读写分离与事务配置
项目开发中经常会遇到读写分离等多数据源配置的需求,在Java项目中可以通过Spring AOP来实现多数据源的切换. 一.Spring事务开启流程 Spring中通常通过@Transactional来 ...
- spring实现数据库读写分离
现在大型的电子商务系统,在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库.Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询.因为在实际的应 ...
- Spring 实现数据库读写分离(转)
现在大型的电子商务系统,在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库.Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询.因为在实际的应 ...
- 数据源管理 | 主从库动态路由,AOP模式读写分离
本文源码:GitHub·点这里 || GitEE·点这里 一.多数据源应用 1.基础描述 在相对复杂的应用服务中,配置多个数据源是常见现象,例如常见的:配置主从数据库用来写数据,再配置一个从库读数据, ...
随机推荐
- (数据科学学习手札36)tensorflow实现MLP
一.简介 我们在前面的数据科学学习手札34中也介绍过,作为最典型的神经网络,多层感知机(MLP)结构简单且规则,并且在隐层设计的足够完善时,可以拟合任意连续函数,而除了利用前面介绍的sklearn.n ...
- FIFO队列(First In First Out)和优先队列
queue<类型名> q; q.size() - 返回队列中元素个数 q.empty() - 若队列为空,返回true ,否则返回false q.pop() - 删除队首元素,但不返回其值 ...
- Python标准库--inspect
inspect模块是针对模块,类,方法,功能等对象提供些有用的方法.例如可以帮助我们检查类的内容,检查方法的代码,提取和格式化方法的参数等. import inspect import os clas ...
- SharePoint显示错误信息
在SharePoint项目中,一般如果发生错误,SharePoint会弹出它自定义的报错页面,一般就显示"Something went wrong",如果光是看这一句话, ...
- 自学MVC开发基础
由于现在面试需求,我必须有点了解MVC开发基础,MVC是一个开发框架或者是一个开发模式,MVC让软件开发的过程大致切割成三个单元,分别是:Model(模型).View(试图).Controller(控 ...
- 【LoadRunner】解决LR11无法录制Chrome浏览器脚本问题
LoadRunner录制脚本时,遇到高版本的IE.FireFox,或者Chrome浏览器,会出现无法录制脚本的问题,下面就来讲一下如何利用LR自带的wplus_init_wsock.exe插件进行脚本 ...
- 阿里云ECS下基于Centos7.4安装MySQL5.7.20
1.首先登录阿里云ECS服务器,如下图所示: 2.卸载MariaDB 说明:CentOS7.x默认安装MariaDB而不是MySQL,而且yum服务器上也移除了MySQL相关的软件包.因为Maria ...
- 监控memcache服务
监控memcache服务是否正常,模拟用户(web客户端)检测. 使用nc命令加上set/get来模拟检测,以及监控响应时间及命中率. #!/bin/bash #################### ...
- 关于Scala文件操作中出现的问题
在各种项目中,我们常常需要用到文件操作,笔者在近期的项目中遇到了一个与文件操作相关的问题. 在代码实现的过程中,笔者首先定义了一个文件路径:def PATH = "/a/b/c.txt&qu ...
- HDU 4744 Starloop System(最小费用最大流)(2013 ACM/ICPC Asia Regional Hangzhou Online)
Description At the end of the 200013 th year of the Galaxy era, the war between Carbon-based lives a ...