MySQL 主从复制
MySQL主从复制与读写分离
在实际的生产环境中,如果数据库的读和写都在同一个数据库服务中操作,无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的,因此,一般来说都是通过主从复制的方式来同步数据,在通过读写分离来提升数据库的并发负载能力这样的的方案来进行部署与实施的。
Mysql主从复制原理:
Mysql的主从复制和mysql的读写分离两者有着紧密联系,首先要部署主从复制,只有主从复制完成了 ,才能在此基础上进行数据的读写分离。
Mysql支持的复制类型:
基于语句的复制:在主服务器上执行的SQL语句,在从服务器上执行同样的语句。默认采用,效率高。
基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍。
混合类型的复制:默认采用基于语句的复制,当无法精确复制时,就会采用基于行的复制。
复制到工作过程:
事务更新Master记录二进制日志(Binary log)
Slave将Master的Binary log复制到其中继日志
Slave开始一个I/O线程,在Master上打开一个普通连接,然后开始Binlog dump process(binlogz转储过程),Binlog dump process 从Master的二进制日志中读取事件,写入Relay log(中继日志)中;
SQL slave thread (SQL从线程)从中继日志读取时间,并重放其中的事件而更新Slave的数据,使其保持数据一致。
复制过程由一个很重要的限制,即复制在Slave上是串化的,也就是说Master上的并行更新操作不能再Slave上并行操作。
MySQL读写分离原理:
读写分离就是只在主服务器上写,只在从服务器上读。
基本的原理是让主数据库处理事务性查询,而从数据库处理select查询。数据库复制被用来把 事务性查询导致的变更同步到集群中的从数据库。
目前比较常见的MySQL读写分离分为两种:
基于程序代码内部实现:在代码中根据select、insert进行路由分类,目前应用最广泛。
基于中间代理层实现:代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库,有两个代理程序:
MySQL-Proxy
Amoeba
首先建立MYSQL
MySQL的编译安装
⦁ 准备工作
确认没有使用RPM方式安装mysql-server、mysql(如果存在mysql,则rpm -e mysql --nodeps删除)
查看是否安装:#rpm -q mysql-server mysql
package mysql-server is not installed
package mysql is not installed
安装光盘自带的ncurses- devel包
Mount /dev/cdrom /media/cdrom
rpm -ivh /media/cdrom/Packages/ncurses-devel-5.7-3.20090208.el6.x86_64.rpm
安装cmake包
#tar zxf cmake-2.8.6.tar.gz
#cd cmake-2.8.6
# ./configure
# gmake && gmake install
⦁ 源码编译及安装
# groupadd mysql
# useradd -M -s /sbin/nologin mysql -g mysql
# tar zxf mysql-5.5.22.tar.gz -C /usr/src/
# cd /usr/src/mysql-5.5.22/
#cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DSYSCONFDIR=/etc -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_EXTRA_CHARSETS=all
[root@www mysql-5.5.22]# make
[root@www mysql-5.5.22]# make install
⦁ 安装后的其他调整
[root@www ~]# chown -R mysql:mysql /usr/local/mysql
[root@www mysql-5.5.22]# cp support-files/my-medium.cnf /etc/my.cnf
[root@wwwmysql-5.5.22]# /usr/local/mysql/scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data/
[root@www mysql-5.5.22]# PATH=$PATH:/usr/local/mysql/bin
⦁ 添加为系统服务
以便通过chkconfig进行管理
# cp support-files/mysql.server /etc/rc.d/init.d/mysqld
# chmod +x /etc/rc.d/init.d/mysqld
# chkconfig --add mysqld
⦁ 启动mysqld服务,并查看运行状态
# service mysqld start
Starting MySQL............ [确定]
# /etc/init.d/mysqld status
MySQL running (56956) [确定]
# netstat -anpt | grep mysqld
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 56956/mysqld 查看服务端口,默认为3306
⦁ 访问MySQL数据库
连接并登录到MySQL操作环境
mysql -u 用户名 [-p]
提示符:mysql>
设置数据库用户的密码
mysqladmin -u root [-p] password 新密码
退出MySQL操作环境
mysql> exit
案例:
代理服务器amoeba 主服务器master 从服务器slave 客户机client
搭建主从复制
在主服务器master搭建时间同步服务器
#rpm –q ntp
#vim /etc/ntp.conf
Server 127.127.1.0 #NTPD把本地主机的时钟也看作外部时钟源来处理,分配的地址是127.127.1.0
Fudge 127.127.1.0 stratum 8
#service ntpd restart
NTPD的运行过程
NTPD启动后,stratum值初始是0,此时NTPD接收到NTP请求,回复Sstratum字段为0的NTP包,客户端接收后,发现stratum字段无效,拒绝更新时间,造成时间更新失败。
几分钟 后,NTPD从上级服务器获取到了更新,设置了正确的stratum,回复stratum字段为n+1的NTP包,客户端接收后,确认stratum有效,成功进行时间跟新。
在NTPD上级服务器不可用的情况下,NTPD将本机时钟服务模拟为一个上级NTP服务器,地址使用环回127.127.1.0,服务启动几分钟后,NTPD从127.127.1.0更新了时钟,设置了有效的stratum,客户端接收后,陈宫进行时间更新。
从服务器slave进行时间同步 :
#rpm -q ntpdate
#ntpdate 192.168.11.6
配置Master主服务器
#vim /etc/my.cnf
Server-id =213 //id号随便
Log-bin=master-bin
Log-slave-updates=true
#mysql -u root –p
Mysql>GRANT REPLICATION SLAVE ON *.* TO ‘myslave’@’192.168.11.10.%’ IDENTIFIED BY’123456’;
Mysql>FLUSH PRIVILEGES;
Mysql>show master status;
Service mysqld restart
配置slave从服务器
#vim /etc/my.cnf
Server-id =354
Relay-log=relay-log-bin
Relay-log-index=slave-relay-bin.index
#service mysqld restart
#mysql -u root –p
Mysql>change master to master_host=’192.168.11.78’,master_user=’myslave’,master_password=’123456’,master_log_file=’master-bin,0000001’,master_log_pos=338;
Mysql>start slave;
Mysql>show slave status\G;
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
验证主服务器与从服务器数据同步
在主服务器上创建数据库
Mysql>create database db_test;
在从服务器上查看数据库
Mysql>show databases;
搭建MySQL读写分离
在代理服务器Amoeba上安装java环境
上传jdk1.6版本jdk-6u14-linusx-x64.bin
#chmod +x /usr/local/jdk-6u14-linux-x64.bin
#cd /usr/local
#./jdk-6u14-linux-x64.bin
# mv jdk1.6.0_14/ /usr/local/jdk1.6
# vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/bin:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba/
# source /etc/profile
# java -versioon
Unrecognized option: -versioon
Could not create the Java virtual machine.
# java -version
java version "1.6.0_14"
Java(TM) SE Runtime Environment (build 1.6.0_14-b08)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b16, mixed mode)
安装并配置Amoeba软件
# mkdir /usr/local/amoeba
# tar zxf /root/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba
# chmod -R 755 /usr/local/amoeba/
# /usr/local/amoeba/bin/amoeba
amoeba start|stop
配置Amoeba读写分离,两个slave读负载均衡
在每个SQL上开发全新给Amoeba访问
Mysql>grant all on *.* to test@’192.168.11.%’ identified by ‘123456’;
#vim /usr/local/amoeba/conf/amoeba.xml
<property name=”authenticator”>
<bean class=”com.meidusa.amoeba.mysql.server.MysqlClientAuthenticator”>
<property name=”use”>amoeba</property>
<property name=”defaultPool”>master</property>
<property name=”writePool”>master</property>
<property name=”readPool”>slaves</property>
#vim /usr/local/amoeba/conf/dbServers.xml
<property name=”user”>test</property>
<property name=”password”>123456</property>
<dbServer name=”’master” paren=”abstractServer”>
<property name=”ipAddress”>192.168.11.78</property>
<dbServer name=”slave1” parent=”abstractServer”>
<property name=”ipAddress”>192.168.11.74</property>
<dbServer name=”slave1” parent=”abstractServer”>
<property name=”ipAddress”>192.168.11.74</property>
<property name=”poolNames”>slave1,slave2</property>
启动amoeba
#/usr/local/amoeba/bin/amoeba start
测试:
在Client主机上安装mysql并通过代理访问Mysql
#yum –y install mysql
#mysql –u amoeba –p123456 –h 192.168.10.11 –P8066
在主服务器Master上创建表
Mysql>use db_test;
Mysql>create table zang(id int(10),name varchar(10),address varchar(20));
在从服务器停止slave
Mysql>stop slave;
在主服务创建数据
Mysql>insert into zang values(‘1’,’zhang’,’this_is_master’);
从服务器创建数据
Mysql>use db_test;
Mysql>insert into zang values(‘2’,’zhang’,’this_is_slave1’);
在Client查询
Mysql>use db_test;
Mysql>select * from zang;
Mysql>insert into zang values(‘3’,’zhang’,’this_is_amoeba’)