参考文章来源:
https://www.cnblogs.com/kevingrace/p/10466530.html
一.Innodb cluster集群介绍
- MySQL的高可用架构无论是社区还是官方,一直在技术上进行探索,这么多年提出了多种解决方案,比如
MMM
,MHA
,NDB Cluster
,Galera Cluster
,InnoDB Cluster
, 腾讯的PhxSQL
,MySQL Fabric
,aliSQL
。 - MySQL官方在2017年4月推出了一套完整的、高可用的Mysql解决方案 - MySQL InnoDB Cluster, 即一组MySQL服务器可以配置为一个MySQL集群。在默认的单主节点模式下,集群服务器具有一个读写主节点和多个只读辅节点。辅助服务器是主服务器的副本。客户端应用程序通过MySQL Router连接到主服务程序。如果主服务连接失败,则次要的节点自动提升为主节点,MySQL Router请求到新的主节点。InnoDB Cluster不提供NDB Cluster支持。
- 分布式MySQL之InnoDB和NDB
分布式MySQL主要有InnoDB和NDB模式, NDB是基于集群的引擎-数据被自动切分并复制到数个机器上(数据节点), 适合于那些需要极高查询性能和高可用性的应用, 原来是为爱立信的电信应用设计的。 NDB提供了高达99.999%的可靠性,在读操作多的应用中表现优异。 对于有很多并发写操作的应用, 还是推荐用InnoDB。
========== NDB和InnoDB存储引擎之间的特性差异 ==========
InnoDB(MySQL 5.7)特性:
- InnoDB版本:InnoDB 5.7.20;
- NDB Cluster版本:不支持;
- 最大存储长度:64TB;
- 事物:所有标准事物类型;
- 多版本并发控制:支持;
- 数据压缩:支持;
- 大行支:VARBINARY、VARCHAR、BLOB;
- 同步支持:半同步、异步;
- 块读取:支持;
- 块写入:需要使用水平分区;
- 高可用性:高;
NDB 7.5/7.6特性:
- InnoDB版本:InnoDB 5.7.20;
- NDB Cluster版本: NDB 7.5.8/7.6.4;
- 最大存储长度:128TB;
- 事物:读提交;
- 多版本并发控制:不支持;
- 数据压缩支持:不支持;
- 大行支持:BLOB、 TEXT;
- 同步支持半:自动同步;
- 块读取:支持;
- 块写入:支持;
- 高可用性:非常高;
- 本次部署采用
InnoDB Cluster
. 每台服务器实例都运行MySQL Group Replication
(冗余复制机制,内置failover
) -
MGR
有两种模式,一种是Single-Primary
,一种是Multi-Primary
,即单主或者多主。 - 注意:
Multi-Primary
模式中,所有的节点都是主节点,都可以同时被读写,看上去这似乎更好,但是因为多主的复杂性,在功能上如果设置了多主模式,则会有一些使用的限制,比如不支持Foreign Keys with Cascading Constraints。
MySQL InnoDB Cluster 集群特性, 有什么好处 (为什么使用它)
-
集成易用
MySQL InnoDB集群紧密集成了MySQL Servers with Group Replication,MySQL Router,和MySQL Shell,所以不必依赖于外部工具,脚本或其他部件。 另外它利用了现有的MySQL特性,如:InnoDB, GTIDs, binary logs, multi-threaded slave execution, multi-source replication and Performance Schema。可以在五分钟内利用MySQL Shell中的脚本化的管理API来创建及管理MySQL集群。 -
使用组复制的mysql server HA
组复制提供了内置的组成员管理、数据一致性保证、冲突检测和处理、节点故障检测和数据库故障转移相关操作的本地高可用性,无需人工干预或自定义工具。组复制同时实现了带自动选主的单主模式及任意更新的多主模式。通过使用一个强大的新的组通信系统,它提供了流行的Paxos算法的内部实现,来自动协调数据复制、一致性、membership。这提供了使MySQL数据库高度可用所需的所有内置机制。 -
弹性
通过组复制,一组服务器协调在一起形成一个组。组成员是动态的,服务器可以自愿或强制的地离开及随时加入。组将根据需要自动重新配置自己,并确保任何加入成员与组同步。这样就可以方便地在需要时快速地调整数据库的总容量。 -
故障检测
组复制实现了一个分布式故障检测器来查找并报告failed或不再参与组的服务器,组中剩余成员将重新配置。 -
容错
组复制基于流行的Paxos分布式算法来提供服务器之间的分布式协调。为了使一个小组继续发挥作用,它要求大多数成员在线,并就每一个变化达成协议。这允许MySQL数据库在发生故障时安全地继续操作,而无需人工干预,不存在数据丢失或数据损坏的风险。 -
自愈
如果一个服务器加入该组,它将自动将其状态与现有成员同步。如果服务器离开该组,例如它被取下来进行维护,剩下的服务器将看到它已离开,并将自动重新配置组。当服务器后重新加入组,它会自动重新与组同步。 -
监测
MySQL Enterprise Monitor 3.4及以后的版本全面支持组复制;监控每个节点的配置,健康,和性能。并且提供最佳实践建议和提醒,以及易于理解的可视化工具,允许您轻松地监控和管理您的组复制和InnoDB集群。 -
通过MySQL Router为mysql客户机应用程序实现HA
MySQL的路由器允许您轻松迁移您的独立的MySQL实例到本地分布式高可用集群而不影响现有的应用程序。新metadata_cache插件为Innodb 集群提供了透明的客户端连接路由、负载平衡和故障转移的能力。 -
简单易用的MySQL shell
MySQL Shell为所有MySQL相关的任务提供了一个直观、灵活、功能强大的接口。
新的adminapi使得它很容易用一种自我描述的自然语言来创建,监控和管理包括MySQL Router在内的MySQL InnoDB集群,而不需要了解低层次的概念,配置选项,或其他复杂的方面。
二.工作原理
MySQL InnoDB集群提供了一个集成的,本地的,HA解决方案。Mysq Innodb Cluster是利用组复制的 pxos 协议,保障数据一致性,组复制支持单主模式和多主模式。
MySQL InnoDB集群由以下几部分组成:
- MySQL Servers with Group Replication:向集群的所有成员复制数据,同时提供容错、自动故障转移和弹性。MySQL Server 5.7.17或更高的版本。
- MySQL Router:确保客户端请求是负载平衡的,并在任何数据库故障时路由到正确的服务器。MySQL Router 2.1.3或更高的版本。
- MySQL Shell:通过内置的管理API创建及管理Innodb集群。MySQL Shell 1.0.9或更高的版本。
各个组件的关系和工作流程如下:
三.集群方案
我采用3台centos7.7 服务器来搭建MySQL Innodb cluster集群,分别是一主两从,如下部署:
ip地址 主机名 角色 安装软件
192.168.62.11 node-1 cluster节点1 Mysql5.7, mysql-shell, mysql-route
192.168.62.12 node-2 cluster节点2 Mysql5.7, mysql-shell, mysql-route
192.168.62.13 node-3 cluster节点3 Mysql5.7, mysql-shell
mysql,mysql shell 和mysql router的安装包如下:
- mysql:mysql-5.7.29-linux-glibc2.12-x86_64.tar.gz
- mysql-shell:mysql-shell-1.0.11-linux-glibc2.12-x86-64bit.tar.gz
- mysql-router:mysql-router-2.1.6-linux-glibc2.12-x86-64bit.tar.gz
根据官方的文档 https://dev.mysql.com/doc/refman/8.0/en/mysql-innodb-cluster-userguide.html,mysql-shell需要python环境,至少在2.7版本以上,所以在安装使用前,需要提前部署好python环境。
查看python版本
python -V
Python 2.7.5
四.环境准备(所有服务器都要操作)
1.关闭防火墙,关闭方法因系统不同,所以不列出
2.关闭selinux(Centos),关闭方法因系统不同,所以不列出
3.配置每个节点的/etc/hosts主机映射, 方便通过节点的hostname进行连接
这一步很重要,否则可能会出现无法同步的情况,因为数据库需要根据member_host同步,如果不配置,默认就是localhost,这样时无法通信的!!!
vim /etc/hosts
...........
192.168.62.11 node-1
192.168.62.12 node-2
192.168.62.13 node-3
4.优化配置
[root@localhost ~]# cat>>/etc/sysctl.conf <<EOF
fs.aio-max-nr = 1048576
fs.file-max = 681574400
kernel.shmmax = 137438953472
kernel.shmmni = 4096
kernel.sem = 250 32000 100 200
net.ipv4.ip_local_port_range = 9000 65000
net.core.rmem_default = 262144
net.core.rmem_max = 4194304
net.core.wmem_default = 262144
net.core.wmem_max = 1048586
EOF
[root@localhost ~]# sysctl -p
#mysql服务需要打开15000个文件数,默认用户只有1024(通过ulimit -n 查询当前是多少),修改如下,其中cluster为我安装mysql使用的linux用户:
[root@localhost ~]# cat>>/etc/security/limits.conf <<EOF
cluster soft nproc 65536
cluster hard nproc 65536
cluster soft nofile 65536
cluster hard nofile 65536
EOF
五.环境部署记录
5.1.在三个cluster节点安装和部署Mysql5.7及 mysql-shell。
三个节点同样操作,此处只列出第一个节点的安装配置记录
安装mysql5.7
使用yum方式安装Mysql5.7,参考:
https://www.cnblogs.com/kevingrace/p/8340690.html
非root用户下安装mysql,参考:
https://www.jianshu.com/p/d91e79b5146b安装mysql-shell
#解压
tar -zvxf mysql-shell-1.0.11-linux-glibc2.12-x86-64bit.tar.gz
mv mysql-shell-1.0.11-linux-glibc2.12-x86-64bit mysql-shell
#在用户目录添加环境变量,编辑.bash_profile或者/etc/profile末尾添加
export PATH=$PATH:/home/cluster/mysql-shell/bin
#更新环境变量
source /etc/profile
#输入指令查询版本
mysqlsh --version
mysqlsh Ver 1.0.11 for Linux on x86_64 - for MySQL 5.7.20 (MySQL Community Server (GPL))
- 测试mysql-shell
[cluster@centos76 ~]$ mysqlsh
MySQL Shell 1.0.11
Copyright (c) 2016, 2017, 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 '\?' for help; '\quit' to exit.
Currently in JavaScript mode. Use \sql to switch to SQL mode and execute queries.
mysql-js>
#连接本节点数据库
mysql-js> shell.connect('root@node-1:3305');
#回车,会提示输入密码
Please provide the password for 'root@node-1:3305':
Creating a Session to 'root@node-1:3305'
Your MySQL connection id is 20
No default schema selected; type \use <schema> to set one.
mysql-js>
#如上所示,表示连接成功
连接时可能会报如下错误:
Shell.connect: Host 'node-1' is not allowed to connect to this MySQL server (MySQL Error 1130)
需要在MySQL中,新建用户及授权,如下:
CREATE USER 'root'@'%' IDENTIFIED BY '123456';
grant all privileges on *.* to 'root'@'%' with grant option;
flush privileges; /*刷新权限*/
- 配置my.cnf
- 配置前先备份
- 修改不同机器的server_id、ip;3个cluster节点除了server_id、loose-group_replication_local_address 两个参数不一样外,其他保持一致。
- loose-group_replication_group_name使用UUID形式,集群中机器使用同一个UUID;
- loose-group_replication_single_primary_mode在单主模式中为ON,在多主模式中为OFF
- 配置完成后, 将my.cnf文件拷贝到其他两个节点,并且依次重启三个节点的数据库,安装MGR插件,设置复制账号(所有MGR节点都要执行)
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
character-set-server = utf8
port = 3305
bind-address = node-1 #需提前在 /etc/hosts 增加 node-1记录
basedir = /home/cluster/mysql
datadir = /home/cluster/mysql/data
socket = /home/cluster/mysql/mysql.sock
log_error=/home/cluster/mysql/error.log
pid-file=/home/cluster/mysql/mysql.pid
# Disabling symbolic-links is recommended to prevent assorted security risks
#symbolic-links = 0
# Replication configuration parameters
server_id = 1
gtid_mode = ON
enforce_gtid_consistency = ON
log_bin = binlog
log_slave_updates = ON
binlog_format = ROW
binlog_checksum = NONE
master_info_repository=TABLE
relay_log_info_repository=TABLE
max_connections=200
max_allowed_packet=16M
#server必须为每个事务收集写集合,并使用XXHASH64哈希算法将其编码为散列
transaction_write_set_extraction=XXHASH64
#告知插件加入或创建组命名,UUID,集群中UUID一致
loose-group_replication_group_name="816dd734-5cfd-11ea-9ba1-fa163e443845"
#server启动时不自启组复制,为了避免每次启动自动引导具有相同名称的第二个组,所以设置为OFF。
loose-group_replication_start_on_boot=off
#告诉插件使用IP地址,端口24901用于接收组中其他成员转入连接
loose-group_replication_local_address= "node-1:3305"
#启动组server,种子server,加入组应该连接这些的ip和端口;其他server要加入组得由组成员同意
loose-group_replication_group_seeds="node-1:3305,node-2:3305,node-3:3305"
loose-group_replication_ip_whitelist="node-1,node-2,node-3"
loose-group_replication_bootstrap_group = off
loose-group_replication_allow_local_disjoint_gtids_join = ON
# 使用MGR的单主模式
loose-group_replication_single_primary_mode = on
loose-group_replication_enforce_update_everywhere_checks = off
# 禁止其他引擎创建库表
disabled_storage_engines = MyISAM,BLACKHOLE,FEDERATED,CSV,ARCHIVE
[client]
port=3305
default-character-set=utf8
socket=/home/cluster/mysql/mysql.sock
5.2.配置创建Innodb Cluster集群
- 持久化集群配置文件,会自动在指定的my.cnf文件中添加配置项 (需要三个节点同样操作)
mysqlsh
mysql-js> dba.configureLocalInstance('root@node-1:3305');
Please provide the password for 'root@node-1:3305':
#输入密码
Detecting the configuration file...
Found configuration file at standard location: /etc/my.cnf
Do you want to modify this file? [Y|n]: [Y|n]:
#由于配置时不是采用用默认的/etc/my.cnf文件,此处选n,然后指定配置文件路径
Default file not found at the standard locations.
Please specify the path to the MySQL configuration file:/home/cluster/mysql/my.cnf
Validating instance...
The instance 'node-2:3305' is valid for Cluster usage
You can now use it in an InnoDB Cluster.
{
"status": "ok"
}
mysql-js>
由上面的信息看出, status 为 ok 说明配置没问题了,检查my.cnf配置文件是否发生变化,可以查看实例状态
mysql-js > dba.checkInstanceConfiguration('root@node-1:3305');
- 在管理节点创建 cluster集群,这里我采用第一个节点作为管理节点创建,节点:node-1(只在管理节点操作创建,窗口一致保持打开,添加节点时也需要用到)
mysqlsh
#连接
mysql-js > shell.connect('root@node-1:3305');
# 创建一个 cluster,命名为 'myCluster'
mysql-js > var cluster = dba.createCluster('myCluster');
A new InnoDB cluster will be created on instance 'root@node-1:3305'.
Creating InnoDB cluster 'myCluster' on 'root@node-1:3305'...
Adding Seed Instance...
Cluster successfully created. Use Cluster.addInstance() to add MySQL instances.
At least 3 instances are needed for the cluster to be able to withstand up to
one server failure.
mysql-js>
# 创建成功后,查看cluster状态,可以看到master已经添加进cluster
mysql-js> cluster.status();
{
"clusterName": "myCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "node-1:3305",
"status": "OK_NO_TOLERANCE",
"statusText": "Cluster is NOT tolerant to any failures.",
"topology": {
"node-1:3305": {
"address": "node-1:3305",
"mode": "R/W",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
}
}
}
}
- 通过cluster状态查看,可以看到master已经添加进cluster,现在添加slave从节点 (在管理节点操作添加)
mysqlsh
#连接
mysql-js > shell.connect('root@node-1:3305');
# 添加实例
mysql-js> cluster.addInstance('root@node-2:3305');
# 如果 之前的管理终端关闭,重新打开,执行语句时会报错:
TypeError: Cannot read property 'status' of undefined
#这时需要先执行下面这条语句获取后,再添加节点
mysql-js> cluster=dba.getCluster();
# 先添加node-2节点
mysql-js> cluster.addInstance('root@node-2:3305');
A new instance will be added to the InnoDB cluster. Depending on the amount of
data on the cluster this might take from a few seconds to several hours.
#输入密码
Please provide the password for 'root@node-2:3305':
Adding instance to the cluster ...
The instance 'root@node-2:3305' was successfully added to the cluster.
mysql-js>
# 再添加node-3节点
mysql-js> cluster.addInstance('root@node-3:3305');
A new instance will be added to the InnoDB cluster. Depending on the amount of
data on the cluster this might take from a few seconds to several hours.
Please provide the password for 'root@node-3:3305':
Adding instance to the cluster ...
The instance 'root@node-3:3305' was successfully added to the cluster.
mysql-js>
#成功后查看集群状态
mysql-js> cluster.status();
{
"clusterName": "myCluster",
"defaultReplicaSet": {
"name": "default",
"primary": "node-1:3305",
"status": "OK",
"statusText": "Cluster is ONLINE and can tolerate up to ONE failure.",
"topology": {
"node-1:3305": {
"address": "node-1:3305",
"mode": "R/W",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
},
"node-2:3305": {
"address": "node-2:3305",
"mode": "R/O",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
},
"node-3:3305": {
"address": "node-3:3305",
"mode": "R/O",
"readReplicas": {},
"role": "HA",
"status": "ONLINE"
}
}
}
}mysql-js>
通过上面cluster集群信息可知, node-1节点是主节点, 具有R/W读写权限, 其他两个节点是从节点, 具有R/O 只读权限。
5.3.在node-1和node-2分别安装mysql-route
1.mysql-route介绍
- MySQL Router是处于应用client和dbserver之间的轻量级代理程序,它能检测,分析和转发查询到后端数据库实例,并把结果返回给client。是mysql-proxy的一个替代品。
- Router实现读写分离,程序不是直接连接数据库IP,而是固定连接到mysql router。MySQL Router对前端应用是透明的。应用程序把MySQL Router当作是普通的mysql实例,把查询发给MySQL Router,而MySQL Router会把查询结果返回给前端的应用程序。
- 从数据库服务器故障,业务可以正常运行。由MySQL Router来进行自动下线不可用服务器。程序配置不需要任何修改。
- 主数据库故障,由MySQL Router来决定主从自动切换,业务可以正常访问。程序配置不需要做任何修改。
- 安装配置
# 解压
tar -xzvf mysql-router-2.1.6-linux-glibc2.12-x86-64bit.tar.gz
mv mysql-router-2.1.6-linux-glibc2.12-x86-64bit mysql-router-init
修改用户配置文件vi .bash_profile,内容如下:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
export PATH=$PATH:/home/cluster/mysql/bin
export PATH=$PATH:/home/cluster/mysql-shell/bin
export PATH=$PATH:/home/cluster/mysql-router-init/bin
source .bash_profile
mysqlprovision --version
mysqlprovision version 2.1.0
- 配置MySQL router
mysqlrouter --bootstrap root@node-1:3305 -d /home/cluster/mysql-router --conf-base-port 23306
# 选项说明参考 https://dev.mysql.com/doc/mysql-router/8.0/en/mysqlrouter.html
Please enter MySQL password for root:
Bootstrapping MySQL Router instance at /home/cluster/mysql-router...
MySQL Router has now been configured for the InnoDB cluster 'myCluster'.
The following connection information can be used to connect to the cluster.
Classic MySQL protocol connections to cluster 'myCluster':
- Read/Write Connections: localhost:23306 #读写端口
- Read/Only Connections: localhost:23307 #只读端口
X protocol connections to cluster 'myCluster':
- Read/Write Connections: localhost:23308
- Read/Only Connections: localhost:23309
会自动在/home/cluster/mysql-router目录下生成配置文件及启动脚本
进入 mysql-router 目录,配置并启动(可以修改配置文件, 也可以默认不修改)
#启动
/home/cluster/mysql-router/start.sh
PID 16819 written to /home/cluster/mysql-router/mysqlrouter.pid
#默认通过route连接mysql后, 23306端口连接后可以进行读写操作. 23307端口连接后只能进行只读操作.
$ netstat -nltp | grep 2330
tcp 0 0 0.0.0.0:23306 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:23307 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:23308 0.0.0.0:* LISTEN off (0.00/0/0)
tcp 0 0 0.0.0.0:23309 0.0.0.0:* LISTEN off (0.00/0/0)
这样就可以使用MySQL客户端连接router了. 下面验证下连接router:
- 管理MySQL Router
a) 管理节点本机mysql-shell连接:
[cluster@node-1 ~]$ mysqlsh --uri root@node-1:23306
b) 管理节点本机mysql连接:
[cluster@node-2 ~]$ mysql -u root -h node-1 -P 23306 -p
c) 远程客户机通过route连接mysql
[root@db-node01 ~]# mysql -u root -h 127.0.0.1 -P 23306 -p
此外, 还可以利用keepalived实现InnoDB Cluster的高可用, 即两台db-route管理节点, 通过VIP资源实现故障无感知切换.