mysql 读写分离 mysql slave,master配置

本文详细介绍了如何通过MySQL主从复制实现读写分离,并利用Amoeba作为中间件管理读写路由策略。从搭建MySQL主从环境、配置Amoeba到客户端调用全流程进行了实战演示。

一个完整的mysql读写分离环境包括以下几个部分:

应用程序client
database proxy
database集群
在本次实战中,应用程序client基于c3p0连接后端的database proxy。database proxy负责管理client实际访问database的路由策略,采用开源框架amoeba。database集群采用mysql的master- slave的replication方案。整个环境的结构图如下所示:

 

实战步骤与详解

一.搭建mysql的master-slave环境

1)分别在host1(10.20.147.110)和host2(10.20.147.111)上安装mysql(5.0.45),具体安装方法可见官方文档

2)配置master

首先编辑/etc/my.cnf,添加以下配置:

log-bin=mysql-bin #slave会基于此log-bin来做replication
server-id=1 #master的标示
binlog-do-db = amoeba_study #用于master-slave的具体数据库

然后添加专门用于replication的用户:

mysql> GRANT REPLICATION SLAVE ON *.* TO repl@10.20.147.111 IDENTIFIED BY '111111';

重启mysql,使得配置生效:

/etc/init.d/mysqld restart

最后查看master状态:

 

3)配置slave

首先编辑/etc/my.cnf,添加以下配置:

server-id=2 #slave的标示

配置生效后,配置与master的连接:

mysql> CHANGE MASTER TO
    -> MASTER_HOST='10.20.147.110',
    -> MASTER_USER='repl',
    -> MASTER_PASSWORD='111111',
    -> MASTER_LOG_FILE='mysql-bin.000003',
    -> MASTER_LOG_POS=161261;

其中MASTER_HOST是master机的ip,MASTER_USER和MASTER_PASSWORD就是我们刚才在master上添加的用户,MASTER_LOG_FILE和MASTER_LOG_POS对应与master status里的信息

最后启动slave:

mysql> start slave;

4)验证master-slave搭建生效

通过查看slave机的log(/var/log/mysqld.log):

100703 10:51:42 [Note] Slave I/O thread: connected to master 'repl@10.20.147.110:3306',  replication started in log 'mysql-bin.000003' at position 161261

如看到以上信息则证明搭建成功,如果有问题也可通过此log找原因

二.搭建database proxy

此次实战中database proxy采用amoeba ,它的相关信息可以查阅官方文档,不在此详述

1)安装amoeba

下载amoeba(1.2.0-GA)后解压到本地(D:\openSource\amoeba-mysql-1.2.0-GA),即完成安装

2)配置amoeba

先配置proxy连接和与各后端mysql服务器连接信息(D:\openSource\amoeba-mysql-1.2.0-GA\conf\amoeba.xml):

<server> 
    <!-- proxy server绑定的端口 --> 
    <property name="port">8066</property> 
      
    <!-- proxy server绑定的IP --> 
    <!--  
    <property name="ipAddress">127.0.0.1</property> 
     --> 
    <!-- proxy server net IO Read thread size --> 
    <property name="readThreadPoolSize">20</property> 
      
    <!-- proxy server client process thread size --> 
    <property name="clientSideThreadPoolSize">30</property> 
      
    <!-- mysql server data packet process thread size --> 
    <property name="serverSideThreadPoolSize">30</property> 
      
    <!-- socket Send and receive BufferSize(unit:K)  --> 
    <property name="netBufferSize">128</property> 
      
    <!-- Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). --> 
    <property name="tcpNoDelay">true</property> 
      
    <!-- 对外验证的用户名 --> 
    <property name="user">root</property> 
      
    <!-- 对外验证的密码 --> 
    <property name="password">root</property> 
</server> 
<server>
 <!-- proxy server绑定的端口 -->
 <property name="port">8066</property>
 
 <!-- proxy server绑定的IP -->
 <!--
 <property name="ipAddress">127.0.0.1</property>
  -->
 <!-- proxy server net IO Read thread size -->
 <property name="readThreadPoolSize">20</property>
 
 <!-- proxy server client process thread size -->
 <property name="clientSideThreadPoolSize">30</property>
 
 <!-- mysql server data packet process thread size -->
 <property name="serverSideThreadPoolSize">30</property>
 
 <!-- socket Send and receive BufferSize(unit:K)  -->
 <property name="netBufferSize">128</property>
 
 <!-- Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). -->
 <property name="tcpNoDelay">true</property>
 
 <!-- 对外验证的用户名 -->
 <property name="user">root</property>
 
 <!-- 对外验证的密码 -->
 <property name="password">root</property>
