MySQL主从复制和读写分离

我们知道应用对数据库的访问通常情况下大部分都是读操作,写只占很少一部分。因此读写分离(read-write-splitting)能有效降低主库压力,从而解决网站发展过程中遇到的第一次数据库瓶颈。

主从复制

首先必须开启master库的bin-log,因为mysql的主从复制是异步的,所以master库必须将更新操作记录下来以供slave库读取。
假设现在有A, B两台机器,A为master, B为slave。

Master

ssh至A服务器,登陆mysql, 创建一个复制专用用户repl

GRANT REPLICATION SLAVE ON *.* TO 'repl'@'B的IP' IDENTIFIED BY '111111';

修改my.cnf文件,开启bin-log并设置server-id:

[mysqld]
log-bin = /XXXX/mysql-bin.log
server-id = 1

重启mysql使配置生效。然后设置读锁,确保在配置好slave库之前master库没有读写操作:

flush tables with read lock;

查看master库当前bin-log的文件名和偏移量:

show master status; +------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | +------------------+----------+--------------+------------------+
| mysql-bin.000002 | 1075 | | | +------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

记下文件名和偏移量。此时master已经停止了所有的数据更新操作,这时候我们要把master库的数据进行备份,然后还原到slave库中。推荐通过mysqldump命令完成该操作。master备份完成后即可取消锁:

unlock tables;

Slave

ssh至B服务器,修改配置文件:

[mysqld]
server-id = 2

通过mysqld_safe启动从库,添加--skip-slave-start参数:

mysqld_safe --skip-slave-start

这样做的目的是不要让从库启动时就启动复制线程,因为我们还没有配置主库信息。

mysql> CHANGE MASTER TO
-> MASTER_HOST='主库地址', -> MASTER_PORT=3306, -> MASTER_USER='repl', -> MASTER_PASSWORD='111111', -> MASTER_LOG_FILE='mysql-bin.000002', -> MASTER_LOG_POS=1075;

启动slave线程:

start slave;

至此从库配置完毕。如果一切顺利的话,此时在主库执行一条更新操作,从库也会马上跟进。
如果发现有问题,可以执行

show slave status;

查看详细信息。

读写分离

目前读写分离有两种方案:

  1. 控制应用程序,写操作连接主库,读操作连接从库。
  2. 引入数据库中间件。如官方的mysql-proxy。好处是读写分离对应用程序完全透明,不需要对程序代码做任何修改。但是目前mysql-proxy依然只有alpha版本,并且官方也不推荐将其用在生产环境中。

其实对于方案一还有一个比较优雅的解决方案,那就是使用ReplicationDriver。MySQL的JDBC驱动中自带ReplicationDriver,它可以将JDBC中所有conn.setReadOnly(true)的连接路由到从库中,从而使得我们不必对程序代码动大手术。 配合Spring, 我们可以使用@Transactional(readOnly = true)注解。因为MySQL主从复制有延迟,所以对于实时性要求高的操作,我们可以将readOnly设为false来让ReplicationDriver从主库中读取数据,这也是一种可以接受的方案。

配置示例:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.ReplicationDriver" />
    <property name="url" value="jdbc:mysql:replication://主库IP:3306,从库IP:3306/test" />
    <property name="username" value="root" />
    <property name="password" value="root" />
    </bean>
相关文章
相关标签/搜索