MySQL——高可用+中间件代理

MySQL高可用

6.3.1 MySQL高可用解决方案

MySQL官方和社区里推出了很多高可用的解决方案,大体如下,仅供参考(数据引用自Percona)

MySQL——高可用+中间件代理_第1张图片

  • MMM: Multi-Master Replication Manager for MySQL,Mysql主主复制管理器是一套灵活的脚本程序,基于perl实现,用来对mysql replication进行监控和故障迁移,并能管理mysql Master-Master复制的配置(同一时间只有一个节点是可写的) 官网: http://www.mysql-mmm.orghttps://code.google.com/archive/p/mysql-master-master/downloads
  • MHA:Master High Availability,对主节点进行监控,可实现自动故障转移至其它从节点;通过提升某一从节点为新的主节点,基于主从复制实现,还需要客户端配合实现,目前MHA主要支持一主多从的架构,要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器,一主二从,即一台充当master,一台充当备用master,另外一台充当从库,出于机器成本的考虑,淘宝进行了改造,目前淘宝TMHA已经支持一主一从 官方网站:https://code.google.com/archive/p/mysql-master-ha/https://github.com/yoshinorim/mha4mysql-manager/wiki/Downloads
  • Galera Cluster:wsrep(MySQL extended with the Write Set Replication) 通过wsrep协议在全局实现复制;任何一节点都可读写,不需要主从复制,实现多主读写
  • GR(Group Replication):MySQL官方提供的组复制技术(MySQL 5.7.17引入的技术),基于原生复制技术Paxos算法,实现了多主更新,复制组由多个server成员构成,组中的每个server可独立地执行事务,但所有读写事务只在冲突检测成功后才会提交

MySQL——高可用+中间件代理_第2张图片

这3个节点互相通信,每当有事件发生,都会向其他节点传播该事件,然后协商,如果大多数节点都同意这次的事件,那么该事件将通过,否则该事件将失败或回滚。这些节点可以是单主模型的(single-primary),也可以是多主模型的(multi-primary)。单主模型只有一个主节点可以接受写操作,主节点故障时可以自动选举主节点。多主模型下,所有节点都可以接受写操作,所以没有master-slave的概念。

6.3.2 MHA Master High Availability
6.3.2.1 MHA 工作原理和架构

MHA集群架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4zR8I4kR-1614077832799)(http://www.yunweipai.com/wp-content/uploads/2020/05/image-20191031160436946-780x592.png)]

MHA工作原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Nfy5QN5d-1614077832811)(http://www.yunweipai.com/wp-content/uploads/2020/05/image-20191031160515157-780x519.png)]

  1. 从宕机崩溃的master保存二进制日志事件(binlog events)
  2. 识别含有最新更新的slave
  3. 应用差异的中继日志(relay log)到其他的slave
  4. 应用从master保存的二进制日志事件(binlog events)
  5. 提升一个slave为新的master
  6. 使其他的slave连接新的master进行复制

MHA软件 MHA软件由两部分组成,Manager工具包和Node工具包 Manager工具包主要包括以下几个工具:

  • masterha_check_ssh 检查MHA的SSH配置状况
  • masterha_check_repl 检查MySQL复制状况
  • masterha_manger 启动MHA
  • masterha_check_status 检测当前MHA运行状态
  • masterha_master_monitor 检测master是否宕机
  • masterha_master_switch 故障转移(自动或手动)
  • masterha_conf_host 添加或删除配置的server信息

**Node工具包:**这些工具通常由MHA Manager的脚本触发,无需人为操作)主要包括以下几个工具:

  • save_binary_logs 保存和复制master的二进制日志
  • apply_diff_relay_logs 识别差异的中继日志事件并将其差异的事件应用于其他的slave
  • filter_mysqlbinlog 去除不必要的ROLLBACK事件(MHA已不再使用此工具)
  • purge_relay_logs 清除中继日志(不会阻塞SQL线程)

注意:为了尽可能的减少主库硬件损坏宕机造成的数据丢失,因此在配置MHA的同时建议配置成MySQL 5.5的半同步复制

MHA自定义扩展:

  • secondary_check_script: 通过多条网络路由检测master的可用性
  • master_ip_ailover_script: 更新Application使用的masterip
  • shutdown_script: 强制关闭master节点
  • report_script: 发送报告
  • init_conf_load_script: 加载初始配置参数
  • master_ip_online_change_script:更新master节点ip地址

MHA配置文件:

  • global配置,为各application提供默认配置,默认文件路径 /etc/masterha_default.cnf
  • application配置:为每个主从复制集群
6.3.2.2 实现MHA实战案例
  1. 在管理节点上安装两个包(不支持CentOS8,可能用CentOS7 以下版本),

    mha4mysql-manager   
    mha4mysql-node
    
  2. 在被管理节点安装(支持CentOS 8,7,6)

    mha4mysql-node
    
  3. 在管理节点建立配置文件

    mkdir /etc/mastermha/
    vim /etc/mastermha/app1.cnf 
    [server default]
    user=mhauser
    password=magedu
    manager_workdir=/data/mastermha/app1/
    manager_log=/data/mastermha/app1/manager.log
    remote_workdir=/data/mastermha/app1/
    ssh_user=root
    repl_user=repluser
    repl_password=magedu
    ping_interval=1
    [server1]
    hostname=192.168.8.17
    candidate_master=1
    [server2]
    hostname=192.168.8.27
    candidate_master=1
    [server3]
    hostname=192.168.8.37
    
  4. 实现Master

    vim /etc/my.cnf
    [mysqld]
    log-bin
    server_id=1
    skip_name_resolve=1
    mysql>show master logs
    mysql>grant replication slave on *.* to repluser@'192.168.8.%' identified by 'magedu';
    mysql>grant all on *.* to mhauser@'192.168.8.%' identified by 'magedu';
    
  5. 实现slave

    vim /etc/my.cnf
    [mysqld]
    server_id=2     #不同节点此值各不相同
    log-bin
    read_only
    relay_log_purge=0
    skip_name_resolve=1
    
    mysql>CHANGE MASTER TO MASTER_HOST=‘MASTER_IP', MASTER_USER='repluser', MASTER_PASSWORD=‘magedu', MASTER_LOG_FILE='mariadb-bin.000001', MASTER_LOG_POS=245;
    
  6. 在所有节点实现相互之间ssh key验证

过程略

  1. Mha验证和启动

    masterha_check_ssh --conf=/etc/mastermha/app1.cnf
    masterha_check_repl --conf=/etc/mastermha/app1.cnf
    masterha_manager --conf=/etc/mastermha/app1.cnf
    
  2. 排错日志:

    /data/mastermha/app1/manager.log
    