</server>

以上是proxy提供给client的连接配置

<dbServerList> 
    <dbServer name="server1">           
        <!-- PoolableObjectFactory实现类 --> 
        <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory"> 
            <property name="manager">defaultManager</property> 
              
            <!-- 真实mysql数据库端口 --> 
            <property name="port">3306</property> 
              
            <!-- 真实mysql数据库IP --> 
            <property name="ipAddress">10.20.147.110</property> 
            <property name="schema">amoeba_study</property> 
              
            <!-- 用于登陆mysql的用户名 --> 
            <property name="user">root</property> 
              
            <!-- 用于登陆mysql的密码 --> 
            <property name="password"></property> 
              
        </factoryConfig> 
          
        <!-- ObjectPool实现类 --> 
        <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool"> 
            <property name="maxActive">200</property> 
            <property name="maxIdle">200</property> 
            <property name="minIdle">10</property> 
            <property name="minEvictableIdleTimeMillis">600000</property> 
            <property name="timeBetweenEvictionRunsMillis">600000</property> 
            <property name="testOnBorrow">true</property> 
            <property name="testWhileIdle">true</property> 
        </poolConfig> 
    </dbServer> 
    <dbServer name="server2"> 
          
        <!-- PoolableObjectFactory实现类 --> 
        <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory"> 
            <property name="manager">defaultManager</property> 
              
            <!-- 真实mysql数据库端口 --> 
            <property name="port">3306</property> 
              
            <!-- 真实mysql数据库IP --> 
            <property name="ipAddress">10.20.147.111</property> 
            <property name="schema">amoeba_study</property> 
              
            <!-- 用于登陆mysql的用户名 --> 
            <property name="user">root</property> 
              
            <!-- 用于登陆mysql的密码 --> 
            <property name="password"></property> 
              
        </factoryConfig> 
          
        <!-- ObjectPool实现类 --> 
        <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool"> 
            <property name="maxActive">200</property> 
            <property name="maxIdle">200</property> 
            <property name="minIdle">10</property> 
            <property name="minEvictableIdleTimeMillis">600000</property> 
            <property name="timeBetweenEvictionRunsMillis">600000</property> 
            <property name="testOnBorrow">true</property> 
            <property name="testWhileIdle">true</property> 
        </poolConfig> 
    </dbServer>         
</dbServerList> 
<dbServerList>
 <dbServer name="server1">   
  <!-- PoolableObjectFactory实现类 -->
  <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
   <property name="manager">defaultManager</property>
   
   <!-- 真实mysql数据库端口 -->
   <property name="port">3306</property>
   
   <!-- 真实mysql数据库IP -->
   <property name="ipAddress">10.20.147.110</property>
   <property name="schema">amoeba_study</property>
   
   <!-- 用于登陆mysql的用户名 -->
   <property name="user">root</property>
   
   <!-- 用于登陆mysql的密码 -->
   <property name="password"></property>
   
  </factoryConfig>
  
  <!-- ObjectPool实现类 -->
  <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
   <property name="maxActive">200</property>
   <property name="maxIdle">200</property>
   <property name="minIdle">10</property>
   <property name="minEvictableIdleTimeMillis">600000</property>
   <property name="timeBetweenEvictionRunsMillis">600000</property>
   <property name="testOnBorrow">true</property>
   <property name="testWhileIdle">true</property>
  </poolConfig>
 </dbServer>
 <dbServer name="server2">
  
  <!-- PoolableObjectFactory实现类 -->
  <factoryConfig class="com.meidusa.amoeba.mysql.net.MysqlServerConnectionFactory">
   <property name="manager">defaultManager</property>
   
   <!-- 真实mysql数据库端口 -->
   <property name="port">3306</property>
   
   <!-- 真实mysql数据库IP -->
   <property name="ipAddress">10.20.147.111</property>
   <property name="schema">amoeba_study</property>
   
   <!-- 用于登陆mysql的用户名 -->
   <property name="user">root</property>
   
   <!-- 用于登陆mysql的密码 -->
   <property name="password"></property>
   
  </factoryConfig>
  
  <!-- ObjectPool实现类 -->
  <poolConfig class="com.meidusa.amoeba.net.poolable.PoolableObjectPool">
   <property name="maxActive">200</property>
   <property name="maxIdle">200</property>
   <property name="minIdle">10</property>
   <property name="minEvictableIdleTimeMillis">600000</property>
   <property name="timeBetweenEvictionRunsMillis">600000</property>
   <property name="testOnBorrow">true</property>
   <property name="testWhileIdle">true</property>
  </poolConfig>
 </dbServer>  
