1.前(jian)言(tao):
明明上星期就弄好了,然而拖到了今天才来写博客纪录,拖延症晚期的我。
2.实现mysql的读写分离
(1)基本的理论知识:
首先,要实现mysql的读写分离,可以使用mysql的主(master)从(slave)复制(Replication)来实现:
主库只提供写数据的服务,而从库只提供读数据的服务。
什么是主从复制?
简单来说,就是主库把对数据改动的操作保存到一个文件里面,而从库会隔一个时间间隔根据这个文件更新自己的数据
(所以读到的数据是有延迟的,这个延迟取决于从库设置的时间间隔)
关于主从复制的详细内容,可以问度娘
(2)实际操作步骤:
使用以下三台电脑:
主库的IP:192.168.1.65
从库1的IP:192.168.1.49
从库2的IP:192.168.1.64
三台电脑都安装了MySQL5.5(实验室的电脑,版本比较老~)
然后把三台电脑的mysql服务停掉
A.打开主库的mysql安装目录,打开配置文件my.ini
B.在[mysql]的后面添加如下代码:
server-id=1 #master的标示
log-bin=mysql-bin #slave会基于此log-bin来做replication
binlog-do-db=test #用于master-slave的具体数据库
binlog_ignore_db=mysql #不用于master-slave的具体数据库
binlog_ignore_db=information_schema #和binlog-do-db一样,可以设置多个
C.打开主库的mysql服务,进入mysql的命令行,输入如下代码:
show master status;
记下File(日志文件)和Position(日志位置),从库会根据这个日志文件和日志位置来更新自己的表,一个从库配置完成之前,不要对主库的数据做任何修改操作。
D.分别给两个从库复制权限
grant replication slave on *.* to 'slave'@'192.168.1.%' identified by '123456';
其中的’slave’为登录账号,’123456’为密码,’192.168.1.%’为从库的IP(这里偷懒使用了通配符~)
E.打开从库1的mysql安装目录,打开配置文件my.ini,在[mysql]的后面添加如下代码:
server-id=2 #比刚刚主库设定的server-id大就行了,且从库之间不能有一样
log-bin=mysql-bin #slave会基于此log-bin来做replication
replicate-do-db=test #用于master-slave的具体数据库
保存后启动从库1的mysql服务,进入mysql的命令行,输入如下代码:
先停止它的slave:
stop slave;
再改变它的master:
change master to master_host='192.168.1.65',
master_port=3306,
master_user='slave',
master_password='123456',
master_log_file='mysql-bin.000040',
master_log_pos=717;
再启动它的slave:
start slave;
然后再输入如下代码,检查是否成功:
show slave status\G;
如果看到上面这句话的,那就没问题了~
当然你也可以在主库上做修改数据的操作,看看从库会不会更新~(注意:从库的数据库和表需要自己手动创建)
F.对从库2的操作和从库1的基本一样
打开配置文件my.ini,在[mysql]的后面添加如下代码:
server-id=3 #比刚刚主库设定的server-id大就行了,且从库之间不能有一样
log-bin=mysql-bin #slave会基于此log-bin来做replication
replicate-do-db=test #用于master-slave的具体数据库
因为从库1的server-id为2,所以从库2的server-id不能为2
保存后启动从库2的mysql服务。
注意要再从主库上获取一次最新的File(日志文件)和Position(日志位置)
先停止它的slave:
stop slave;
再改变它的master:
change master to master_host='192.168.1.65',
master_port=3306,
master_user='slave',
master_password='123456',
master_log_file='mysql-bin.000040',
master_log_pos=1751;
剩下的操作和从库1一毛一样~
G.到这里,mysql的读写分离就完成了~
但是这样不够方便,因为我们写数据时需要连接主库,而读数据时需要连接从库。在连接从库时,不能负载均衡。
这时候就要靠神器Amoeba了~
它就像一个中转站,将所有的写请求分配给主库,读请求分配给从库,并且在从库之间实现负载均衡,丢个官网的图~
H.配置Amoeba服务器:
这里最好找另外的一台电脑充当Amoeba服务器:192.168.1.62
博主使用的版本是amoeba-mysql-3.0.5-RC-distribution,链接如下:
下载完成后解压,打开conf文件夹,配置amoeba.xml和dbServer.xml:
amoeba.xml:
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:configuration SYSTEM "amoeba.dtd">
<amoeba:configuration xmlns:amoeba="http://amoeba.meidusa.com/">
<proxy>
<!-- service class must implements com.meidusa.amoeba.service.Service -->
<service name="Amoeba for Mysql" class="com.meidusa.amoeba.mysql.server.MySQLService">
<!-- amoeba代理端口号 -->
<property name="port">8066</property>
<!-- amoeba服务器IP地址 -->
<property name="ipAddress">192.168.1.62</property>
<property name="connectionFactory">
<bean class="com.meidusa.amoeba.mysql.net.MysqlClientConnectionFactory">
<property name="sendBufferSize">128</property>
<property name="receiveBufferSize">64</property>
</bean>
</property>
<property name="authenticateProvider">
<bean class="com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator">
<!-- amoeba服务器用户名 -->
<property name="user">amoeba</property>
<!-- amoeba服务器密码 -->
<property name="password">123456</property>
<property name="filter">
<bean class="com.meidusa.toolkit.net.authenticate.server.IPAccessController">
<property name="ipFile">${amoeba.home}/conf/access_list.conf</property>
</bean>
</property>
</bean>
</property>
</service>
<runtime class="com.meidusa.amoeba.mysql.context.MysqlRuntimeContext">
<!-- proxy server client process thread size -->
<property name="executeThreadSize">128</property>
<!-- per connection cache prepared statement size -->
<property name="statementCacheSize">500</property>
<!-- default charset -->
<property name="serverCharset">utf8</property>
<!-- query timeout( default: 60 second , TimeUnit:second) -->
<property name="queryTimeout">60</property>
</runtime>
</proxy>
<!--
Each ConnectionManager will start as thread
manager responsible for the Connection IO read , Death Detection
-->
<connectionManagerList>
<connectionManager name="defaultManager" class="com.meidusa.toolkit.net.MultiConnectionManagerWrapper">
<property name="subManagerClassName">com.meidusa.toolkit.net.AuthingableConnectionManager</property>
</connectionManager>
</connectionManagerList>
<!-- default using file loader -->
<dbServerLoader class="com.meidusa.amoeba.context.DBServerConfigFileLoader">
<property name="configFile">${amoeba.home}/conf/dbServers.xml</property>
</dbServerLoader>
<queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
<property name="ruleLoader">
<bean class="com.meidusa.amoeba.route.TableRuleFileLoader">
<property name="ruleFile">${amoeba.home}/conf/rule.xml</property>
<property name="functionFile">${amoeba.home}/conf/ruleFunctionMap.xml</property>
</bean>
</property>
<property name="sqlFunctionFile">${amoeba.home}/conf/functionMap.xml</property>
<property name="LRUMapSize">1500</property>
<!-- 设定默认节点-->
<property name="defaultPool">master</property>
<!-- 设定可写节点-->
<property name="writePool">master</property>
<!-- 设定只读节点-->
<property name="readPool"> multiPool </property>
<property name="needParse">true</property>
</queryRouter>
</amoeba:configuration>
dbServers.xml:
<?xml version="1.0" encoding="gbk"?>
<!DOCTYPE amoeba:dbServers SYSTEM "dbserver.dtd">
<amoeba:dbServers xmlns:amoeba="http://amoeba.meidusa.com/">
<!--
Each dbServer needs to be configured into a Pool,
If you need to configure multiple dbServer with load balancing that can be simplified by the following configuration:
add attribute with name virtual = "true" in dbServer, but the configuration does not allow the element with name factoryConfig
such as 'multiPool' dbServer
-->
<dbServer name="abstractServer" abstractive="true">
<factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
<property name="connectionManager">${defaultManager}</property>
<property name="sendBufferSize">64</property>
<property name="receiveBufferSize">128</property>
<!-- mysql port(数据库端口) -->
<property name="port">3306</property>
<!-- mysql schema(数据库名称,数据库中必须存在此数据库) -->
<property name="schema">test</property>
<!-- mysql user(控制数据库用户名) -->
<property name="user">proxy</property>
<!-- mysql password(控制数据库密码) -->
<property name="password">123456</property>
</factoryConfig>
<poolConfig class="com.meidusa.toolkit.common.poolable.PoolableObjectPool">
<property name="maxActive">500</property>
<property name="maxIdle">500</property>
<property name="minIdle">1</property>
<property name="minEvictableIdleTimeMillis">600000</property>
<property name="timeBetweenEvictionRunsMillis">600000</property>
<property name="testOnBorrow">true</property>
<property name="testOnReturn">true</property>
<property name="testWhileIdle">true</property>
</poolConfig>
</dbServer>
<!-- 主数据库配置 -->
<dbServer name="master" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.1.65</property>
</factoryConfig>
</dbServer>
<!-- 从数据库配置 -->
<dbServer name="slave1" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.1.64</property>
</factoryConfig>
</dbServer>
<dbServer name="slave2" parent="abstractServer">
<factoryConfig>
<!-- mysql ip -->
<property name="ipAddress">192.168.1.49</property>
</factoryConfig>
</dbServer>
<!-- 定义虚拟服务器组,即只读池 -->
<dbServer name="multiPool" virtual="true">
<poolConfig class="com.meidusa.amoeba.server.MultipleServerPool">
<!-- Load balancing strategy: 1=ROUNDROBIN , 2=WEIGHTBASED , 3=HA-->
<property name="loadbalance">1</property>
<!-- Separated by commas,such as: server1,server2,server1 -->
<property name="poolNames">slave1,slave2</property>
</poolConfig>
</dbServer>
</amoeba:dbServers>
I.给Amoeba授权:
分别到主库、从库1、从库2的mysql控制台下给Amoeba服务器授权,代码如下:
grant all on *.* to 'proxy'@'192.168.1.62' identified by '123456';
这里的账号和密码必须和dbServers.xml中的配置一毛一样:
连接Amoeba数据库,这里的账号、密码、Ip、端口必须和amoeba.xml的配置一毛一样:
然后使用这个连接对数据库test做数据修改操作,再到主库从库上面查看是否有同步修改,如果有,那就完成了读写分离~
如果想看看有没有实现负载均衡,可以打开Amoeba安装目录的logs/root.log查看日志。
这样我们的应用可以通过连接Amoeba服务器来访问数据库中的数据~