6.3.3 Galera Cluster
6.3.3.1 Galera Cluster介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6WWPR6n8-1614077832815)(http://www.yunweipai.com/wp-content/uploads/2020/05/image-20191031160248186.png)]

Galera Cluster:集成了Galera插件的MySQL集群,是一种新型的,数据不共享的,高度冗余的高可用方案,目前Galera Cluster有两个版本,分别是Percona Xtradb Cluster及MariaDB Cluster,Galera本身是具有多主特性的,即采用multi-master的集群架构,是一个既稳健,又在数据一致性、完整性及高性能方面有出色表现的高可用解决方案 Galera Cluster特点

  • 多主架构:真正的多点读写的集群,在任何时候读写数据,都是最新的
  • 同步复制:集群不同节点之间数据同步,没有延迟,在数据库挂掉之后,数据不会丢失
  • 并发复制:从节点APPLY数据时,支持并行执行,更好的性能
  • 故障切换:在出现数据库故障时,因支持多点写入,切换容易
  • 热插拔:在服务期间,如果数据库挂了,只要监控程序发现的够快,不可服务时间就会非常少。在节点故障期间,节点本身对集群的影响非常小
  • 自动节点克隆:在新增节点,或者停机维护时,增量数据或者基础数据不需要人工手动备份提供,Galera Cluster会自动拉取在线节点数据,最终集群会变为一致
  • 对应用透明:集群的维护,对应用程序是透明的

Galera Cluster 缺点

  • 由于DDL 需全局验证通过,则集群性能由集群中最差性能节点决定(一般集群节点配置都是一样的)
  • 新节点加入或延后较大的节点重新加入需全量拷贝数据(SST,State Snapshot Transfer),作为donor( 贡献者,如: 同步数据时的提供者)的节点在同步过程中无法提供读写
  • 只支持innodb存储引擎的表

Galera Cluster工作过程

MySQL——高可用+中间件代理_第3张图片

  1. Galera Cluster官方文档: http://galeracluster.com/documentation-webpages/galera-documentation.pdf http://galeracluster.com/documentation-webpages/index.html https://www.percona.com/doc/percona-xtradb-cluster/LATEST/index.html https://mariadb.com/kb/en/library/getting-started-with-mariadb-galera-cluster/

Galera Cluster包括两个组件 Galera replication library (galera-3) WSREP:MySQL extended with the Write Set Replication

WSREP复制实现:

  • PXC:Percona XtraDB Cluster,是Percona对Galera的实现

参考仓库:

https://mirrors.tuna.tsinghua.edu.cn/percona/release/releasever/RPMS/releasever/RPMS/basearch
  • MariaDB Galera Cluster: 参考仓库:https://mirrors.tuna.tsinghua.edu.cn/mariadb/mariadb-5.5.X/yum/centos7-amd64/

注意:两者都需要至少三个节点,不能安装mysql server 或 mariadb-server

6.3.3.2 PXC 原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZxZPP77j-1614077832823)(http://www.yunweipai.com/wp-content/uploads/2020/05/image-20191130142436829.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O7BcOiv3-1614077832833)(http://www.yunweipai.com/wp-content/uploads/2020/05/image-20191130142641739.png)]

PXC最常使用如下4个端口号:

  • 3306:数据库对外服务的端口号
  • 4444:请求SST的端口号
  • 4567:组成员之间进行沟通的端口号
  • 4568:用于传输IST的端口号

PXC中涉及到的重要概念和核心参数:

(1)集群中节点的数量:整个集群中节点数量应该控制在最少3个、最多8个的范围内。最少3个节点是为了防止出现脑裂现象,因为只有在2个节点下才会出现此现象。脑裂现象的标志就是输入任何命令,返回的结果都是unknown command。节点在集群中,会因新节点的加入或故障、同步失效等原因发生状态的切换。

(2)节点状态的变化阶段:

MySQL——高可用+中间件代理_第4张图片

  • open:节点启动成功,尝试连接到集群时的状态
  • primary:节点已处于集群中,在新节点加入并选取donor进行数据同步时的状态
  • joiner:节点处于等待接收同步文件时的状态
  • joined:节点完成数据同步工作,尝试保持和集群进度一致时的状态
  • synced:节点正常提供服务时的状态,表示已经同步完成并和集群进度保持一致
  • donor:节点处于为新加入的节点提供全量数据时的状态

备注:donor节点就是数据的贡献者,如果一个新节点加入集群,此时又需要大量数据的SST数据传输,就有可能因此而拖垮整个集群的性能,所以在生产环境中,如果数据量较小,还可以使用SST全量数据传输,但如果数据量很大就不建议使用这种方式,可以考虑先建立主从关系,然后再加入集群。

(3)节点的数据传输方式:

  • SST:State Snapshot Transfer,全量数据传输
  • IST:Incremental State Transfer,增量数据传输

SST数据传输有xtrabackup、mysqldump和rsync三种方式,而增量数据传输就只有一种方式xtrabackup,但生产环境中一般数据量较小时,可以使用SST全量数据传输,但也只使用xtrabackup方法。

(4)GCache模块:在PXC中一个特别重要的模块,它的核心功能就是为每个节点缓存当前最新的写集。如果有新节点加入进来,就可以把新数据的增量传递给新节点,而不需要再使用SST传输方式,这样可以让节点更快地加入集群中,涉及如下参数:

  • gcache.size:缓存写集增量信息的大小,它的默认大小是128MB,通过wsrep_provider_options参数设置,建议调整为2GB~4GB范围,足够的空间便于缓存更多的增量信息。
  • gcache.mem_size:GCache中内存缓存的大小,适度调大可以提高整个集群的性能
  • gcache.page_size:如果内存不够用(GCache不足),就直接将写集写入磁盘文件中
6.3.3.3 实战案例:Percona XtraDB Cluster(PXC 5.7)

1 环境准备

四台主机:

pxc1:10.0.0.7
pxc1:10.0.0.17
pxc1:10.0.0.27
pxc4:10.0.0.37

OS 版本目前不支持CentOS 8

[root@pxc1 ~]#cat /etc/redhat-release 
CentOS Linux release 7.6.1810 (Core)

关闭防火墙和SELinux,保证时间同步

注意:如果已经安装MySQL,必须卸载

2 安装 Percona XtraDB Cluster 5.7

#此处使用清华大学yum源,官方源太慢了
[root@pxc1 ~]#vim /etc/yum.repos.d/pxc.repo
[percona]
name=percona_repo
baseurl = https://mirrors.tuna.tsinghua.edu.cn/percona/release/releasever/RPMS/releasever/RPMS/basearch
enabled = 1
gpgcheck = 0

[root@pxc1 ~]#scp /etc/yum.repos.d/pxc.repo  10.0.0.17:/etc/yum.repos.d
[root@pxc1 ~]#scp /etc/yum.repos.d/pxc.repo  10.0.0.27:/etc/yum.repos.d

#在三个节点都安装好PXC 5.7 
[root@pxc1 ~]#yum install Percona-XtraDB-Cluster-57 -y
[root@pxc2 ~]#yum install Percona-XtraDB-Cluster-57 -y
[root@pxc3 ~]#yum install Percona-XtraDB-Cluster-57 -y

3 在各个节点上分别配置mysql及集群配置文件

/etc/my.cnf为主配置文件,当前版本中,其余的配置文件都放在/etc/percona-xtradb-cluster.conf.d目录里,包括mysqld.cnf,mysqld_safe.cnf,wsrep.cnf 三个文件

#主配置文件不需要修改
[root@pxc1 ~]#cat /etc/my.cnf
# The Percona XtraDB Cluster 5.7 configuration file.
...省略...
!includedir /etc/my.cnf.d/
!includedir /etc/percona-xtradb-cluster.conf.d/

[root@pxc1 ~]#ls /etc/my.cnf.d/
[root@pxc1 ~]#ls /etc/percona-xtradb-cluster.conf.d/
mysqld.cnf  mysqld_safe.cnf  wsrep.cnf

#下面配置文件不需要修改
[root@pxc1 ~]#cat /etc/percona-xtradb-cluster.conf.d/mysqld.cnf 
...省略...
[client]
socket=/var/lib/mysql/mysql.sock

[mysqld]
server-id=1     #建议各个节点不同
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
log-bin     #建议启用,非必须项
log_slave_updates
expire_logs_days=7

# Disabling symbolic-links is recommended to prevent assorted security risks

symbolic-links=0

#下面配置文件不需要修改
[root@pxc1 ~]#cat /etc/percona-xtradb-cluster.conf.d/mysqld_safe.cnf 
...省略...
[mysqld_safe]
pid-file = /var/run/mysqld/mysqld.pid
socket   = /var/lib/mysql/mysql.sock
nice     = 0

#PXC的配置文件必须修改
[root@pxc1 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf 
[root@pxc1 ~]#grep -Ev "^#|^ParseError: KaTeX parse error: Expected 'EOF', got '#' at position 170: ….17,10.0.0.27  #̲三个节点的IP
binlog_…"  /etc/percona-xtradb-cluster.conf.d/wsrep.cnf 
[mysqld]
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27
binlog_format=ROW
default_storage_engine=InnoDB
wsrep_slave_threads= 8
wsrep_log_conflicts
innodb_autoinc_lock_mode=2          #各个节点,指定自已的IP
wsrep_node_address=10.0.0.17
wsrep_cluster_name=pxc-cluster
wsrep_node_name=pxc-cluster-node-2    #各个节点,指定自已节点名称
pxc_strict_mode=ENFORCING
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth="sstuser:s3cretPass"   #取消本行注释

[root@pxc3 ~]#grep -Ev "^#|^$"  /etc/percona-xtradb-cluster.conf.d/wsrep.cnf 
[mysqld]
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27
binlog_format=ROW
default_storage_engine=InnoDB
wsrep_slave_threads= 8
wsrep_log_conflicts
innodb_autoinc_lock_mode=2   
wsrep_node_address=10.0.0.27         #各个节点,指定自已的IP
wsrep_cluster_name=pxc-cluster
wsrep_node_name=pxc-cluster-node-3    #各个节点,指定自已的IP
pxc_strict_mode=ENFORCING
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth="sstuser:s3cretPass"   #取消本行注释

注意:尽管Galera Cluster不再需要通过binlog的形式进行同步,但还是建议在配置文件中开启二进制日志功能,原因是后期如果有新节点需要加入,老节点通过SST全量传输的方式向新节点传输数据,很可能会拖垮集群性能,所以让新节点先通过binlog方式完成同步后再加入集群会是一种更好的选择

配置文件各项配置意义

配置 说明
wsrep_provider 指定Galera库的路径
wsrep_cluster_name Galera集群的名称
wsrep_cluster_address Galera集群中各节点地址。地址使用组通信协议gcomm://(group communication)
wsrep_node_name 本节点在Galera集群中的名称
wsrep_node_address 本节点在Galera集群中的通信地址
wsrep_sst_method state_snapshot_transfer(SST)使用的传输方法,可用方法有mysqldump、rsync和xtrabackup,前两者在传输时都需要对Donor加全局只读锁(FLUSH TABLES WITH READ LOCK),xtrabackup则不需要(它使用percona自己提供的backup lock)。强烈建议采用xtrabackup
wsrep_sst_auth 在SST传输时需要用到的认证凭据,格式为:”用户:密码”
pxc_strict_mode 是否限制PXC启用正在试用阶段的功能,ENFORCING是默认值,表示不启用
binlog_format 二进制日志的格式。Galera只支持row格式的二进制日志
default_storage_engine 指定默认存储引擎。Galera的复制功能只支持InnoDB
innodb_autoinc_lock_mode 只能设置为2,设置为0或1时会无法正确处理死锁问题

4 启动PXC集群中第一个节点

root@pxc1 ~]#ss -ntul
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port 
udp UNCONN 0 0 127.0.0.1:323 *:* 
udp UNCONN 0 0 ::1:323 :::* 
tcp LISTEN 0 128 *:22 *:* 
tcp LISTEN 0 100 127.0.0.1:25 *:* 
tcp LISTEN 0 128 :::22 :::* 
tcp LISTEN 0 100 ::1:25 :::*

#启动第一个节点
[root@pxc1 ~]#systemctl start [email protected]
[root@pxc1 ~]#ss -ntul
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port 
udp UNCONN 0 0 127.0.0.1:323 *:* 
udp UNCONN 0 0 ::1:323 :::* 
tcp LISTEN 0 128 *:22 *:* 
tcp LISTEN 0 128 *:4567 *:* 
tcp LISTEN 0 100 127.0.0.1:25 *:* 
tcp LISTEN 0 80 :::3306 :::* 
tcp LISTEN 0 128 :::22 :::* 
tcp LISTEN 0 100 ::1:25 :::*

#查看root密码
[root@pxc1 ~]#grep "temporary password" /var/log/mysqld.log
2019-11-30T02:53:54.292659Z 1 [Note] A temporary password is generated for root@localhost: =tWFP0oRJl8t

[root@pxc1 ~]#mysql -uroot -p'=tWFP0oRJl8t'
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.7.27-30-57-log

Copyright (c) 2009-2019 Percona LLC and/or its affiliates
Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

#修改root密码
mysql> alter user 'root'@'localhost' identified by 'magedu';
Query OK, 0 rows affected (0.01 sec)
mysql> CREATE USER 'sstuser'@'localhost' IDENTIFIED BY 's3cretPass';
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'sstuser'@'localhost';
Query OK, 0 rows affected (0.01 sec)

#查看相关变量
mysql> SHOW VARIABLES LIKE 'wsrep%'\G
*************************** 1. row ***************************
Variable_name: wsrep_OSU_method
Value: TOI
*************************** 2. row ***************************
Variable_name: wsrep_RSU_commit_timeout
Value: 5000
*************************** 3. row ***************************
Variable_name: wsrep_auto_increment_control
Value: ON
*************************** 4. row ***************************
Variable_name: wsrep_causal_reads
Value: OFF
*************************** 5. row ***************************
Variable_name: wsrep_certification_rules
Value: strict
*************************** 6. row ***************************
Variable_name: wsrep_certify_nonPK
Value: ON
*************************** 7. row ***************************
Variable_name: wsrep_cluster_address
Value: gcomm://10.0.0.7,10.0.0.17,10.0.0.27
*************************** 8. row ***************************
Variable_name: wsrep_cluster_name
Value: pxc-cluster
*************************** 9. row ***************************
Variable_name: wsrep_convert_LOCK_to_trx
Value: OFF
*************************** 10. row ***************************
Variable_name: wsrep_data_home_dir
Value: /var/lib/mysql/
*************************** 11. row ***************************
Variable_name: wsrep_dbug_option
Value: 
*************************** 12. row ***************************
Variable_name: wsrep_debug
Value: OFF
*************************** 13. row ***************************
Variable_name: wsrep_desync
Value: OFF
*************************** 14. row ***************************
Variable_name: wsrep_dirty_reads
Value: OFF
*************************** 15. row ***************************
Variable_name: wsrep_drupal_282555_workaround
Value: OFF
*************************** 16. row ***************************
Variable_name: wsrep_forced_binlog_format
Value: NONE
*************************** 17. row ***************************
Variable_name: wsrep_load_data_splitting
Value: ON
*************************** 18. row ***************************
Variable_name: wsrep_log_conflicts
Value: ON
*************************** 19. row ***************************
Variable_name: wsrep_max_ws_rows
Value: 0
*************************** 20. row ***************************
Variable_name: wsrep_max_ws_size
Value: 2147483647
*************************** 21. row ***************************
Variable_name: wsrep_node_address
Value: 10.0.0.7
*************************** 22. row ***************************
Variable_name: wsrep_node_incoming_address
Value: AUTO
*************************** 23. row ***************************
Variable_name: wsrep_node_name
Value: pxc-cluster-node-1
*************************** 24. row ***************************
Variable_name: wsrep_notify_cmd
Value: 
*************************** 25. row ***************************
Variable_name: wsrep_on
Value: ON
*************************** 26. row ***************************
Variable_name: wsrep_preordered
Value: OFF
*************************** 27. row ***************************
Variable_name: wsrep_provider
Value: /usr/lib64/galera3/libgalera_smm.so
*************************** 28. row ***************************
Variable_name: wsrep_provider_options
Value: base_dir = /var/lib/mysql/; base_host = 10.0.0.7; base_port = 4567; cert.log_conflicts = no; cert.optimistic_pa = yes; debug = no; evs.auto_evict = 0; evs.causal_keepalive_period = PT1S; evs.debug_log_mask = 0x1; evs.delay_margin = PT1S; evs.delayed_keep_period = PT30S; evs.inactive_check_period = PT0.5S; evs.inactive_timeout = PT15S; evs.info_log_mask = 0; evs.install_timeout = PT7.5S; evs.join_retrans_period = PT1S; evs.keepalive_period = PT1S; evs.max_install_timeouts = 3; evs.send_window = 10; evs.stats_report_period = PT1M; evs.suspect_timeout = PT5S; evs.use_aggregate = true; evs.user_send_window = 4; evs.version = 0; evs.view_forget_timeout = P1D; gcache.dir = /var/lib/mysql/; gcache.freeze_purge_at_seqno = -1; gcache.keep_pages_count = 0; gcache.keep_pages_size = 0; gcache.mem_size = 0; gcache.name = /var/lib/mysql//galera.cache; gcache.page_size = 128M; gcache.recover = no; gcache.size = 128M; gcomm.thread_prio = ; gcs.fc_debug = 0; gcs.fc_factor = 1; gcs.fc_limit = 100; gcs.fc_master_slave = no; gcs
*************************** 29. row ***************************
Variable_name: wsrep_recover
Value: OFF
*************************** 30. row ***************************
Variable_name: wsrep_reject_queries
Value: NONE
*************************** 31. row ***************************
Variable_name: wsrep_replicate_myisam
Value: OFF
*************************** 32. row ***************************
Variable_name: wsrep_restart_slave
Value: OFF
*************************** 33. row ***************************
Variable_name: wsrep_retry_autocommit
Value: 1
*************************** 34. row ***************************
Variable_name: wsrep_slave_FK_checks
Value: ON
*************************** 35. row ***************************
Variable_name: wsrep_slave_UK_checks
Value: OFF
*************************** 36. row ***************************
Variable_name: wsrep_slave_threads
Value: 8
*************************** 37. row ***************************
Variable_name: wsrep_sst_auth
Value: ********
*************************** 38. row ***************************
Variable_name: wsrep_sst_donor
Value: 
*************************** 39. row ***************************
Variable_name: wsrep_sst_donor_rejects_queries
Value: OFF
*************************** 40. row ***************************
Variable_name: wsrep_sst_method
Value: xtrabackup-v2
*************************** 41. row ***************************
Variable_name: wsrep_sst_receive_address
Value: AUTO
*************************** 42. row ***************************
Variable_name: wsrep_start_position
Value: 00000000-0000-0000-0000-000000000000:-1
*************************** 43. row ***************************
Variable_name: wsrep_sync_wait
Value: 0
43 rows in set (0.01 sec)

#查看相关状态变量
mysql> SHOW STATUS LIKE 'wsrep%'\G
*************************** 1. row ***************************
Variable_name: wsrep_local_state_uuid
Value: aad2c02e-131c-11ea-9294-b2e80a6c08c4
*************************** 2. row ***************************
Variable_name: wsrep_protocol_version
Value: 9
*************************** 3. row ***************************
Variable_name: wsrep_last_applied
Value: 3
*************************** 4. row ***************************
Variable_name: wsrep_last_committed
Value: 3
*************************** 5. row ***************************
Variable_name: wsrep_replicated
Value: 3
*************************** 6. row ***************************
Variable_name: wsrep_replicated_bytes
Value: 760
*************************** 7. row ***************************
Variable_name: wsrep_repl_keys
Value: 3
*************************** 8. row ***************************
Variable_name: wsrep_repl_keys_bytes
Value: 96
*************************** 9. row ***************************
Variable_name: wsrep_repl_data_bytes
Value: 465
*************************** 10. row ***************************
Variable_name: wsrep_repl_other_bytes
Value: 0
*************************** 11. row ***************************
Variable_name: wsrep_received
Value: 2
*************************** 12. row ***************************
Variable_name: wsrep_received_bytes
Value: 150
*************************** 13. row ***************************
Variable_name: wsrep_local_commits
Value: 0
*************************** 14. row ***************************
Variable_name: wsrep_local_cert_failures
Value: 0
*************************** 15. row ***************************
Variable_name: wsrep_local_replays
Value: 0
*************************** 16. row ***************************
Variable_name: wsrep_local_send_queue
Value: 0
*************************** 17. row ***************************
Variable_name: wsrep_local_send_queue_max
Value: 1
*************************** 18. row ***************************
Variable_name: wsrep_local_send_queue_min
Value: 0
*************************** 19. row ***************************
Variable_name: wsrep_local_send_queue_avg
Value: 0.000000
*************************** 20. row ***************************
Variable_name: wsrep_local_recv_queue
Value: 0
*************************** 21. row ***************************
Variable_name: wsrep_local_recv_queue_max
Value: 2
*************************** 22. row ***************************
Variable_name: wsrep_local_recv_queue_min
Value: 0
*************************** 23. row ***************************
Variable_name: wsrep_local_recv_queue_avg
Value: 0.500000
*************************** 24. row ***************************
Variable_name: wsrep_local_cached_downto
Value: 1
*************************** 25. row ***************************
Variable_name: wsrep_flow_control_paused_ns
Value: 0
*************************** 26. row ***************************
Variable_name: wsrep_flow_control_paused
Value: 0.000000
*************************** 27. row ***************************
Variable_name: wsrep_flow_control_sent
Value: 0
*************************** 28. row ***************************
Variable_name: wsrep_flow_control_recv
Value: 0
*************************** 29. row ***************************
Variable_name: wsrep_flow_control_interval
Value: [ 100, 100 ]
*************************** 30. row ***************************
Variable_name: wsrep_flow_control_interval_low
Value: 100
*************************** 31. row ***************************
Variable_name: wsrep_flow_control_interval_high
Value: 100
*************************** 32. row ***************************
Variable_name: wsrep_flow_control_status
Value: OFF
*************************** 33. row ***************************
Variable_name: wsrep_cert_deps_distance
Value: 1.000000
*************************** 34. row ***************************
Variable_name: wsrep_apply_oooe
Value: 0.000000
*************************** 35. row ***************************
Variable_name: wsrep_apply_oool
Value: 0.000000
*************************** 36. row ***************************
Variable_name: wsrep_apply_window
Value: 1.000000
*************************** 37. row ***************************
Variable_name: wsrep_commit_oooe
Value: 0.000000
*************************** 38. row ***************************
Variable_name: wsrep_commit_oool
Value: 0.000000
*************************** 39. row ***************************
Variable_name: wsrep_commit_window
Value: 1.000000
*************************** 40. row ***************************
Variable_name: wsrep_local_state
Value: 4
*************************** 41. row ***************************
Variable_name: wsrep_local_state_comment
Value: Synced
*************************** 42. row ***************************
Variable_name: wsrep_cert_index_size
Value: 1
*************************** 43. row ***************************
Variable_name: wsrep_cert_bucket_count
Value: 22
*************************** 44. row ***************************
Variable_name: wsrep_gcache_pool_size
Value: 2200
*************************** 45. row ***************************
Variable_name: wsrep_causal_reads
Value: 0
*************************** 46. row ***************************
Variable_name: wsrep_cert_interval
Value: 0.000000
*************************** 47. row ***************************
Variable_name: wsrep_open_transactions
Value: 0
*************************** 48. row ***************************
Variable_name: wsrep_open_connections
Value: 0
*************************** 49. row ***************************
Variable_name: wsrep_ist_receive_status
Value: 
*************************** 50. row ***************************
Variable_name: wsrep_ist_receive_seqno_start
Value: 0
*************************** 51. row ***************************
Variable_name: wsrep_ist_receive_seqno_current
Value: 0
*************************** 52. row ***************************
Variable_name: wsrep_ist_receive_seqno_end
Value: 0
*************************** 53. row ***************************
Variable_name: wsrep_incoming_addresses
Value: 10.0.0.7:3306
*************************** 54. row ***************************
Variable_name: wsrep_cluster_weight
Value: 1
*************************** 55. row ***************************
Variable_name: wsrep_desync_count
Value: 0
*************************** 56. row ***************************
Variable_name: wsrep_evs_delayed
Value: 
*************************** 57. row ***************************
Variable_name: wsrep_evs_evict_list
Value: 
*************************** 58. row ***************************
Variable_name: wsrep_evs_repl_latency
Value: 0/0/0/0/0
*************************** 59. row ***************************
Variable_name: wsrep_evs_state
Value: OPERATIONAL
*************************** 60. row ***************************
Variable_name: wsrep_gcomm_uuid
Value: aad1f935-131c-11ea-910a-ce3ee95c675e
*************************** 61. row ***************************
Variable_name: wsrep_cluster_conf_id
Value: 1
*************************** 62. row ***************************
Variable_name: wsrep_cluster_size
Value: 1
*************************** 63. row ***************************
Variable_name: wsrep_cluster_state_uuid
Value: aad2c02e-131c-11ea-9294-b2e80a6c08c4
*************************** 64. row ***************************
Variable_name: wsrep_cluster_status
Value: Primary
*************************** 65. row ***************************
Variable_name: wsrep_connected
Value: ON
*************************** 66. row ***************************
Variable_name: wsrep_local_bf_aborts
Value: 0
*************************** 67. row ***************************
Variable_name: wsrep_local_index
Value: 0
*************************** 68. row ***************************
Variable_name: wsrep_provider_name
Value: Galera
*************************** 69. row ***************************
Variable_name: wsrep_provider_vendor
Value: Codership Oy 
*************************** 70. row ***************************
Variable_name: wsrep_provider_version
Value: 3.39(rb3295e6)
*************************** 71. row ***************************
Variable_name: wsrep_ready
Value: ON
71 rows in set (0.00 sec)

#重点关注下面内容
mysql> show status like 'wsrep%';
+----------------------------+--------------------------------------+
| Variable_name | Value |
+----------------------------+--------------------------------------+
| wsrep_local_state_uuid | aad2c02e-131c-11ea-9294-b2e80a6c08c4 |
| ... | ... |
| wsrep_local_state | 4 |
| wsrep_local_state_comment | Synced |
| ... | ... |
| wsrep_cluster_size | 1 |
| wsrep_cluster_status | Primary |
| wsrep_connected | ON |
| ... | ... |
| wsrep_ready | ON |
+----------------------------+--------------------------------------+

说明:

wsrep_cluster_size表示,该Galera集群中只有一个节点

wsrep_local_state_comment 状态为Synced(4),表示数据已同步完成(因为是第一个引导节点,无数据需要同步)。 如果状态是Joiner, 意味着 SST 没有完成. 只有所有节点状态是Synced,才可以加新节点

wsrep_cluster_status为Primary,且已经完全连接并准备好

5 启动PXC集群中其它所有节点

[root@pxc2 ~]#ss -ntul
Netid State      Recv-Q Send-Q     Local Address:Port                    Peer Address:Port              
udp   UNCONN     0      0              127.0.0.1:323                                *:*                  
udp   UNCONN     0      0                    ::1:323                               :::*                  
tcp   LISTEN     0      128                    *:22                                 *:*                  
tcp   LISTEN     0      100            127.0.0.1:25                                 *:*                  
tcp   LISTEN     0      128                   :::22                                :::*                  
tcp   LISTEN     0      100                  ::1:25                                :::*                  

[root@pxc2 ~]#systemctl start mysql
[root@pxc2 ~]#ss -ntulp
Netid State      Recv-Q Send-Q     Local Address:Port                    Peer Address:Port              
udp   UNCONN     0      0              127.0.0.1:323                                *:*                   users:(("chronyd",pid=6289,fd=1))
udp   UNCONN     0      0                    ::1:323                               :::*                   users:(("chronyd",pid=6289,fd=2))
tcp   LISTEN     0      128                    *:22                                 *:*                   users:(("sshd",pid=6617,fd=3))
tcp   LISTEN     0      128                    *:4567                               *:*                   users:(("mysqld",pid=7754,fd=11))
tcp   LISTEN     0      100            127.0.0.1:25                                 *:*                   users:(("master",pid=6752,fd=13))
tcp   LISTEN     0      80                    :::3306                              :::*                   users:(("mysqld",pid=7754,fd=34))
tcp   LISTEN     0      128                   :::22                                :::*                   users:(("sshd",pid=6617,fd=4))
tcp   LISTEN     0      100                  ::1:25                                :::*                   users:(("master",pid=6752,fd=14))

[root@pxc3 ~]#systemctl start mysql

6 查看集群状态,验证集群是否成功

#在任意节点,查看集群状态
[root@pxc1 ~]#mysql -uroot -pmagedu
mysql> SHOW VARIABLES LIKE 'wsrep_node_name';
+-----------------+--------------------+
| Variable_name   | Value              |
+-----------------+--------------------+
| wsrep_node_name | pxc-cluster-node-1 |
+-----------------+--------------------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'wsrep_node_address';
+--------------------+----------+
| Variable_name      | Value    |
+--------------------+----------+
| wsrep_node_address | 10.0.0.7 |
+--------------------+----------+
1 row in set (0.01 sec)

mysql> SHOW VARIABLES LIKE 'wsrep_on';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_on      | ON    |
+---------------+-------+
1 row in set (0.00 sec)

mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 3     |
+--------------------+-------+
1 row in set (0.01 sec)

#在任意节点查看数据库
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

#在任意节点创建数据库
mysql> create database testdb1;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb1            |
+--------------------+
5 rows in set (0.00 sec)

mysql> 

#在任意其它节点验证数据是否同步
[root@pxc2 ~]#mysql -uroot -pmagedu
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb1            |
+--------------------+
5 rows in set (0.01 sec)

#利用Xshell软件,同时在三个节点数据库,在其中一个节点成功
mysql> create database testdb2;
Query OK, 1 row affected (0.01 sec)

#在其它节点都提示失败
mysql> create database testdb2;
ERROR 1007 (HY000): Can't create database 'testdb2'; database exists

7 在PXC集群中加入节点

一个节点加入到Galera集群有两种情况:新节点加入集群、暂时离组的成员再次加入集群 1)新节点加入Galera集群 新节点加入集群时,需要从当前集群中选择一个Donor节点来同步数据,也就是所谓的state_snapshot_tranfer(SST)过程。SST同步数据的方式由选项wsrep_sst_method决定,一般选择的是xtrabackup。 必须注意,新节点加入Galera时,会删除新节点上所有已有数据,再通过xtrabackup(假设使用的是该方式)从Donor处完整备份所有数据进行恢复。所以,如果数据量很大,新节点加入过程会很慢。而且,在一个新节点成为Synced状态之前,不要同时加入其它新节点,否则很容易将集群压垮。 如果是这种情况,可以考虑使用wsrep_sst_method=rsync来做增量同步,既然是增量同步,最好保证新节点上已经有一部分数据基础,否则和全量同步没什么区别,且这样会对Donor节点加上全局read only锁。 2)旧节点加入Galera集群 如果旧节点加入Galera集群,说明这个节点在之前已经在Galera集群中呆过,有一部分数据基础,缺少的只是它离开集群时的数据。这时加入集群时,会采用IST(incremental snapshot transfer)传输机制,即使用增量传输。 但注意,这部分增量传输的数据源是Donor上缓存在GCache文件中的,这个文件有大小限制,如果缺失的数据范围超过已缓存的内容,则自动转为SST传输。如果旧节点上的数据和Donor上的数据不匹配(例如这个节点离组后人为修改了一点数据),则自动转为SST传输。