</dbServerList>

以上是proxy与后端各mysql数据库服务器配置信息,具体配置见注释很明白了

最后配置读写分离策略:

<queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter"> 
    <property name="LRUMapSize">1500</property> 
    <property name="defaultPool">server1</property> 
    <property name="writePool">server1</property> 
    <property name="readPool">server2</property> 
    <property name="needParse">true</property> 
</queryRouter> 
<queryRouter class="com.meidusa.amoeba.mysql.parser.MysqlQueryRouter">
 <property name="LRUMapSize">1500</property>
 <property name="defaultPool">server1</property>
 <property name="writePool">server1</property>
 <property name="readPool">server2</property>
 <property name="needParse">true</property>
</queryRouter>

从以上配置不然发现,写操作路由到server1(master),读操作路由到server2(slave)

3)启动amoeba

在命令行里运行D:\openSource\amoeba-mysql-1.2.0-GA\amoeba.bat即可:

log4j:WARN log4j config load completed from file:D:\openSource\amoeba-mysql-1.2.0-GA\conf\log4j.xml
log4j:WARN ip access config load completed from file:D:\openSource\amoeba-mysql-1.2.0-GA/conf/access_list.conf
2010-07-03 09:55:33,821 INFO  net.ServerableConnectionManager - Server listening on 0.0.0.0/0.0.0.0:8066.
三.client端调用与测试

1)编写client调用程序

具体程序细节就不详述了,只是一个最普通的基于mysql driver的jdbc的数据库操作程序

2)配置数据库连接

本client基于c3p0,具体数据源配置如下:

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
    destroy-method="close"> 
    <property name="driverClass" value="com.mysql.jdbc.Driver" /> 
    <property name="jdbcUrl" value="jdbc:mysql://localhost:8066/amoeba_study" /> 
    <property name="user" value="root" /> 
    <property name="password" value="root" /> 
    <property name="minPoolSize" value="1" /> 
    <property name="maxPoolSize" value="1" /> 
    <property name="maxIdleTime" value="1800" /> 
    <property name="acquireIncrement" value="1" /> 
    <property name="maxStatements" value="0" /> 
    <property name="initialPoolSize" value="1" /> 
    <property name="idleConnectionTestPeriod" value="1800" /> 
    <property name="acquireRetryAttempts" value="6" /> 
    <property name="acquireRetryDelay" value="1000" /> 
    <property name="breakAfterAcquireFailure" value="false" /> 
    <property name="testConnectionOnCheckout" value="true" /> 
    <property name="testConnectionOnCheckin" value="false" /> 
</bean> 
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
 destroy-method="close">
 <property name="driverClass" value="com.mysql.jdbc.Driver" />
 <property name="jdbcUrl" value="jdbc:mysql://localhost:8066/amoeba_study" />
 <property name="user" value="root" />
 <property name="password" value="root" />
 <property name="minPoolSize" value="1" />
 <property name="maxPoolSize" value="1" />
 <property name="maxIdleTime" value="1800" />
 <property name="acquireIncrement" value="1" />
 <property name="maxStatements" value="0" />
 <property name="initialPoolSize" value="1" />
 <property name="idleConnectionTestPeriod" value="1800" />
 <property name="acquireRetryAttempts" value="6" />
 <property name="acquireRetryDelay" value="1000" />
 <property name="breakAfterAcquireFailure" value="false" />
 <property name="testConnectionOnCheckout" value="true" />
 <property name="testConnectionOnCheckin" value="false" />
</bean>

值得注意是,client端只需连到proxy,与实际的数据库没有任何关系,因此jdbcUrl、user、password配置都对应于amoeba暴露出来的配置信息

3)调用与测试

首先插入一条数据:insert into zone_by_id(id,name) values(20003,'name_20003')

通过查看master机上的日志/var/lib/mysql/mysql_log.log:

100703 11:58:42       1 Query       set names latin1
                      1 Query       SET NAMES latin1
                      1 Query       SET character_set_results = NULL
                      1 Query       SHOW VARIABLES
                      1 Query       SHOW COLLATION
                      1 Query       SET autocommit=1
                      1 Query       SET sql_mode='STRICT_TRANS_TABLES'
                      1 Query       SHOW VARIABLES LIKE 'tx_isolation'
                      1 Query       SHOW FULL TABLES FROM `amoeba_study` LIKE 'PROBABLYNOT'
                      1 Prepare     [1] insert into zone_by_id(id,name) values(?,?)
                      1 Prepare     [2] insert into zone_by_id(id,name) values(?,?)          
                      1 Execute     [2] insert into zone_by_id(id,name) values(20003,'name_20003')

