官网下载 mysql
https://www.mysql.com/
现在企业中用的最多的也是5.6 5.7,我们下载5.7版本的就可。
实验环境:
server1 172.25.254.1 前三种复制方式中充当master结点
server2 172.25.254.2 前三中复制方式中充当slave结点
server3 172.25.254.3 再做全同步复制时开启
在做实验的时候每台主机之间必须有解析,因为后面的实验会用到解析。
安装mysql
下载的 rpm-bundle 包里面有:
将他们用rpm的方式进行安装。
它的配置文件为 /etc/my.cnf
并且会自动生成 /var/log/mysqld.log 的日志文件,并且会生成一个初始密码:
[root@server1 ~]# cat /var/log/mysqld.log | grep password
2020-05-09T13:56:35.301030Z 1 [Note] A temporary password is generated for root@localhost: Khq*fpetp1S<
初次登陆它会警告我们更改密码:
进行安全初始化:
mysql_secure_installation
这里的密码设置要求较高,需要设置的复杂一点 ,我的密码为Cc990718-+
进行相关的设置就可以了。
登陆数据库:
就可以登陆了。
mysql中的锁
对数据的操作其实只有两种,也就是读和写,而数据库在实现锁时,也会对这两种操作使用不同的锁,
- 共享锁(读锁),允许多个事务读一行数据。Share Lock
- 排他锁(写锁),允许一个事务删除或更新一行数据,其他事物不可以在上锁(读或写)。Exclusive Lock
mysql中的事务
事务: event ,具有四个个特性,原子性,隔离性,一致性,持久性
是无就是一组原子性的SQL查询,或者说一个独立的工作单元。
如果数据库引擎能够成功地对数据库进行该组查询的全部语句,那么就执行改组查询,如果其中有任何一条语句因为崩溃或者其它原因而无法执行,那么所有的语句都不会执行,也就是说,事务内的语句,要莫全部执行成功,要么全部执行失败。
mysql的主从复制(基于二进制日志)
主节点 server1 :172.25.254.1
从结点 server2 :172.25.254.2
原理:复制操作,不是复制数据,更稳定。
主节点先进行写操作,然后会把操作记录进二进制的日志文件中,此时主节点的dump的线程会通知从结点的IO线程复制数据,IO线程就和master结点进行通信,然后把获取到的二进制日志数据写入到终继日志(relay log)中,此时SQL线程会读取中继日志中的内容,在本机重新执行一次(replay)
master 主节点中配置文件:
vim /etc/my.cnf
然后打开数据库,执行命令,为复制创建一个用户:
# 创建repl用户,%代表整个网段,Cc9为密码
mysql> CREATE USER 'repl'@'172.25.254.%' IDENTIFIED BY 'Cc990718-+';
Query OK, 0 rows affected (0.00 sec)
#授权所有库的所有表的复制权限给刚创建的用户
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'172.25.254.%';
Query OK, 0 rows affected (0.00 sec)
SHOW MASTER STATUS; 获取,当前二进制日志的文件名称和位置
然后层测试使用repl用户登录;
slave 从结点进行配置
配置文件:vim /etc/my.cnf
登陆mysql执行命令:
mysql> CHANGE MASTER TO
-> MASTER_HOST='172.25.254.1', 主机名
-> MASTER_USER='repl', 用户
-> MASTER_PASSWORD='Cc990718-+', 密码
-> MASTER_LOG_FILE='mysql-bin.000001', 主节点获取到的文件名
-> MASTER_LOG_POS=154; 主节点获取到的文件位置
#CHANGE MASTER TO MASTER_HOST='172.25.254.1',MASTER_USER='repl',MASTER_PASSWORD='Cc990718-+',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=154;
start slave; 开启复制
show slave status\G 查看slave结点状态,可以看见SQL线程和IO线程都是yes ,则正常开启复制
IO 线程负责和master结点进行通信,SQL进程负责把通信得来的数据写入到本机的数据库。
查看复制:
在主节点创建的数据库就可以在从结点看到了。
我们再在主节点创建一张表:
在从结点查看:
这就说明主从复制是ok的,这就是基于二进制日志的主从复制.
这里面是mysql的一些日志信息,我们可以用 mysqlbinlog 读取这些日志
基于全局事务标识的复制GTID
避免了即与二进制文件日志的复制的缺点:中途出现错误时事务就不能完整进行了,就成为了废数据。
GTID的优点就就是把一个事物看成一个单元,要么整体成功,要么整体失败。
在两台主机上的配置文件都加上GTID:
然后再slave结点去配置基于gtid的自动位置识别:
先停掉上面的基于二进制文件的slave:
再修改复制的方式,开启复制;
IO和SQL线程开启。
跟踪gtid 和执行gtid。
我们再次插入数据进行尝试:
插入user2,
这时slave结点也能看到了,
并且此时查看状态 , gtid捕捉到了一个事务:
半同步复制 Semi-synchronous replication
传统的复制原理:
master的新事务 t1 -> binlog buffer(缓冲区) -> dumper -> slave
binlog buffer(check) -> slave(IO) -> relay log -> SQL -> mysql
- 传统的几种复制方式存在一个普遍的问题,就是如果master主节点执行一个比较大的任务时,slave主机的复制会消耗系统资源,会有一些延迟,这个时候如果slave还没有复制完成时master结点就挂掉了,这时还没有完成复制的slave就被迫成为新的master主机,这样的方式就会丢失数据。
- 这样是有很大的缺陷的,所以mysql在5.5本本后就退出了这个半同步复制,相比于异步复制(GTID,二进制日志)提高了数据的完整性。
- 也就是说master的dumper线程在通知slave之后会接收slave的ack的确认消息,ack 就是是否成功收到 t1 的标志,slave结点再把所有的 binlog 的数据记录到relay log 中后才会返回ack给dumper线程。
- 如果没有收到ack信号就进入到等待,直到接至少接收到一个ack信号为止(slave结点可能由有多个),如果等待超时,就降级为普通的异步复制,接收到了ack就说明slave结点接收到了完整的 t1 ,就继续进行新的事务。
在主节点安装插件:
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (0.16 sec)
在每个子结点安装插件:
mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
Query OK, 0 rows affected (0.03 sec)
插件安装完成。
激活插件:
mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
Query OK, 0 rows affected (0.00 sec)
slave 结点重启IO线程:
mysql> stop slave IO_THREAD;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> start slave IO_THREAD;
Query OK, 0 rows affected (0.00 sec)
在master结点查看状态:
功能打开,且又一个客户端在半同步复制。
功能打开,超时时间为10s。
slave结点查看:
现在在主节点插入数据测试:
复制正常,但我们怎样测试接收的ack信号哪?,我们关闭slave结点的IO线程。
mysql> stop slave io_thread;
Query OK, 0 rows affected (0.04 sec)
然后再次在追结点插入数据。
可见此时等待了10s才结束的,这时就已经切换到了异步复制了。
再次插入:
就又非常快了,因为已经到了异步复制了。
但这时我们在slave主机看不到刚才插入的两条数据:
我们再开启slave结点上的IO线程:
可见数据就又回来了。
全同步复制,组复制
group replication。银行机构一般会使用全同步。
组复制不同与半同步复制的地方在于,master结点会接收到所有的slave结点的ack信号时才会开始下一步。而半同步只要求接收到 >= 一个的信号就可以了。由于每台结点的内容都一样,所以每台结点主机都可以作为master结点。
我们开启第三台虚拟机: server3 172.25.254.3 作为第二个slave结点。
在三个结点中进行配置:
关闭数据库,并清空之前的数据。
systemctl stop mysqld
rm -fr /var/lib/mysql/*
配置文件:
删除前面的配置,并添加下面的配置:
vim /etc/my.cnf
server1 :
server_id=1
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
plugin_load_add='group_replication.so'
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="1d630e12-92a0-11ea-943f-525400685c65"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "172.25.254.1:33061"
loose-group_replication_group_seeds= "172.25.254.1:33061,172.25.254.2:33061,172.25.254.3:33061" # 主机组
loose-group_replication_bootstrap_group=off
loose-group_replication_ip_whitelist='127.0.0.1,172.25.254.0/24'
loose-group_replication_enforce_update_everywhere_check=ON
loose-group_replication_single_primary_mode=OFF 关闭单主机模式,
server2:
server_id=2 这里的id不能和上面相同
gtid_mode=ON
enforce_gtid_consistency=ON
master_info_repository=TABLE
relay_log_info_repository=TABLE
binlog_checksum=NONE
log_slave_updates=ON
log_bin=binlog
binlog_format=ROW
plugin_load_add='group_replication.so'
transaction_write_set_extraction=XXHASH64
loose-group_replication_group_name="1d630e12-92a0-11ea-943f-525400685c65"
loose-group_replication_start_on_boot=off
loose-group_replication_local_address= "172.25.254.2:33061" 本地ip
loose-group_replication_group_seeds= "172.25.254.1:33061,172.25.254.2:33061,172.25.254.3:33061"
loose-group_replication_bootstrap_group=off
loose-group_replication_ip_whitelist='127.0.0.1,172.25.254.0/24'
loose-group_replication_enforce_update_everywhere_check=ON
loose-group_replication_single_primary_mode=OFF
做完后我们启动mysqld ,并重新进行初始化,因为我们刚才删除了全部的文件,所以会重新生成初始密码,我们进行更改(三台主机都做):
mysql> alter user root@localhost identified by 'Cc990718-+';
Query OK, 0 rows affected (0.10 sec)
在mysql中进行配置:
server1:
#关闭二进制日志,防止中间三步产生的日志数据传输混乱
mysql> SET SQL_LOG_BIN=0;
Query OK, 0 rows affected (0.00 sec)
#创建用户
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'Cc990718-+';
Query OK, 0 rows affected (0.00 sec)
#授权所有库所有表
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
Query OK, 0 rows affected (0.00 sec)
#刷新授权表
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
#再次开启二进制日志
mysql> SET SQL_LOG_BIN=1;
Query OK, 0 rows affected (0.00 sec)
#更改master用户,并指定组复制的插件。
mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='Cc990718-+' FOR CHANNEL 'group_replication_recovery';
Query OK, 0 rows affected, 2 warnings (0.25 sec)
#安装组复制的插件
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
#发起组复制,生成组名,只能再一个结点开启, 这里我们选择server1
mysql> SET GLOBAL group_replication_bootstrap_group=ON;
Query OK, 0 rows affected (0.00 sec)
#启动组复制
mysql> START GROUP_REPLICATION;
Query OK, 0 rows affected (2.56 sec)
#关闭这个是因为这个参数会再每次开启组复制时生成一个组名,这样就混乱了,所以我们开启一次就关闭。
mysql> SET GLOBAL group_replication_bootstrap_group=OFF;
Query OK, 0 rows affected (0.00 sec)
#获取组信息,当前只有一台
mysql> SELECT * FROM performance_schema.replication_group_members;
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| CHANNEL_NAME | MEMBER_ID | MEMBER_HOST | MEMBER_PORT | MEMBER_STATE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
| group_replication_applier | 26ff60fd-92a1-11ea-9713-525400e49b44 | server1 | 3306 | ONLINE |
+---------------------------+--------------------------------------+-------------+-------------+--------------+
1 row in set (0.00 sec)
然后我们把server2 和server3 加进组去,和上面相同的操作:
server2和server3:
mysql> SET SQL_LOG_BIN=0;
mysql> CREATE USER rpl_user@'%' IDENTIFIED BY 'Cc990718-+';
mysql> GRANT REPLICATION SLAVE ON *.* TO rpl_user@'%';
mysql> FLUSH PRIVILEGES;
mysql> SET SQL_LOG_BIN=1;
mysql> CHANGE MASTER TO MASTER_USER='rpl_user', MASTER_PASSWORD='Cc990718-+' FOR CHANNEL 'group_replication_recovery';
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
mysql> START GROUP_REPLICATION;
## 如果报错,先关闭组复制,再执行这条命令,这是由于数据冲突产生的
set global group_replication_allow_local_disjoint_gtids_join=on;
这时我们再server1查看组:
server2和server3就加进去了。
这时我们就可以输入数据进行测试了:
再server1中插入数据:
INSERT INTO t1 VALUES (1, 'Luis');
再server3中插入数据:
insert into t1 values (2,'cay');
在server2中查看:
发现所有的组内的主机的数据都是一样的。
这样的方式是因为我们在哪一台主机上插入数据,那一台主机就是master主机。这就是组复制的原理。