#在PXC集群中再加一台新的主机PXC4:10.0.0.37
[root@pxc4 ~]#yum install Percona-XtraDB-Cluster-57 -y
[root@pxc4 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[root@pxc4 ~]#grep -Ev "^#|^$"  /etc/percona-xtradb-cluster.conf.d/wsrep.cnf 
[mysqld]
wsrep_provider=/usr/lib64/galera3/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27,10.0.0.37
binlog_format=ROW
default_storage_engine=InnoDB
wsrep_slave_threads= 8
wsrep_log_conflicts
innodb_autoinc_lock_mode=2
wsrep_node_address=10.0.0.37
wsrep_cluster_name=pxc-cluster
wsrep_node_name=pxc-cluster-node-4
pxc_strict_mode=ENFORCING
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth="sstuser:s3cretPass"

[root@pxc4 ~]#systemctl start mysql
[root@pxc4 ~]#mysql -uroot -pmagedu
Server version: 5.7.27-30-57-log Percona XtraDB Cluster (GPL), Release rel30, Revision 
mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 4     |
+--------------------+-------+
1 row in set (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb1            |
| testdb2            |
| testdb3            |
+--------------------+
8 rows in set (0.00 sec)

#将其它节点的配置文件加以修改
[root@pxc1 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
wsrep_cluster_address=gcomm://10.0.0.7,10.0.0.17,10.0.0.27,10.0.0.37
[root@pxc2 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf
[root@pxc3 ~]#vim /etc/percona-xtradb-cluster.conf.d/wsrep.cnf

8 在PXC集群中修复故障节点

#在任意节点停止服务
[root@pxc4 ~]#systemctl stop mysql

#在其它任意节点查看wsrep_cluster_size变量少了一个节点
[root@pxc1 ~]#mysql -uroot -pmagedu
Server version: 5.7.27-30-57-log Percona XtraDB Cluster (GPL), Release rel30, Revision 
mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 3     |
+--------------------+-------+
1 row in set (0.01 sec)

mysql> create database testdb4;

#在其它任意节点可看到数据已同步
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb1            |
| testdb2            |
| testdb3            |
| testdb4            |
+--------------------+
10 rows in set (0.00 sec)

#恢复服务,数据同步
[root@pxc4 ~]#systemctl start mysql
[root@pxc4 ~]#mysql -uroot -pmagedu
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| testdb1            |
| testdb2            |
| testdb3            |
| testdb4            |
+--------------------+
10 rows in set (0.00 sec)
mysql> SHOW STATUS LIKE 'wsrep_cluster_size';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| wsrep_cluster_size | 4     |
+--------------------+-------+
1 row in set (0.01 sec)
6.3.3.4 实战案例:MariaDB Galera Cluster

范例:在centos8 实现MariaDB Galera Cluster

#在三个节点上都实现
[root@centos8 ~]#dnf install mariadb-server-galera -y
[root@centos8 ~]#vim /etc/my.cnf.d/galera.cnf
#wsrep_cluster_address="dummy://"
wsrep_cluster_address="gcomm://10.0.0.8,10.0.0.18,10.0.0.28"

#启动第一节点
[root@centos8 ~]#galera_new_cluster

#再启动其它节点
[root@centos8 ~]#systemctl start mariadb
[root@centos8 ~]#ss -ntul
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port 
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:* 
tcp LISTEN 0 128 0.0.0.0:4567 0.0.0.0:* 
tcp LISTEN 0 80 0.0.0.0:3306 0.0.0.0:* 
tcp LISTEN 0 128 [::]:22 [::]:*

[root@centos8 ~]#mysql 
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.3.11-MariaDB MariaDB Server

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> 
MariaDB [(none)]> show status like "wsrep_ready";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_ready | ON |
+---------------+-------+
1 row in set (0.001 sec)

MariaDB [(none)]> SHOW STATUS LIKE 'wsrep_cluster_size'; 
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 3 |
+--------------------+-------+
1 row in set (0.001 sec)
MariaDB [(none)]> SHOW VARIABLES LIKE 'wsrep_%'\G
MariaDB [(none)]> SHOW STATUS LIKE 'wsrep_%';
6.3.4 TiDB概述

TiDB 是 PingCAP 公司受 Google Spanner / F1 论文启发而设计的开源分布式 HTAP (Hybrid Transactional and Analytical Processing) 数据库,结合了传统的 RDBMS 和NoSQL 的最佳特性。TiDB 兼容 MySQL,支持无限的水平扩展,具备强一致性和高可用性。TiDB和mysql几乎完全兼容 TiDB 是一个分布式 NewSQL 数据库。它支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议,具有数据强一致的高可用特性,是一个不仅适合 OLTP 场景还适合 OLAP 场景的混合数据库。 TiDB 的目标是为 OLTP(Online Transactional Processing) 和 OLAP (Online Analytical Processing) 场景提供一站式的解决方案。

6.3.4.1 TiDB 核心特点
  1. 高度兼容 MySQL  大多数情况下,无需修改代码即可从 MySQL 轻松迁移至 TiDB,分库分表后的 MySQL 集群亦可通过 TiDB 工具进行实时迁移
  2. 水平弹性扩展  通过简单地增加新节点即可实现 TiDB 的水平扩展,按需扩展吞吐或存储,轻松应对高并发、海量数据场景
  3. 分布式事务  TiDB 100% 支持标准的 ACID 事务
  4. 真正金融级高可用  相比于传统主从 (M-S) 复制方案,基于 Raft 的多数派选举协议可以提供金融级的 100% 数据强一致性保证,且在不丢失大多数副本的前提下,可实现故障的自动恢复 (auto-failover),无需人工介入
  5. 一站式 HTAP 解决方案  TiDB 作为典型的 OLTP 行存数据库,同时兼具强大的 OLAP 性能,配合 TiSpark,可提供一站式 HTAP解决方案,一份存储同时处理OLTP & OLAP(OLAP、OLTP的介绍和比较 )无需传统繁琐的 ETL 过程
  6. 云原生 SQL 数据库  TiDB 是为云而设计的数据库,同 Kubernetes 深度耦合,支持公有云、私有云和混合云,使部署、配置和维护变得十分简单。  TiDB 的设计目标是 100% 的 OLTP 场景和 80% 的 OLAP 场景,更复杂的 OLAP 分析可以通过 TiSpark 项目来完成。 TiDB 对业务没有任何侵入性,能优雅的替换传统的数据库中间件、数据库分库分表等 Sharding 方案。同时它也让开发运维人员不用关注数据库 Scale 的细节问题,专注于业务开发,极大的提升研发的生产力
6.3.4.2 TiDB整体架构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JWwKEu2B-1614077832839)(http://www.yunweipai.com/wp-content/uploads/2020/05/tidb-780x377.png)]

TiDB Server

TiDB Server 负责接收SQL请求,处理SQL相关的逻辑,并通过PD找到存储计算所需数据的TiKV地址,与TiKV交互获取数据,最终返回结果。TiDB Server 是无状态的,其本身并不存储数据,只负责计算,可以无限水平扩展,可以通过负载均衡组件(LVS、HAProxy或F5)对外提供统一的接入地址。

PD Server

Placement Driver(简称PD)是整个集群的管理模块,其主要工作有三个:一是存储集群的元信息(某个Key存储在那个TiKV节点);二是对TiKV集群进行调度和负载均衡(如数据的迁移、Raft group leader的迁移等);三是分配全局唯一且递增的事务ID

PD 是一个集群,需要部署奇数个节点,一般线上推荐至少部署3个节点。PD在选举的过程中无法对外提供服务,这个时间大约是3秒

TiKV Server

TiKV Server 负责存储数据,从外部看TiKV是一个分布式的提供事务的Key-Value存储引擎。存储数据的基本单位是Region,每个Region负责存储一个Key Range(从StartKey到EndKey的左闭右开区间)的数据,每个TiKV节点会负责多个Region。TiKV使用Raft协议做复制,保持数据的一致性和容灾。副本以Region为单位进行管理,不同节点上的多个Region构成一个Raft Group,互为副本。数据在多个TiKV之间的负载均衡由PD调度,这里也就是以Region为单位进行调度

MySQL 中间件代理服务器

6.2.1 关系型数据库和 NoSQL 数据库

数据库主要分为两大类:关系型数据库与 NoSQL 数据库。 关系型数据库,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库中的 数据。主流的 MySQL、Oracle、MS SQL Server 和 DB2 都属于这类传统数据库。 NoSQL 数据库,全称为 Not Only SQL,意思就是适用关系型数据库的时候就使用关系型数据库,不适用的 时候也没有必要非使用关系型数据库不可,可以考虑使用更加合适的数据存储。主要分为临时性键值存储 (memcached、Redis)、永久性键值存储(ROMA、Redis)、面向文档的数据库(MongoDB、CouchDB)、 面向列的数据库(Cassandra、HBase),每种 NoSQL 都有其特有的使用场景及优点。 Oracle,mysql 等传统的关系数据库非常成熟并且已大规模商用,为什么还要用 NoSQL 数据库呢?主要是 由于随着互联网发展,数据量越来越大,对性能要求越来越高,传统数据库存在着先天性的缺陷,即单机(单库) 性能瓶颈,并且扩展困难。这样既有单机单库瓶颈,却又扩展困难,自然无法满足日益增长的海量数据存储及其 性能要求,所以才会出现了各种不同的 NoSQL 产品,NoSQL 根本性的优势在于在云计算时代,简单、易于大规 模分布式扩展,并且读写性能非常高

RDBMS和NOSQL的特点及优缺点:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NRFgi9Vn-1614077832841)(http://www.yunweipai.com/wp-content/uploads/2020/06/image-20191129190833327-780x643.png)]

6.2.2 数据切分

简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机) 上面,以达到分散单台设备负载的效果。

数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。

一种是按照不同的表(或者 Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据 表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。

垂直切分的最大特点就是规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低,相互影响很小, 业务逻辑非常清晰的系统。在这种系统中,可以很容易做到将不同业务模块所使用的表分拆到不同的数据库中。 根据不同的表来进行拆分,对应用程序的影响也更小,拆分规则也会比较简单清晰。

水平切分于垂直切分相比,相对来说稍微复杂一些。因为要将同一个表中的不同数据拆分到不同的数据库中, 对于应用程序来说,拆分规则本身就较根据表名来拆分更为复杂,后期的数据维护也会更为复杂一些。

6.2.2.1 垂直切分

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oyFZqlGv-1614077832844)(http://www.yunweipai.com/wp-content/uploads/2020/06/image-20191031143053797-780x538.png)]

一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面,如下图:

MySQL——高可用+中间件代理_第5张图片

系统被切分成了,用户,订单交易,支付几个模块。 一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。

但是往往系统之有些表难以做到完全独立,存在着跨库 join 的情况,对于这类表,就需要去做平衡, 是数据库让步业务,共用一个数据源,还是分成多个库,业务之间通过接口来做调用。在系统初期,数据量比较 少,或者资源有限的情况下,会选择共用数据源,但是当数据发展到了一定的规模,负载很大的情况,就需要必须去做分割。

一般来讲业务存在着复杂 join 的场景是难以切分的,往往业务独立的易于切分。如何切分,切分到何种 程度是考验技术架构的一个难题。

垂直切分的优缺点:

优点:

  • 拆分后业务清晰,拆分规则明确
  • 系统之间整合或扩展容易
  • 数据维护简单

缺点:

  • 部分业务表无法 join,只能通过接口方式解决,提高了系统复杂度;
  • 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高
  • 事务处理复杂

由于垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存储瓶颈,所以就需要水平拆分来做解决。

6.2.2.2 水平切分

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qZj3aewS-1614077832848)(http://www.yunweipai.com/wp-content/uploads/2020/06/image-20191031143109117-780x504.png)]

对应shard中查询相关数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ezq4V25Q-1614077832851)(http://www.yunweipai.com/wp-content/uploads/2020/06/image-20191031143127772-780x509.png)]

相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中的某些行切分 到一个数据库,而另外的某些行又切分到其他的数据库中,如图:

MySQL——高可用+中间件代理_第6张图片

拆分数据就需要定义分片规则。关系型数据库是行列的二维模型,拆分的第一原则是找到拆分维度。比如: 从会员的角度来分析,商户订单交易类系统中查询会员某天某月某个订单,那么就需要按照会员结合日期来拆分, 不同的数据按照会员 ID 做分组,这样所有的数据查询 join 都会在单库内解决;如果从商户的角度来讲,要查询某 个商家某天所有的订单数,就需要按照商户 ID 做拆分;但是如果系统既想按会员拆分,又想按商家数据,则会有 一定的困难。如何找到合适的分片规则需要综合考虑衡量。

几种典型的分片规则包括:

  • 按照用户 ID 求模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中
  • 按照日期,将不同月甚至日的数据分散到不同的库中
  • 按照某个特定的字段求摸,或者根据特定范围段分散到不同的库中

如图,切分原则都是根据业务找到适合的切分规则分散到不同的库,下面用用户 ID 求模举例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M2l8DncQ-1614077832856)(http://www.yunweipai.com/wp-content/uploads/2020/06/image-20191129185545592.png)]

既然数据做了拆分有优点也就优缺点。

优点:

  • 拆分规则抽象好,join 操作基本可以数据库做
  • 不存在单库大数据,高并发的性能瓶颈
  • 应用端改造较少
  • 提高了系统的稳定性跟负载能力

缺点:

  • 拆分规则难以抽象
  • 分片事务一致性难以解决
  • 数据多次扩展难度跟维护量极大
  • 跨库 join 性能较差

前面讲了垂直切分跟水平切分的不同跟优缺点,会发现每种切分方式都有缺点,但共同特点缺点有:

  • 引入分布式事务的问题
  • 跨节点 Join 的问题
  • 跨节点合并排序分页问题
  • 多数据源管理问题

针对数据源管理,目前主要有两种思路:

A. 客户端模式,在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库, 在模块内完成数据的整合

B. 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明; 可能 90%以上的人在面对上面这两种解决思路的时候都会倾向于选择第二种,尤其是系统不断变得庞大复杂 的时候。确实,这是一个非常正确的选择,虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的 扩展性来说,是非常有帮助的。

MySQL中间件服务器可以通过将数据切分解决传统数据库的缺陷,又有了 NoSQL 易于扩展的优点。通过中间代理层规避了多数 据源的处理问题,对应用完全透明,同时对数据切分后存在的问题,也做了解决方案。

由于数据切分后数据 Join 的难度在此也分享一下数据切分的经验:

第一原则:能不切分尽量不要切分

第二原则:如果要切分一定要选择合适的切分规则,提前规划好。

第三原则:数据切分尽量通过数据冗余或表分组(Table Group)来降低跨库 Join 的可能

第四原则:由于数据库中间件对数据 Join 实现的优劣难以把握,而且实现高性能难度极大,业务读取尽量 少使用多表 Join。

6.2.3 MySQL中间件各种应用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YNNTBqY5-1614077832858)(http://www.yunweipai.com/wp-content/uploads/2020/06/image-20191129183107291.png)]

mysql-proxy:Oracle,https://downloads.mysql.com/archives/proxy/ Atlas:Qihoo,https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md dbproxy:美团,https://github.com/Meituan-Dianping/DBProxy Cetus:网易乐得,https://github.com/Lede-Inc/cetus Amoeba:https://sourceforge.net/projects/amoeba/ Cobar:阿里巴巴,Amoeba的升级版, https://github.com/alibaba/cobar Mycat:基于Cobar, http://www.mycat.io/ ProxySQL:https://proxysql.com/

6.2.4 Mycat
6.2.4.1 Mycat介绍

在整个IT系统架构中,数据库是非常重要,通常又是访问压力较大的一个服务,除了在程序开发的本身做优化,如:SQL语句优化、代码优化,数据库的处理本身优化也是非常重要的。主从、热备、分表分库等都是系统发展迟早会遇到的技术问题问题。Mycat是一个广受好评的数据库中间件,已经在很多产品上进行使用了。

Mycat是一个开源的分布式数据库系统,是一个实现了MySQL协议的服务器,前端用户可以把它看作是一个数据库代理(类似于Mysql Proxy),用MySQL客户端工具和命令行访问,而其后端可以用MySQL原生协议与多个MySQL服务器通信,也可以用JDBC协议与大多数主流数据库服务器通信,其核心功能是分表分库,即将一个大表水平分割为N个小表,存储在后端MySQL服务器里或者其他数据库里。

Mycat发展到目前的版本,已经不是一个单纯的MySQL代理了,它的后端可以支持MySQL、SQL Server、Oracle、DB2、PostgreSQL等主流数据库,也支持MongoDB这种新型NoSQL方式的存储,未来还会支持更多类型的存储。而在最终用户看来,无论是那种存储方式,在MyCat里,都是一个传统的数据库表,支持标准的SQL语句进行数据的操作,这样一来,对前端业务系统来说,可以大幅降低开发难度,提升开发速度

Mycat可以简单概括为

  • 一个彻底开源的,面向企业应用开发的大数据库集群
  • 支持事务、ACID、可以替代MySQL的加强版数据库
  • 一个可以视为MySQL集群的企业级数据库,用来替代昂贵的Oracle集群
  • 一个融合内存缓存技术、NoSQL技术、HDFS大数据的新型SQL Server
  • 结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
  • 一个新颖的数据库中间件产品

Mycat 官网:

http://www.mycat.io/

Mycat关键特性

  • 支持SQL92标准
  • 遵守MySQL 原生协议,跨语言,跨平台,跨数据库的通用中间件代理
  • 基于心跳的自动故障切换,支持读写分离,支持MySQL主从,以及galera cluster集群
  • 支持Galera for MySQL集群,Percona Cluster或者MariaDB cluster
  • 基于Nio实现,有效管理线程,高并发问题
  • 支持数据的多片自动路由与聚合,支持sum,count,max等常用的聚合函数,支持跨库分页
  • 支持单库内部任意join,支持跨库2表join,甚至基于caltlet的多表join
  • 支持通过全局表,ER关系的分片策略,实现了高效的多表join查询
  • 支持多租户方案
  • 支持分布式事务(弱xa)
  • 支持全局序列号,解决分布式下的主键生成问题
  • 分片规则丰富,插件化开发,易于扩展
  • 强大的web,命令行监控
  • 支持前端作为mysq通用代理,后端JDBC方式支持Oracle、DB2、SQL Server 、 mongodb 、巨杉
  • 支持密码加密
  • 支持服务降级
  • 支持IP白名单
  • 支持SQL黑名单、sql注入攻击拦截
  • 支持分表(1.6)
  • 集群基于ZooKeeper管理,在线升级,扩容,智能优化,大数据处理(2.0开发版)

为什么要用MyCat 这里要先搞清楚Mycat和MySQL的区别(Mycat的核心作用)。我们可以把上层看作是对下层的抽象,例如操作系统是对各类计算机硬件的抽象。那么我们什么时候需要抽象?假如只有一种硬件的时候,我们需要开发一个操作系统吗?再比如一个项目只需要一个人完成的时候不需要leader,但是当需要几十人完成时,就应该有一个管理者,发挥沟通协调等作用,而这个管理者对于他的上层来说就是对项目组的抽象

同样的,当我们的应用只需要一台数据库服务器的时候我们并不需要Mycat,而如果你需要分库甚至分表,这时候应用要面对很多个数据库的时候,这个时候就需要对数据库层做一个抽象,来管理这些数据库,而最上面的应用只需要面对一个数据库层的抽象或者说数据库中间件就好了,这就是Mycat的核心作用。所以可以这样理解:数据库是对底层存储文件的抽象,而Mycat是对数据库的抽象

Mycat工作原理

MySQL——高可用+中间件代理_第7张图片

Mycat的原理中最重要的一个动词是“拦截”,它拦截了用户发送过来的SQL语句,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户

Mycat应用场景 Mycat适用的场景很丰富,以下是几个典型的应用场景

  • 单纯的读写分离,此时配置最为简单,支持读写分离,主从切换
  • 分表分库,对于超过1000万的表进行分片,最大支持1000亿的单表分片
  • 多租户应用,每个应用一个库,但应用程序只连接Mycat,从而不改造程序本身,实现多租户化
  • 报表系统,借助于Mycat的分表能力,处理大规模报表的统计
  • 替代Hbase,分析大数据
  • 作为海量数据实时查询的一种简单有效方案,比如100亿条频繁查询的记录需要在3秒内查询出来结果,除了基于主键的查询,还可能存在范围查询或其他属性查询,此时Mycat可能是最简单有效的选择
  • Mycat长期路线图
  • 强化分布式数据库中间件的方面的功能,使之具备丰富的插件、强大的数据库智能优化功能、全面的系统监控能力、以及方便的数据运维工具,实现在线数据扩容、迁移等高级功能
  • 进一步挺进大数据计算领域,深度结合Spark Stream和Storm等分布式实时流引擎,能够完成快速的巨表关联、排序、分组聚合等 OLAP方向的能力,并集成一些热门常用的实时分析算法,让工程师以及DBA们更容易用Mycat实现一些高级数据分析处理功能
  • 不断强化Mycat开源社区的技术水平,吸引更多的IT技术专家,使得Mycat社区成为中国的Apache,并将Mycat推到Apache 基金会,成为国内顶尖开源项目,最终能够让一部分志愿者成为专职的Mycat开发者,荣耀跟实力一起提升

Mycat不适合的应用场景

  • 设计使用Mycat时有非分片字段查询,请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时有分页排序,请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时如果要进行表JOIN操作,要确保两个表的关联字段具有相同的数据分布,否则请慎重使用Mycat,可以考虑放弃!
  • 设计使用Mycat时如果有分布式事务,得先看是否得保证事务得强一致性,否则请慎重使用Mycat,可以考虑放弃!

MyCat的高可用性:

需要注意: 在生产环境中, Mycat节点最好使用双节点, 即双机热备环境, 防止Mycat这一层出现单点故障. 可以使用的高可用集群方式有:

  • Keepalived+Mycat+Mysql
  • Keepalived+LVS+Mycat+Mysql
  • Keepalived+Haproxy+Mycat+Mysql
6.2.4.2 Mycat安装

下载安装JDK

yum -y install java
#确认安装成功
java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)

下载安装mycat

wget http://dl.mycat.io/1.6-RELEASE/Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz
mkdir /app
tar xf Mycat-server-1.6-RELEASE-20161028204710-linux.tar.gz -C /app
ls /app/mycat/
bin  catlet  conf  lib  logs  version.txt

mycat安装目录结构:

  • bin mycat命令,启动、重启、停止等
  • catlet catlet为Mycat的一个扩展功能
  • conf Mycat 配置信息,重点关注
  • lib Mycat引用的jar包,Mycat是java开发的
  • logs 日志文件,包括Mycat启动的日志和运行的日志
  • version.txt mycat版本说明

logs目录:

  • wrapper.log mycat启动日志
  • mycat.log mycat详细工作日志
  • Mycat的配置文件都在conf目录里面,这里介绍几个常用的文件:
  • server.xml Mycat软件本身相关的配置文件,设置账号、参数等
  • schema.xml Mycat对应的物理数据库和数据库表的配置,读写分离、高可用、分布式策略定制、节点控制
  • rule.xml Mycat分片(分库分表)规则配置文件,记录分片规则列表、使用方法等

启动和连接

#配置环境变量
vim /etc/profile.d/mycat.sh
PATH=/app/mycat/bin:$PATH
source /etc/profile.d/mycat.sh
#启动
mycat start
#查看日志,确定成功
cat /app/mycat/logs/wrapper.log 
...省略...
INFO   | jvm 1    | 2019/11/01 21:41:02 | MyCAT Server startup successfully. see logs in logs/mycat.log

#连接mycat:
mysql -uroot -p123456 -h 127.0.0.1 -P8066
6.2.4.3 Mycat 主要配置文件说明

server.xml

存放Mycat软件本身相关的配置文件,比如:连接Mycat的用户,密码,数据库名称等

server.xml文件中配置的参数解释说明:

参数 说明 user 用户配置节点 name 客户端登录MyCAT的用户名,也就是客户端用来连接Mycat的用户名。 password 客户端登录MyCAT的密码 schemas 数据库名,这里会和schema.xml中的配置关联,多个用逗号分开,例如:db1,db2 privileges 配置用户针对表的增删改查的权限 readOnly mycat逻辑库所具有的权限。true为只读,false为读写都有,默认为false

注意:

  • server.xml文件里登录mycat的用户名和密码可以任意定义,这个账号和密码是为客户机登录mycat时使用的账号信息
  • 逻辑库名(如上面的TESTDB,也就是登录mycat后显示的库名,切换这个库之后,显示的就是代理的真实mysql数据库的表)要在schema.xml里面也定义,否则会导致mycat服务启动失败!
  • 这里只定义了一个标签,所以把多余的都注释了。如果定义多个标签,即设置多个连接mycat的用户名和密码,那么就需要在schema.xml文件中定义多个对应的库!

schema.xml

是最主要的配置项,此文件关联mysql读写分离策略,读写分离、分库分表策略、分片节点都是在此文件中配置的.MyCat作为中间件,它只是一个代理,本身并不进行数据存储,需要连接后端的MySQL物理服务器,此文件就是用来连接MySQL服务器的

schema.xml文件中配置的参数解释说明:

参数 说明 schema 数据库设置,此数据库为逻辑数据库,name与server.xml中schema对应 dataNode 分片信息,也就是分库相关配置 dataHost 物理数据库,真正存储数据的数据库

配置说明

name属性唯一标识dataHost标签,供上层的标签使用。 maxCon属性指定每个读写实例连接池的最大连接。也就是说,标签内嵌套的writeHost、readHost标签都会使用这个属性的值来实例化出连接池的最大连接数 minCon属性指定每个读写实例连接池的最小连接,初始化连接池的大小

每个节点的属性逐一说明

schema: 属性 说明 name 逻辑数据库名,与server.xml中的schema对应 checkSQLschema 数据库前缀相关设置,这里为false sqlMaxLimit select 时默认的limit,避免查询全表

table 属性 说明 name 表名,物理数据库中表名 dataNode 表存储到哪些节点,多个节点用逗号分隔。节点为下文dataNode设置的name primaryKey 主键字段名,自动生成主键时需要设置 autoIncrement 是否自增 rule 分片规则名,具体规则下文rule详细介绍

dataNode 属性 说明 name 节点名,与table中dataNode对应 datahost 物理数据库名,与datahost中name对应 database 物理数据库中数据库名

dataHost 属性 说明 name 物理数据库名,与dataNode中dataHost对应 balance 均衡负载的方式 writeType 写入方式 dbType 数据库类型 heartbeat 心跳检测语句,注意语句结尾的分号要加

schema.xml文件中有三点需要注意:balance=”1″,writeType=”0″ ,switchType=”1″ schema.xml中的balance的取值决定了负载均衡对非事务内的读操作的处理。balance 属性负载均衡类型,目前的取值有 4 种:

balance=”0″:不开启读写分离机制,所有读操作都发送到当前可用的writeHost上,即读请求仅发送到writeHost上 balance=”1″:一般用此模式,读请求随机分发到当前writeHost对应的readHost和standby的writeHost上。即全部的readHost与stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1 ->S1 , M2->S2,并且 M1 与 M2 互为主备),正常情况下, M2,S1, S2 都参与 select 语句的负载均衡 balance=”2″:读请求随机分发到当前dataHost内所有的writeHost和readHost上。即所有读操作都随机的在writeHost、 readhost 上分发 balance=”3″:读请求随机分发到当前writeHost对应的readHost上。即所有读请求随机的分发到 wiriterHost 对应的 readhost 执行, writerHost 不负担读压力,注意 balance=3 只在 1.4 及其以后版本有,1.3 没有

writeHost和readHost 标签

这两个标签都指定后端数据库的相关配置给mycat,用于实例化后端连接池。

唯一不同的是:writeHost指定写实例、readHost指定读实例,组着这些读写实例来满足系统的要求。

在一个dataHost内可以定义多个writeHost和readHost。但是,如果writeHost指定的后端数据库宕机,那么这个writeHost绑定的所有readHost都将不可用。另一方面,由于这个writeHost宕机系统会自动的检测到,并切换到备用的writeHost上去

注意: Mycat主从分离只是在读的时候做了处理,写入数据的时候,只会写入到writehost,需要通过mycat的主从复制将数据复制到readhost

6.2.4.4 实战案例:利用Mycat实现MySQL的读写分离

系统环境:

cat /etc/centos-release
CentOS Linux release 8.0.1905 (Core)

服务器共三台

mycat-server 192.168.100.10,内存建议2G以上
mysql-master 192.168.100.11
mysql-slave 192.168.100.12

关闭SELinux和防火墙

systemctl stop firewalld
setenforce 0
时间同步

1、创建 MySQL 主从数据库

[root@centos8 ~]#yum -y install mariadb-server

1) 修改master和slave上的配置文件

#master上的my.cnf
[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
server-id = 1
log-bin

#slave上的my.cnf
[mysqld]
server-id = 2

[root@centos8 ~]#systemctl start mariadb

2) Master上创建复制用户

[root@centos8 ~]#mysql -uroot -p
MariaDB [(none)]>GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'192.168.100.12' IDENTIFIED BY 'replpass';
mysql> FLUSH PRIVILEGES;    
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
|mariadb-bin.000001|      403 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

3) Slave上执行