得知写操作发生在master机上

通过查看slave机上的日志/var/lib/mysql/mysql_log.log:

100703 11:58:42       2 Query       insert into zone_by_id(id,name) values(20003,'name_20003')

得知slave同步执行了这条语句

然后查一条数据:select t.name from zone_by_id t where t.id = 20003

通过查看slave机上的日志/var/lib/mysql/mysql_log.log:

100703 12:02:00      33 Query       set names latin1
                     33 Prepare     [1] select t.name from zone_by_id t where t.id = ?
                     33 Prepare     [2] select t.name from zone_by_id t where t.id = ?   
                     33 Execute     [2] select t.name from zone_by_id t where t.id = 20003 

得知读操作发生在slave机上

并且通过查看slave机上的日志/var/lib/mysql/mysql_log.log发现这条语句没在master上执行

通过以上验证得知简单的master-slave搭建和实战得以生效

 

本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/cutesource/archive/2010/07/03/5710645.aspx




####################################################################
####################  mysql 主从复制读写分离实现  ##################
####################################################################

mysql 主从复制读写分离实现

mysql主从复制
(一)安装mysql(主从服务器皆相同) 先创建用户 useradd mysql -s /sbin/nologin

tar zxvf mysql-5.0.45.tar.gz
cd mysql-5.0.45
./configure --prefix=/usr/local/mysql  --localstatedir=/opt/data --with-extra-charsets=utf8,gb2312,gbk --with-pthread --enable-thread-safe-client
注:配置过程指定数据文件的位置及另加的字符集.
make
make install
cp support-files/my-large.cnf   /etc/my.cnf
cd /usr/local/mysql
chgrp -R mysql .
生成基本的数据库和表:  /usr/local/mysql/bin/mysql_install_db --user=mysql
成功执行后察看数据目录/opt/data,看是否有文件或目录生成.
chown -R mysql:mysql /opt/data
记得给每个数据库设置root密码.

(二)修改配置文件
不同的地方就是server-id,主服务器配置文件不用修改,从服务器的配置文件server-id=10.其他的内容基本相同.
(三)启动服务
/usr/local/mysql/bin/mysqld_safe --user=mysql&
这个过程主辅服务器都相同.
(四)授权(在主服务器上进行)
GRANT REPLICATION SLAVE ON *.* to 'rep1'@'192.168.1.20' identified by '123456';
flush hosts;
flush privileges;
(五)查询主数据库状态(主服务器上进行)
mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |      388 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)
记下file及position的值,后面做从服务器操作的时候需要用.
(六)配置从服务器
mysql> change master to master_host='192.168.1.19', master_user='rep1', master_password='mysql', master_log_file=' mysql-bin.000003', master_log_pos=388;
正确执行后再执行:
mysql> start slave;
就启用了复制功能.这里我们运行一下 mysql> show slave status\G 来检查一下,一个正常的输出结果应该如下面的形式:
mysql> show slave status\G
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: 192.168.8.101
                Master_User: rep1
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-bin.000003
        Read_Master_Log_Pos: 235
             Relay_Log_File: -relay-bin.000009
              Relay_Log_Pos: 235
      Relay_Master_Log_File: mysql-bin.000003
           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: 235
            Relay_Log_Space: 235
            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
1 row in set (0.00 sec)
请注意:slave_IO进程及slave_SQL进程都必须正常运行,在状态输出重表现为:   Slave_IO_Running: Yes  及Slave_SQL_Running: Yes 否则都是不正确的状态(如一个值Yes,另外一个是NO则不行).
(七)主数据库有数据的情况:
1、数据库锁表操作,不让数据再进行写入动作。mysql> FLUSH TABLES WITH READ LOCK;
2、察看主数据库的状态 mysql> show master status; 照第(五)步记录输出值。
3、把主服务器数据文件复制到从服务器,最好先用tar处理一下。
4、取消主数据库锁定 mysql> UNLOCK TABLES;
5、从服务器的操作。跟前面的步骤一样(略过)
    
mysql代理安装配置

