准备两台装有mysql的虚拟机
安装mysql
https://aguai.fun/mysql二进制日志详解.html
主机名 | ip地址 |
MySQL1(主) | 192.168.1.10 |
MySQL2(从) | 192.168.1.20 |
MySQL支持哪些复制
(1)基于语句的复制
在主服务器上执行的sql语句,在从服务器上执行同样的语句。mysql默认采用基于语句的复制,效率比较高。一旦发现没法精确复制时,会自动选择基于行的复制。
(2)基于行的复制
把改变的内容复制过去,而不是把命令在从服务器上执行一遍,从mysql 5.0开始支持。
(3)混合类型的复制
默认采用基于语句的复制,一旦发现基于语句的无法精确复制时,就会采用基于行的复制。
MySQL复制解决的问题
- 数据分布(data distribution)
- 负载平衡(load balancing)
- 数据备份(backup),保证数据安全
- 高可用性与容错行(high availability and failover)
- 实现读写分离,缓解数据库压力
MySQL主从复制原理
master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中;slave服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变。如果发生改变,则开始一个I/O Thread请求master二进制事件,同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志 中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后I/O Thread和SQL Thread将进入睡眠状态,等待下一次被唤醒。
注意几点:
- master将操作语句记录到binlog日志中,然后授予slave远程连接的权限(master一定要开启binlog二进制日志功能;通常为了数据安全考虑,slave也开启binlog功能)。
- slave开启两个线程:IO线程和SQL线程。其中:IO线程负责读取master的binlog内容到中继日志relay log里;SQL线程负责从relay log日志里读出binlog内容,并更新到slave的数据库里,这样就能保证slave数据和 master数据保持一致了。
- Mysql复制至少需要两个Mysql的服务,当然Mysql服务可以分布在不同的服务器上,也可以在一台服务器上启动多个服务。
- Mysql复制最好确保master和slave服务器上的Mysql版本相同(如果不能满足版本一致,那么要保证master主节点的版本低于slave从节点的版本)。
- master和slave两节点间时间需同步。
MySQL复制流程
如上图所示:
- Mysql复制过程的第一部分就是master记录二进制日志。在每个事务更新数据完成之前,master在二日志记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务。
- 第二部分就是slave将master的binary log拷贝到它自己的中继日志。首先,slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,如果已经跟上master,它会睡眠并等待master产生新的事件。I/O线程将这些事件写入中继日志。
- SQL slave thread(SQL从线程)处理该过程的最后一步。SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。
- 此外,在master中也有一个工作线程:和其它MySQL的连接一样,slave在master中打开一个连接也会使得master开始一个线程。复制过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操作不能在slave上并行操作。
MySQL复制的模式
主从复制
主库授权从库远程连接,读取binlog日志并更新到本地数据库的过程;主库写数据后,从库会自动同步过来(从库跟着主库变)。
主主复制
主从相互授权连接,读取对方binlog日志并更新到本地数据库的过程;只要对方数据改变,自己就跟着改变。
MySQL主从复制优点
- 在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;(主库写,从库读,降压)
- 在从主服务器进行备份,避免备份期间影响主服务器服务;(确保数据安全)
- 当主服务器出现问题时,可以切换到从服务器。(提升性能)
MySQL主从复制工作流程细节
- MySQL支持单向、异步复制,复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。
- MySQL复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。每个从服务器从主服务器接收主服务器上已经记录到其二进制日志的保存的更新。当一个从服务器连接主服务器时,它通知主服务器定位到从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,并在本机上执行相同的更新。然后封锁并等待主服务器通知新的更新。从服务器执行备份不会干扰主服务器,在备份过程中主服务器可以继续处理更新。
- MySQL使用3个线程来执行复制功能,其中两个线程(Sql线程和IO线程)在从服务器,另外一个线程(IO线程)在主服务器。
- 当发出START SLAVE时,从服务器创建一个I/O线程,以连接主服务器并让它发送记录在其二进制日志中的语句。主服务器创建一个线程将二进制日志中的内容发送到从服务器。该线程可以即为主服务器上SHOW PROCESSLIST的输出中的Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷贝到从服务器数据目录中的本地文件中,即中继日志。第3个线程是SQL线程,由从服务器创建,用于读取中继日志并执行日志中包含的更新。在从服务器上,读取和执行更新语句被分成两个独立的任务。当从服务器启动时,其I/O线程可以很快地从主服务器索取所有二进制日志内容,即使SQL线程执行更新的远远滞后。
主从数据完成同步的过程
- 在Slave 服务器上执行sart slave命令开启主从复制开关,开始进行主从复制。
- 此时,Slave服务器的IO线程会通过在master上已经授权的复制用户权限请求连接master服务器,并请求从执行binlog日志文件的指定位置(日志文件名和位置就是在配置主从复制服务时执行change master命令指定的)之后开始发送binlog日志内容。
- Master服务器接收到来自Slave服务器的IO线程的请求后,其上负责复制的IO线程会根据Slave服务器的IO线程请求的信息分批读取指定binlog日志文件指定位置之后的binlog日志信息,然后返回给Slave端的IO线程。返回的信息中除了binlog日志内容外,还有在Master服务器端记录的IO线程。返回的信息中除了binlog中的下一个指定更新位置。
- 当Slave服务器的IO线程获取到Master服务器上IO线程发送的日志内容、日志文件及位置点后,会将binlog日志内容依次写到Slave端自身的Relay Log(即中继日志)文件(Mysql-relay-bin.xxx)的最末端,并将新的binlog文件名和位置记录到master-info文件中,以便下一次读取master端新binlog日志时能告诉Master服务器从新binlog日志的指定文件及位置开始读取新的binlog日志内容。
- Slave服务器端的SQL线程会实时检测本地Relay Log 中IO线程新增的日志内容,然后及时把Relay LOG 文件中的内容解析成sql语句,并在自身Slave服务器上按解析SQL语句的位置顺序执行应用这样sql语句,并在relay-log.info中记录当前应用中继日志的文件名和位置点。
主从复制条件
- 开启Binlog功能
- 主库要建立账号
- 从库要配置master.info(CHANGE MASTER to …相当于配置密码文件和Master的相关信息)
- start slave开启复制功能
需要注意的
- 主从复制是异步的逻辑的SQL语句级的复制
- 复制时,主库有一个I/0线程,从库有两个线程,I/0和SQL线程
- 实现主从复制的必要条件是主库要开启记录binlog功能
- 作为复制的所有Mysq1节点的server -i d都不能相同
- bin1 og文件只记录对数据库有更改的SQL语句(来自主库内容的变更),不记录任何查询 (select, show)语句
配置主从复制
主
[root@localhost ~]# vim /etc/my.cnf
添加
server-id = 1 #唯一的
log-bin = mysql-bin
binlog-ignore-db = mysql,information_schema
sync_binlog = 1
binlog_checksum = none
binlog_format = mixed
auto-increment-increment = 2 #唯一的
auto-increment-offset = 1 #唯一的
slave-skip-errors = all
[root@localhost ~]# systemctl restart mysqld
[root@localhost ~]# firewall-cmd --zone=public --add-port=3306/tcp --permanent
success
[root@localhost ~]# firewall-cmd --reload
success
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_length=6;
Query OK, 0 rows affected (0.00 sec)
mysql> grant replication slave,replication client on *.* to skx@'192.168.1.20' identified by 'skx123';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+--------------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000001 | 620 | | mysql,information_schema | |
+------------------+----------+--------------+--------------------------+-------------------+
1 row in set (0.00 sec)
从
[root@localhost ~]# vim /etc/my.cnf
添加
server-id= 2 #唯一的
log-bin = mysql-bin
binlog-ignore-db = mysql,information_schema
sync_binlog = 1
binlog_checksum = none
binlog_format = mixed
auto-increment-increment = 2 #唯一的
auto-increment-offset = 2 #唯一的
slave-skip-errors = all
[root@localhost ~]# systemctl restart mysqld
[root@localhost ~]# firewall-cmd --zone=public --add-port=3306/tcp --permanent
success
[root@localhost ~]# firewall-cmd --reload
success
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_policy=LOW;
Query OK, 0 rows affected (0.00 sec)
mysql> set global validate_password_length=6;
Query OK, 0 rows affected (0.00 sec)
mysql> grant replication slave,replication client on *.* to skx@'192.168.1.10' identified by 'skx123';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> FLUSH TABLES WITH READ LOCK;
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+--------------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000001 | 150 | | mysql,information_schema | |
+------------------+----------+--------------+--------------------------+-------------------+
1 row in set (0.00 sec)
从同步主
主、从
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
mysql> show master status;
+------------------+----------+--------------+--------------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+--------------------------+-------------------+
| mysql-bin.000001 | 150 | | mysql,information_schema | |
+------------------+----------+--------------+--------------------------+-------------------+
1 row in set (0.00 sec)
从
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to master_host='192.168.1.10',master_user='skx',master_password='skx123',master_log_file='mysql-bin.000001',master_log_pos=150;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status \G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
主同步从
主、从
mysql> reset master;
Query OK, 0 rows affected (0.00 sec)
主
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)
mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> change master to master_host='192.168.1.20',master_user='skx',master_password='skx123',master_log_file='mysql-bin.000001',master_log_pos=150;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status \G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
验证
主
mysql> create database ppp;
Query OK, 1 row affected (0.01 sec)
mysql> use ppp;
Database changed
mysql> create table grade(id int);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into grade values(1),(2),(3);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from grade;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
主或从随便创点东西,去另一台查看,就会看到同步过去了
从
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| ppp |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> use ppp;
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> select * from grade;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
Keepalived
Keepalived简介
keepalived的安装配置
安装keepalived
下载keepalived
wget https://www.keepalived.org/software/keepalived-2.0.20.tar.gz
安装依赖库
yum -y install kernel-devel openssl-devel popt-devel
解压
tar zxf keepalived-2.0.20.tar.gz
安装
[root@localhost ~]# cd keepalived-2.0.20/
[root@localhost keepalived-2.0.20]# ./configure --prefix=/ && make && make install
如果安装失败就
[root@localhost keepalived-2.0.20]# yum -y install gcc
再安装就好
更改配置
双主复制
更改配置
vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived //!表示注释
global_defs {
router_id MYSQL-1 //表示运行keepalived服务器的一个标识
}
vrrp_instance VI_1 {
# 指定keepalived的角色, 两台配置此处均是BACKUP,设为BACKUP将根据优先级决定主或从
state BACKUP
# 指定HA监测网络的接口
interface ens33
# 虚拟路由标识,这个标识是一个数字(取值在0-255之间,用来区分多个instance的VRRP组播),
# 同一个vrrp实例使用唯一的标识,确保和master2相同,同网内不同集群此项必须不同,否则发生冲突。
virtual_router_id 51
# 用来选举master的,要成为master,该项取值范围是1-255(在此范围之外会被识别成默认值100),
# 此处master2上设置为50
priority 100
# 发VRRP包的时间间隔,即多久进行一次master选举(可以认为是健康查检时间间隔)
advert_int 1
# 不抢占,即允许一个priority比较低的节点作为master,即使有priority更高的节点启动
nopreempt
# 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位)
authentication {
auth_type PASS
auth_pass 1111
}
# VIP区域,指定vip地址
virtual_ipaddress {
192.168.1.100
}
}
# 设置虚拟服务器,需要指定虚拟IP地址和服务端口,IP与端口之间用空格隔开
virtual_server 192.168.1.100 3306 {
# 设置运行情况检查时间,单位是秒
delay_loop 2
# 设置后端调度算法,这里设置为rr,即轮询算法
lb_algo rr
# 设置LVS实现负载均衡的机制,有NAT、TUN、DR三个模式可选
lb_kind DR
# 会话保持时间,单位是秒。
# 这个选项对动态网页是非常有用的,为集群系统中的session共享提供了一个很好的解决方案。
# 有了这个会话保持功能,用户的请求会被一直分发到某个服务节点,直到超过这个会话的保持时间。
persistence_timeout 60
# 指定转发协议类型,有TCP和UDP两种
protocol TCP
# 配置服务节点1,需要指定real server的真实IP地址和端口,IP与端口之间用空格隔开
# 注:master 2上此处改为192.168.206.130(即master2本机ip)
real_server 192.168.1.10 3306 {
# 配置服务节点的权值,权值大小用数字表示,数字越大,权值越高,
# 设置权值大小为了区分不同性能的服务器
weight 3
# 检测到realserver的mysql服务down后执行的脚本
notify_down /etc/keepalived/bin/mysql.sh
TCP_CHECK {
# 连接超时时间
connect_timeout 3
# 重连次数
nb_get_retry 3
# 重连间隔时间
delay_before_retry 3
# 健康检查端口
connect_port 3306
}
}
}
注意,无论有多少台主机,虚拟ip只有一个
另外需要设置优先级,将以下内容第一台位100,第二台为50
priority 100
防火墙配置
systemctl stop firewalld
或者
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface ens33 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --reload
然后启动mysql
systemctl start mysqld
查看
[root@localhost ~]# systemctl restart keepalived.service
[root@localhost ~]# ip addr show dev ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:db:26:5a brd ff:ff:ff:ff:ff:ff
inet 192.168.1.20/24 brd 192.168.1.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet 192.168.1.200/32 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::fb75:de75:6b38:a7a4/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@localhost ~]# systemctl restart keepalived.service
[root@localhost ~]# ip addr show dev ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:30:ac:24 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.10/24 brd 192.168.1.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::b893:ffae:d8f4:c2c2/64 scope link noprefixroute
valid_lft forever preferred_lft forever
测试
停掉优先级高的主机,虚拟ip会到第二台上