[root@centos8 ~]#mysql -uroot -p
mysql> CHANGE MASTER TO
 ->     MASTER_HOST='192.168.100.11',
 ->     MASTER_USER='repluser',
 ->     MASTER_PASSWORD='replpass',
 ->     MASTER_LOG_FILE='mariadb-bin.000001',
 ->     MASTER_LOG_POS=403;

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.100.11
                  Master_User: repluser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mariadb-bin.000001
          Read_Master_Log_Pos: 439
               Relay_Log_File: mariadb-relay-bin.000002
                Relay_Log_Pos: 689
        Relay_Master_Log_File: mariadb-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
...省略..,

2、在192.168.100.10安装mycat并启动

[root@centos8 ~]#yum -y install java mariadb
#确认安装成功
[root@centos8 ~]#java -version
openjdk version "1.8.0_201"
OpenJDK Runtime Environment (build 1.8.0_201-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)

#下载并安装
[root@centos8 ~]#wget http://dl.mycat.io/1.6.7.3/20190927161129/Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz
[root@centos8 ~]#mkdir /app
[root@centos8 ~]#tar xvf Mycat-server-1.6.7.3-release-20190927161129-linux.tar.gz -C /app

#配置环境变量
[root@centos8 ~]#vim /etc/profile.d/mycat.sh
PATH=/app/mycat/bin:$PATH
[root@centos8 ~]#source /etc/profile.d/mycat.sh