一、安装mysql-proxy.需要按下列顺序安装其所依赖的包:
(一)安装LUA
tar zxvf lua-5.1.tar.gz
cd lua-5.1
用vi修改Makefile,使"INSTALL_TOP=/usr/local/lua",这样做的目的是为了是lua的所有文件都安装在目录/usr/local/lua/
make posix
make install

(二)安装 libevent
tar zxvf libevent-1.1a.tar.gz
cd libevent-1.1a
./configure --prefix=/usr/local/libevent
make
make install

(三)安装check
tar zxvf check-0.8.4.tar.gz
cd check-0.8.4
./configure
make
make install

(四)设置安装mysql-proxy所需的环境变量.把下面的内容追加到/etc/profile中
export LUA_CFLAGS="-I/usr/local/lua/include" LUA_LIBS="-L/usr/local/lua/lib -llua -ldl" LDFLAGS="-L/usr/local/libevent/lib -lm"
export CPPFLAGS="-I/usr/local/libevent/include"
export CFLAGS="-I/usr/local/libevent/include"
然后执行 source /etc/profile (安装完mysql-proxy不再需要这些变量,可以删除之)

(五)安装mysql(只安装mysql客户端即可)
tar zxvf  mysql-5.0.45.tar.gz
cd mysql-5.0.45
./configure --prefix=/usr/local/mysql  --without-server
make
make install

(六)安装mysql-proxy
tar zxvf mysql-proxy-0.5.0.tar.gz
cd mysql-proxy-0.5.0
./configure –prefix=/usr/local/mysql-proxy  --with-mysql=/usr/local/mysql  --with-lua
Make
Make install

二、主要的命令行选项
--help-all显示所有的帮助选项
--admin-address=host:port 管理主机及端口,默认是4041
--proxy-address=host:port 代理服务器的监听地址及端口,默认4040
--proxy-read-only-address=host:port 只读连接时,代理服务器的监听地址及端口。默认4042
--proxy-backend-addresses=host:port连接真实服务器的地址及监听端口,默认是3306,这是mysql代理最重要的选项,多个主机之间用空格隔开。使用rr算法。
--proxy-lua-script=file 指定lua脚本的名称

三、 使用方法
2个mysql服务器的情形
mysql-proxy \
     --proxy-backend-addresses=mysql_ip1:3306 \
     --proxy-backend-addresses=mysql_ip2:3306
3个服务器的情形:一个主服务器,负责写入;2个从服务器,负责查询。
mysql-proxy --proxy-backend-addresses= :3306\
         --proxy-read-only-address=:3306 \
         --proxy-read-only-address=:3306

四、mysql-proxy启动
编写脚本/usr/local/bin/mysql-proxy.sh其内容如下:
#!/bin/bash
LUA_PATH="/usr/local/mysql-proxy/share/mysql-proxy/?.lua" mysql-proxy --proxy-read-only-backend-addresses=192.168.1.38:3306 --proxy-
backend-addresses=192.168.1.33:3306 --proxy-lua-script=/usr/local/mysql-proxy/share/mysql-proxy/rw-splitting.lua >> /var/log/mysql-proxy.log &
chmod 755 /usr/local/bin/mysql-proxy.sh; 执行命令/usr/local/bin/mysql-proxy.sh启动服务


配置验证
1、主从复制测试:在主数据库服务器上创建库和表,然后再插入记录,再登陆到从服务器,看是否也建立相一致的库和表以及记录。
mysql> create database first_db;
Query OK, 1 row affected (0.01 sec)
在主数据库服务器创建库first_db

mysql> create table first_tb(id int(3),name char(10));
Query OK, 0 rows affected (0.00 sec)
在主数据库服务器创建表first_db

mysql> insert into first_tb values (001,'myself');
Query OK, 1 row affected (0.00 sec)
在主数据服务器的表first_db中插入记录
现在转到从数据库服务器,看是否同步了上面主数据库的数据
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| first_db           |
| mysql              |
| test               |
+--------------------+
4 rows in set (0.01 sec)
数据库自动生成了

mysql> use first_db;
Database changed
mysql> show tables;
+--------------------+
| Tables_in_first_db |
+--------------------+
| first_tb           |
+--------------------+
1 row in set (0.00 sec)
表也自动生成了

mysql> select * from first_tb;
+------+--------+
| id   | name   |
+------+--------+
|    1 | myself |
+------+--------+
1 row in set (0.00 sec)
记录也按照我们的意愿存在了
2、读写分离:用mysql客户端程序如mysql登陆到mysql代理,然后执行读写操作,以测试读写分离的正确性。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值