MySQL日志及主从复制实现

MySQL日志及主从复制实现

 

一:MySQL是一个关系型数据库管理系统,最早由瑞典MySQL AB 公司发,后在2008年1月16号被Sun公司用10亿美金收购,但好景不长,2010年4月20日oracle用74亿美金收购了Sun,因此到目前MySQL属于 Oracle旗下产品。MySQL 最流行的关系型数据库管理系统,在 WEB 应用方面MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一,MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。
MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,它分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库,由于其社区版的性能卓越,搭配 PHP 和 Apache 可组成良好的开发环境。

1.1:MySQL主从复制过程:

    MySQL主从同步一共需要三个线程的操作,主MySQL有一个IO线程,从MySQL有一个IO线程和一个SQL线程, MySQL主从是实现MySQL高可用、数据备份、读写分离架构的一种最常见的解决方案,在绝大部分公司都有使用,要实现MySQL主从复制,必须要在Master打开binary log(bin-log)功能,因为整个MySQL的复制过程实际就是Slave从Master端获取响应的二进制日志,然后在Slave端顺序的执行日志中所记录的各种操作,二进制日志中几乎记录了出select以外的所有针对数据库的sql操作语句,具体的复制过程如下:

1.1.1:Slave端的IO线程连接上Master,并向Master请求指定日志文件的指定位置(新部署的Master和Slave从最开始的日志)之后的日志。

1.1.2:Master接收到来自Slave的IO线程请求,负责IO复制的IO线程根据Slave的请求信息读取相应的日志内容,然后将本地读取的bin-log的文件名、位置及指定位置之后的内容一起返回给Slave的IO线程处理。

1.1.3:Slave的IO线程将接收到的信息依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的bin-log的文件名和位置记录到Master-info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从哪个bin-log的哪个位置开始往后的日志内容请发给我”。

1.1.4:Slave的sql线程检查到relay-log中新增了内容后,会马上将relay-log中的内容解析为在Master端真实执行时候的可执行命令,并顺序执行,从而保证对Slave的MySQL进行响应的增加或删除等操作,最终实现和Master数据保持一致。

1.2:减少主从同步延时的方案:

1.2.1:从库使用SSD硬盘,这样从库可以用最快的速度从主控同步数据

1.2.2:尽量在主库使用避免大量的写入,可以使用其他非关系型数据库的尽量使用非关系型数据库

1.2.3:主库和从库直接使用专用网络高速互联

1.2.4:对于数据一致性要求比较严格的场景,就不查询从库,因为从库可能有数据未同步到数据

1.2.5:读场景比较大的场景,可以使用多个从库,将读请求在各个slave服务器分解处理

1.3:数据库延迟复制,即设置slave故意从master延迟同步一小时或其他指定时间差,用于解决一下三个问题:

1.3.1:用于在数据库误操作之后快速的恢复数据,比如误删除表,那个这个延迟操作在延迟时间内从库的数据还没有发生变化,可以使用从库的数据进行恢复,然后再把一小时内的bin-log补写到Master即可完成数据的全部恢复。

1.3.2:用来做延迟测试,比如做好的数据库读写分离,把从库作为读库,即测试主从数据延迟五分钟或指定的时候,业务会发生什么样的问题,即可以模拟数据库延迟指定时间的业务错误。

1.3.3:用于老数据的查询,比如经常需要查看某天前的一个表或者字段的数值,你可能需要把备份恢复之后才能进行查看,但是如果有延迟从库,比如延迟一周,那么久可以解决这一的类似的业务需求场景。

1.3.4:设置延迟复制,通过设置SLAVE上的MASTER TO MASTER_DELAY参数来实现:

CHANGE MASTER TO MASTER_DELAY = N;

N为多少秒,该语句设置从库延时N秒后再与主数据库进行同步复制

1.3.5:具体MySQL延迟复制操作,登录到SLAVE之上进行操作:

mysql> stop slave;
mysql> CHANGE MASTER TO MASTER_DELAY = 600; mysql> start slave; mysql> SHOW SLAVE STATUS \G;

1.4:生产环境MySQL经验:

1.4.1:生产应用MySQL用户,不允许执行delete,可以只授权给update、select、insert,可以把delete更改为update,将要删除的数据加一个字段标记为已删除,因此线上的业务可以不需要delete

1.4.2:在有条件的情况下做一个延迟一小时等制定时间的从库

1.4.3:所有DML操作之前必须备份

1.4.4:规范开发在update数据库必须有两个脚本,如下:

1.4.4.1:数据库修改脚本,修改数据库的脚本

1.4.4.2:数据库回滚脚本,当数据更新失败的时候用于回滚