#查看端口
[root@centos8 ~]#ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port 
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* 
LISTEN 0 128 [::]:22 [::]:* 
*:*
#启动mycat
[root@centos8 ~]#mycat start
Starting Mycat-server...
[root@centos8 ~]#ss -ntlp
State Recv-Q Send-Q Local Address:Port Peer Address:Port 
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=791,fd=5)) 
LISTEN 0 1 127.0.0.1:32000 0.0.0.0:* users:(("java",pid=4640,fd=4)) 
LISTEN 0 128 [::]:22 [::]:* users:(("sshd",pid=791,fd=7)) 
LISTEN 0 50 *:1984 *:* users:(("java",pid=4640,fd=57)) 
LISTEN 0 100 *:8066 *:* users:(("java",pid=4640,fd=87)) 
LISTEN 0 50 *:43465 *:* users:(("java",pid=4640,fd=58)) 
LISTEN 0 100 *:9066 *:* users:(("java",pid=4640,fd=83)) 
LISTEN 0 50 *:45259 *:* users:(("java",pid=4640,fd=56))

#查看日志,确定成功,可能需要等一会儿才能看到成功的提示
[root@centos8 ~]#tail /app/mycat/logs/wrapper.log 
ERROR | wrapper | 2020/02/28 15:21:48 | Startup failed: Timed out waiting for a signal from the JVM.
ERROR | wrapper | 2020/02/28 15:21:48 | JVM did not exit on request, terminated
INFO | wrapper | 2020/02/28 15:21:48 | JVM exited on its own while waiting to kill the application.
STATUS | wrapper | 2020/02/28 15:21:48 | JVM exited in response to signal SIGKILL (9).
STATUS | wrapper | 2020/02/28 15:21:52 | Launching a JVM...
INFO | jvm 2 | 2020/02/28 15:21:52 | OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=64M; support was removed in 8.0
INFO | jvm 2 | 2020/02/28 15:22:13 | Wrapper (Version 3.2.3) http://wrapper.tanukisoftware.org
INFO | jvm 2 | 2020/02/28 15:22:13 | Copyright 1999-2006 Tanuki Software, Inc. All Rights Reserved.
INFO | jvm 2 | 2020/02/28 15:22:13 | 
INFO | jvm 2 | 2020/02/28 15:22:31 | MyCAT Server startup successfully. see logs in logs/mycat.log