1.5:DML操作备份脚本

dml_backup.sh  stable_name  #输入表明即可备份表

1.5.1:开启相关日志:

[mysqld]
socket=/var/lib/mysql/mysql.sock user=mysql symbolic-links=0 datadir=/data/mysql innodb_file_per_table=1 relay-log = /data/mysql server-id=20 log-error= /data/mysql_error.txt #记录错误日志 log-bin=/data/mysql/master-log #MySQL的bin-log即二进制日志,记录二进制形式SQL语句、主从复制和增量备份使用 general_log=ON #正常查询日志 general_log_file=/data/general_mysql.log long_query_time=2 #慢查询日志配置 slow_query_log=1 slow_query_log_file= /data/slow_mysql.txt [client] port=3306 socket=/var/lib/mysql/mysql.sock [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/tmp/mysql.sock

1.5.2:mysqlsla 工具使用:

使用语法如下:
# mysqlslap [options]
常用参数 [options] 详细说明:
–auto-generate-sql, -a 自动生成测试表和数据,表示用mysqlslap工具自己生成的SQL脚本来测试并发压力。
–auto-generate-sql-load-type=type 测试语句的类型。代表要测试的环境是读操作还是写操作还是两者混合的。取值包括:read,key,write,update和mixed(默认)。
–auto-generate-sql-add-auto-increment 代表对生成的表自动添加auto_increment列,从5.1.18版本开始支持。
–number-char-cols=N, -x N 自动生成的测试表中包含多少个字符类型的列,默认1
–number-int-cols=N, -y N 自动生成的测试表中包含多少个数字类型的列,默认1
–number-of-queries=N 总的测试查询次数(并发客户数×每客户查询次数)
–query=name,-q 使用自定义脚本执行测试,例如可以调用自定义的一个存储过程或者sql语句来执行测试。
–create-schema 代表自定义的测试库名称,测试的schema,MySQL中schema也就是database。
–commint=N 多少条DML后提交一次。
–compress, -C 如果服务器和客户端支持都压缩,则压缩信息传递。
–concurrency=N, -c N 表示并发量,也就是模拟多少个客户端同时执行select。可指定多个值,以逗号或者–delimiter参数指定的值做为分隔符。例如:–concurrency=100,200,500。
–engine=engine_name, -e engine_name 代表要测试的引擎,可以有多个,用分隔符隔开。例如:–engines=myisam,innodb。
–iterations=N, -i N 测试执行的迭代次数,代表要在不同并发环境下,各自运行测试多少次。
–only-print 只打印测试语句而不实际执行。
–detach=N 执行N条语句后断开重连。
–debug-info, -T 打印内存和CPU的相关信息。

说明:
测试的过程需要生成测试表,插入测试数据,这个mysqlslap可以自动生成,默认生成一个mysqlslap的schema,如果已经存在则先删除。可以用–only-print来打印实际的测试过程,整个测试完成后不会在数据库中留下痕迹。
各种测试参数实例(-p后面跟的是mysql的root密码):
单线程测试。测试做了什么。
# mysqlslap -a -uroot -p123456
多线程测试。使用–concurrency来模拟并发连接。
# mysqlslap -a -c 100 -uroot -p123456
迭代测试。用于需要多次执行测试得到平均值。
# mysqlslap -a -i 10 -uroot -p123456
# mysqlslap —auto-generate-sql-add-autoincrement -a -uroot -p123456
# mysqlslap -a –auto-generate-sql-load-type=read -uroot -p123456
# mysqlslap -a –auto-generate-secondary-indexes=3 -uroot -p123456
# mysqlslap -a –auto-generate-sql-write-number=1000 -uroot -p123456
# mysqlslap –create-schema world -q “select count(*) from City” -uroot -p123456
# mysqlslap -a -e innodb -uroot -p123456
# mysqlslap -a –number-of-queries=10 -uroot -p123456
测试同时不同的存储引擎的性能进行对比:
# mysqlslap -a –concurrency=50,100 –number-of-queries 1000 –iterations=5 –engine=myisam,innodb –debug-info -uroot -p123456
执行一次测试,分别50和100个并发,执行1000次总查询:
# mysqlslap -a –concurrency=50,100 –number-of-queries 1000 –debug-info -uroot -p123456
50和100个并发分别得到一次测试结果(Benchmark),并发数越多,执行完所有查询的时间越长。为了准确起见,可以多迭代测试几次:
# mysqlslap -a –concurrency=50,100 –number-of-queries 1000 –iterations=5 –debug-info -uroot -p123456

二:数据库主从同步实现:

2.1:两台服务器分别安装MySQL,提前准备好安装包和my.conf文件,使用以下脚本自动安装:

[root@sql-master mysql]# cat mysql-install.sh  #!/bin/bash DIR=`pwd` NAME="mysql-5.6.34-linux-glibc2.5-x86_64.tar.gz" FULL_NAME=${DIR}/${NAME} DATA_DIR="/data/mysql" yum install vim gcc gcc-c++ wget autoconf net-tools lrzsz iotop lsof iotop bash-completion -y yum install curl policycoreutils openssh-server openssh-clients postfix -y if [ -f ${FULL_NAME} ];then echo "安装文件存在" else echo "安装文件不存在" exit 3 fi if [ -h /usr/local/mysql ];then echo "Mysql 已经安装" exit 3 else tar xvf ${FULL_NAME} -C /usr/local/src ln -sv /usr/local/src/mysql-5.6.34-linux-glibc2.5-x86_64 /usr/local/mysql if id mysql;then echo "mysql 用户已经存在,跳过创建用户过程" fi useradd mysql -s /sbin/nologin if id mysql;then chown -R mysql.mysql /usr/local/mysql/* -R if [ ! -d /data/mysql ];then mkdir -pv /data/mysql && chown -R mysql.mysql /data -R /usr/local/mysql/scripts/mysql_install_db --user=mysql --datadir=/data/mysql --basedir=/usr/local/mysql/ cp /usr/local/src/mysql-5.6.34-linux-glibc2.5-x86_64/support-files/mysql.server /etc/init.d/mysqld chmod a+x /etc/init.d/mysqld cp ${DIR}/my.cnf /etc/my.cnf ln -sv /usr/local/mysql/bin/mysql /usr/bin/mysql /etc/init.d/mysqld start else echo "MySQL数据目录已经存在," exit 3 fi fi fi

1.2:更改Master和Slave的my.conf文件,主要将id改为不一样:

1.2.1:Master的配置my.conf文件,更改完成重启MySQL服务:

[root@sql-master ~]# cat /etc/my.cnf [mysqld] socket=/var/lib/mysql/mysql.sock user=mysql symbolic-links=0 datadir=/data/mysql innodb_file_per_table=1 server-id=10 log-bin=/data/mysql/master-log [client] port=3306 socket=/var/lib/mysql/mysql.sock [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/tmp/mysql.sock

1.2.2:Slave的my.cnf配置文件,更改完成重启MySQL服务:

[root@sql-slave ~]# cat /etc/my.cnf [mysqld] socket=/var/lib/mysql/mysql.sock user=mysql symbolic-links=0 datadir=/data/mysql innodb_file_per_table=1 relay-log = /data/mysql #中级日志的路径 server-id=20 #server id与Master不能一样 [client] port=3306 socket=/var/lib/mysql/mysql.sock [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/tmp/mysql.sock

1.2.3:在 Master生成简单数据:

mysql> create database testdatabase; #创建库 Query OK, 1 row affected (0.00 sec) mysql> use testdatabase; #切换库 Database changed mysql> CREATE TABLE testtable (Id_P int,Name varchar(255),Address varchar(255),City varchar(255)); #创建表 Query OK, 0 rows affected (0.47 sec) mysql> show tables; #查看表 +------------------------+ | Tables_in_testdatabase | +------------------------+ | testtable | +------------------------+ 1 row in set (0.01 sec) mysql> INSERT INTO testtable VALUES (1,"Jack","China","Beijing"); #插入数据 Query OK, 1 row affected (0.00 sec) mysql> select * from testtable; #插卡数据并验证 +------+------+---------+---------+ | Id_P | Name | Address | City | +------+------+---------+---------+ | 1 | Jack | China | Beijing | +------+------+---------+---------+ 1 row in set (0.00 sec)

1.2.4:创建同步账号:

mysql>  GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'tom'@'192.168.10.%' IDENTIFIED BY '123456'; #授权tom从192.168.10.*使用密码123456同步数据 Query OK, 0 rows affected (0.30 sec)

1.2.5:Master导出数据、复制到Slave:

[root@sql-master ~]# /usr/local/mysql/bin/mysqldump --all-databases --single_transaction --flush-logs --master-data=2 --lock-tables > /backup.sql [root@sql-master ~]# scp /backup.sql 192.168.10.102:/opt/ root@192.168.10.102's password: backup.sql 100% 637KB 636.7KB/s 00:00

1.2.6:Slave将sql文件导入并记录Master的日志文件名称和要同步的位置:

[root@sql-slave ~]# /usr/local/mysql/bin/mysql < /opt/backup.sql