#用默认密码123456来连接mycat
[root@centos8 ~]#mysql -uroot -p123456 -h 192.168.100.10 -P8066
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.6.29-mycat-1.6-RELEASE-20161028204710 MyCat Server (OpenCloundDB)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB |
+----------+
1 row in set (0.01 sec)

MySQL [TESTDB]> show tables;
+------------------+
| Tables in TESTDB |
+------------------+
| travelrecord |
+------------------+
1 row in set (0.00 sec)

MySQL [TESTDB]> select * from travelrecord ;
ERROR 1105 (HY000): backend connect: java.lang.IllegalArgumentException: Invalid DataSource:0
MySQL [TESTDB]>

4、在mycat 服务器上修改server.xml文件配置Mycat的连接信息

[root@centos8 ~]#vim  /app/mycat/conf/server.xml
...省略...
                                       #连接Mycat的用户名
    magedu          #连接Mycat的密码
    TESTDB           #数据库名要和schema.xml相对应



这里使用的是root,密码为magedu,逻辑数据库为TESTDB,这些信息都可以自己随意定义,读写权限都有,没有针对表做任何特殊的权限。重点关注上面这段配置,其他默认即可。

5、修改schema.xml实现读写分离策略

[root@centos8 ~]#vim /app/mycat/conf/schema.xml                                       