1.2.7:在Slave配置从Master同步并设置Slave开启 只读:

mysql> CHANGE MASTER TO    MASTER_HOST='192.168.10.101',MASTER_USER='tom',MASTER_PASSWORD='123456',MASTER_LOG_FILE='master-log.000006',MASTER_LOG_POS=120; Query OK, 0 rows affected, 2 warnings (0.01 sec) mysql> start slave; Query OK, 0 rows affected (0.00 sec) mysql> show global variables like "%read_only%"; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | innodb_read_only | OFF | | read_only | OFF | | tx_read_only | OFF | +------------------+-------+ 3 rows in set (0.00 sec) mysql> set global read_only=1; #开启只读模式,只读模式仅对普通用户生效,对root不生效 Query OK, 0 rows affected (0.00 sec) mysql> show global variables like "%read_only%"; #验证是否生效 +------------------+-------+ | Variable_name | Value | +------------------+-------+ | innodb_read_only | OFF | | read_only | ON | | tx_read_only | OFF | +------------------+-------+ 3 rows in set (0.00 sec)

1.2.8:验证Slave的IO线程与SQL线程是OK的:

mysql> show slave status\G;
*************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 192.168.10.101 Master_User: tom Master_Port: 3306 Connect_Retry: 60 Master_Log_File: master-log.000006 Read_Master_Log_Pos: 120 Relay_Log_File: mysql.000002 Relay_Log_Pos: 284 Relay_Master_Log_File: master-log.000006 Slave_IO_Running: Yes #这两个线程状态必须为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: 120 Relay_Log_Space: 447 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收到的bin-log到当前的同步位置差多少秒,不是严格意义的主从差多少秒,因为Master的bin-log更新以后可能还没有同步到Slave 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: 10 Master_UUID: 003e966d-de3e-11e6-bc0f-000c2944baf2 Master_Info_File: /data/mysql/master.info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: Executed_Gtid_Set: Auto_Position: 0 1 row in set (0.00 sec)

1.2.9:关于Master_Info_File:

记录了MySQL Master的IP地址、同步使用的用户名和密码、MySQL端口、bin-log日志文件名等信息:

[root@sql-slave ~]# cat /data/mysql/master.info 23 master-log.000006 #Master bin-log的文件名 392 #Master的Position位置  192.168.10.101 #Master地址 tom #同步用户 123456 #密码 3306 #端口 60 0 0 1800.000 0 003e966d-de3e-11e6-bc0f-000c2944baf2 86400 0

1.2.10:Master信息如下:

mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +-------------------+----------+--------------+------------------+-------------------+ | master-log.000006 | 392 | | | | +-------------------+----------+--------------+------------------+-------------------+

1.2.11:

为了保证主从同步可以一直进行,在slave库上要保证具有super权限的root等用户只能在本地登录,不会发生数据变化,其他远程连接的应用用户只按需分配为select,insert,update,delete等权限,保证没有super权限,则只需要将salve设定“read_only=1”模式,即可保证主从同步,又可以实现从库只读。

1.3:在Master 新插入数据,验证是否回同步到Slave:

1.3.1:在Master插入数据:

mysql> use testdatabase;
Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> INSERT INTO testtable VALUES (2,"tom","China","Beijing"); Query OK, 1 row affected (0.00 sec)

1.3.2:在Slave验证数是否同步完成:

1.4:MySQL主从同步状态和监控脚本:

1.4.1:脚本内容:

[root@sql-slave ~]# cat mysql_monitor.sh  #!/bin/bash Seconds_Behind_Master(){ NUM=`mysql -uroot -hlocalhost -e "show slave status\G;" | grep "Seconds_Behind_Master:" | awk -F: '{print $2}'` echo $NUM } master_slave_check(){ NUM1=`mysql -uroot -hlocalhost -e "show slave status\G;" | grep "Slave_IO_Running" | awk -F: '{print $2}' | sed 's/^[ \t]*//g'` #echo $NUM1 NUM2=`mysql -uroot -hlocalhost -e "show slave status\G;" | grep "Slave_SQL_Running:" | awk -F: '{print $2}' | sed 's/^[ \t]*//g'` #echo $NUM2 if test $NUM1 == "Yes" && test $NUM2 == "Yes";then echo 50 else echo 100 fi } main(){ case $1 in Seconds_Behind_Master) Seconds_Behind_Master; ;; master_slave_check) master_slave_check ;; esac } main $1

1.4.2:执行结果:

1.4.3:zabbix添加主从同步状态监控并报警:

1.4.4:zabbix添加主从同步延迟并报警:

猜你喜欢

转载自www.cnblogs.com/dengbingbing/p/10497365.html