select user()
******
******




#重新启动mycat
[root@centos8 ~]#mycat restart

上面配置中,balance改为1,表示读写分离。以上配置达到的效果就是192.168.100.11为主库,192.168.100.12为从库

注意:要保证192.168.100.11和192.168.100.12机器能使用root/123456权限成功登录mysql数据库。同时,也一定要授权mycat机器能使用root/123456权限成功登录这两台机器的mysql数据库!!这很重要,否则会导致登录mycat后,对库和表操作失败!

范例:schema.xml

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1byIY8sh-1614077832862)(http://www.yunweipai.com/wp-content/uploads/2020/06/image-20200228162026999-780x491.png)]

6、在后端主服务器创建用户并对mycat授权

[root@centos8 ~]#mysql -uroot -p
mysql> create database mycat;
mysql>GRANT ALL ON *.* TO 'root'@'192.168.100.10' IDENTIFIED BY '123456'  WITH GRANT OPTION;
mysql> flush privileges;

7、在Mycat服务器上连接并测试

[root@centos8 ~]#mysql -uroot -pmagedu -h127.0.0.1 -P8066 -DTESTDB
mysql> show databases;
+----------+
| DATABASE |
+----------+
| TESTDB   |    //只能看一个虚拟数据库
+----------+
mysql> use TESTDB;
mysql> create table t1(id int);
MySQL> select @@server_id;



8、通过通用日志确认实现读写分离

在mysql中查看通用日志

show variables like 'general_log';  #查看日志是否开启
set global general_log=on;    #开启日志功能
show variables like 'general_log_file'; #查看日志文件保存位置
set global general_log_file='tmp/general.log'; #设置日志文件保存位置

在主和从服务器分别启用通用日志,查看读写分离

[root@centos8 ~]#vim /etc/my.cnf.d/mariadb-server.cnf
[mysqld]
general_log=ON

[root@centos8 ~]#systemctl restart mariadb
[root@centos8 ~]#tail -f /var/lib/mysql/centos8.log

9、停止从节点,MyCAT自动调度读请求至主节点

[root@slave ~]#systemctl stop mariadb
[root@client ~]#mysql -uroot -pmagedu -h192.168.100.10 -P8066
MySQL [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|          1 |
+-------------+
1 row in set (0.00 sec)

MySQL [(none)]>

6.2.5 ProxySQL
6.2.5.1 ProxySQL 介绍

ProxySQL: MySQL中间件

两个版本:官方版和percona版,percona版是基于官方版基础上修改 C++语言开发,轻量级但性能优异,支持处理千亿级数据 具有中间件所需的绝大多数功能,包括: 多种方式的读/写分离 定制基于用户、基于schema、基于语句的规则对SQL语句进行路由 缓存查询结果 后端节点监控

官方站点:https://proxysql.com/ 官方手册:https://github.com/sysown/proxysql/wiki

6.2.5.2 ProxySQL安装

基于YUM仓库安装 cat <

yum install proxysql

ProxySQL组成

  • 服务脚本:/etc/init.d/proxysql
  • 配置文件:/etc/proxysql.cnf
  • 主程序:/usr/bin/proxysql
  • 基于SQLITE的数据库文件:/var/lib/proxysql/

启动ProxySQL:

service proxysql start

启动后会监听两个默认端口

  • 6032:ProxySQL的管理端口
  • 6033:ProxySQL对外提供服务的端口

连接ProxySQL的管理端口

使用mysql客户端连接到ProxySQL的管理接口6032,默认管理员用户和密码都是admin:

mysql -uadmin -padmin -P6032 -h127.0.0.1

数据库说明:

  • main 是默认的”数据库”名,表里存放后端db实例、用户验证、路由规则等信息。表名以 runtime开头的表示
  • proxysql当前运行的配置内容,不能通过dml语句修改,只能修改对应的不以 runtime_ 开头的(在内存)里的表,然后 LOAD 使其生效, SAVE 使其存到硬盘以供下次重启加载
  • disk 是持久化到硬盘的配置,sqlite数据文件
  • stats 是proxysql运行抓取的统计信息,包括到后端各命令的执行次数、流量、processlist、查询种类汇总/执行时间,等等
  • monitor 库存储 monitor 模块收集的信息,主要是对后端db的健康/延迟检查

说明: 在main和monitor数据库中的表, runtime开头的是运行时的配置,不能修改,只能修改非runtime表 修改后必须执行LOAD … TO RUNTIME才能加载到RUNTIME生效 执行save … to disk 才将配置持久化保存到磁盘,即保存在proxysql.db文件中 global_variables 有许多变量可以设置,其中就包括监听的端口、管理账号等 参考: https://github.com/sysown/proxysql/wiki/Global-variables

7.2.5.3 实战案例:利用ProxySQL实现读写分离
  1. 环境准备:

准备三台主机,一台ProxySQL服务器:192.168.8.7,另外两台主机实现主从复制192.168.8.17,27

注意:slave节点需要设置read_only=1

  1. 安装ProxySQL,并向ProxySQL中添加MySQL节点,以下操作不需要use main也可成功

    MySQL>  show tables;
    MySQL > select * from sqlite_master where  name='mysql_servers'\G
    MySQL > select * from  mysql_servers;   
    MySQL > insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.8.17',3306); 
    MySQL > insert into mysql_servers(hostgroup_id,hostname,port) values(10,'192.168.8.27',3306);
    MySQL > load mysql servers to runtime;
    MySQL > save mysql servers to disk;
    
    
  2. 添加监控后端节点的用户,连接每个节点的read_only值来自动调整主从节点是属于读组还是写组

    #在master上执行
    MySQL> grant replication client on *.* to monitor@'192.168.8.%'  identified by 'magedu';
    #ProxySQL上配置监控
    MySQL [(none)]> set mysql-monitor_username='monitor';
    MySQL [(none)]> set mysql-monitor_password='magedu';
    #加载到RUNTIME,并保存到disk
    MySQL [(none)]> load mysql variables to runtime;
    MySQL [(none)]> save mysql variables to disk;
    
    
  3. 查看监控 监控模块的指标保存在monitor库的log表中

    #查看监控连接是否正常的 (对connect指标的监控),如果connect_error的结果为NULL则表示正常
    MySQL> select * from mysql_server_connect_log;
    #查看监控心跳信息 (对ping指标的监控):
    MySQL> select * from mysql_server_ping_log;
    
    
  4. 设置分组信息 需要修改的是main库中的mysql_replication_hostgroups表,该表有3个字段:writer_hostgroup,reader_hostgroup,comment, 指定写组的id为10,读组的id为20

    MySQL> insert into mysql_replication_hostgroups values(10,20,"test");
    将mysql_replication_hostgroups表的修改加载到RUNTIME生效
    MySQL> load mysql servers to runtime;
    MySQL> save mysql servers to disk;
    #Monitor模块监控后端的read_only值,按照read_only的值将节点自动移动到读/写组
    MySQL> select hostgroup_id,hostname,port,status,weight from mysql_servers; 
    +--------------+--------------+------+--------+--------+
    | hostgroup_id | hostname     | port | status | weight |
    +--------------+--------------+------+--------+--------+
    | 10           | 192.168.8.17 | 3306 | ONLINE | 1      |
    | 20           | 192.168.8.27 | 3306 | ONLINE | 1      |
    
    
  5. 配置访问数据库的SQL 用户

    #在master节点上创建访问用户
    MySQL> grant all on *.* to sqluser@'192.168.8.%' identified by 'magedu';
    #在ProxySQL配置,将用户sqluser添加到mysql_users表中, default_hostgroup默认组设置为写组10,当读写分离的路由规则不符合时,会访问默认组的数据库
    MySQL> insert into mysql_users(username,password,default_hostgroup) values('sqluser','magedu',10);
    MySQL> load mysql users to runtime;
    MySQL> save mysql users to disk;
    #使用sqluser用户测试是否能路由到默认的10写组实现读、写数据
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select @@server_id' 
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'create database testdb' 
    mysql -usqluser -pmagedu testdb -P6033 -h127.0.0.1 -e 'create table t(id int)'
    
    
  6. 在proxysql上配置路由规则,实现读写分离 与规则有关的表:mysql_query_rules和mysql_query_rules_fast_routing,后者是前者的扩展表,1.4.7之后支持 插入路由规则:将select语句分离到20的读组,select语句中有一个特殊语句SELECT…FOR UPDATE它会申请写锁,应路由到10的写组

    MySQL> insert into mysql_query_rules 
    (rule_id,active,match_digest,destination_hostgroup,apply)VALUES 
    (1,1,'^SELECT.*FOR UPDATE$',10,1),(2,1,'^SELECT',20,1);
    MySQL> load mysql query rules to runtime;
    MySQL> save mysql query rules to disk;
    #注意:因ProxySQL根据rule_id顺序进行规则匹配,select ... for update规则的rule_id必须要小于普通的select规则的rule_id
    
  7. 测试proxySQL

    #读操作是否路由给20的读组
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select @@server_id'
    #测试写操作,以事务方式进行测试
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 \
    -e 'start transaction;select @@server_id;commit;select @@server_id'
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'insert testdb.t values (1)'
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select id from testdb.t' 
    #路由的信息:查询stats库中的stats_mysql_query_digest表
    MySQL > SELECT hostgroup hg,sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;
    
    #测试读操作是否路由给20的读组
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select @@server_id'
    #测试写操作,以事务方式进行测试
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 \
    -e 'start transaction;select @@server_id;commit;select @@server_id'
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'insert testdb.t values (1)'
    mysql -usqluser -pmagedu -P6033 -h127.0.0.1 -e 'select id from testdb.t' 
    #路由的信息:查询stats库中的stats_mysql_query_digest表
    MySQL > SELECT hostgroup hg,sum_time, count_star, digest_text FROM stats_mysql_query_digest ORDER BY sum_time DESC;
    

你可能感兴趣的:(MySQL——高可用+中间件代理)