MySQL Router介绍
MySQL Router是MySQL官方提供的一个轻量级中间件,是InnoDB Cluster的一部分,当然它也可以单独部署使用,可在应用程序和后端MySQL服务器之间提供透明路由方式。主要用以解决MySQL主从/集群的高可用、负载均衡、易扩展等问题。Router作为一个流量转发层,位于应用程序与MySQL服务器之间,其功能类似于LVS。MySQL Router还可以与MySQL Fabric无缝连接,允许Fabric存储和管理用于路由的高可用数据库服务器组,使得管理MySQL服务器组更加简单。
官方介绍如下:
MySQL Router is part of InnoDB Cluster, and is lightweight middleware that provides transparent routing between your application and back-end MySQL Servers. It can be used for a wide variety of use cases, such as providing high availability and scalability by effectively routing database traffic to appropriate back-end MySQL Servers. The pluggable architecture also enables developers to extend MySQL Router for custom use cases. For additional details about how MySQL Router is part of InnoDB Cluster, see MySQL AdminAPI.
中文翻译如下:
MySQL Router 是 InnoDB Cluster 的一部分,是轻量级中间件,可在您的应用程序和后台MySQL服务器之间提供透明路由。它可用于各种用例,例如通过有效地将数据库流量路由到适当的后端 MySQL 服务器来提供高可用性和可扩展性。可插拔架构还使开发人员能够针对自定义用例扩展 MySQL Router。有关 MySQL Router 如何成为 InnoDB Cluster 的一部分的更多详细信息,请参阅MySQL AdminAPI。
其实,MySQL Router作为一个流量转发层,应用程序不再直接连MySQL Server,而是与MySQL Router连接,根据MySQL Router的配置,它通过端口实现读写分离,然后根据设置把应用程序的读写请求转发给后端的MySQL Server. MySQL Router对读写请求进行负载均衡, 当后台的某个MySQL 实例不能提供服务时,Router会将其从Acitve列表移除,当其Online后,MySQL Router会再次将其加入Active列表。更多关于MySQL Router的资料,建议参考官方文档, 官方文档资料链接如下:
https://dev.mysql.com/doc/mysql-router/8.0/en/
另外,MySQL Router源码放在github上:
https://github.com/mysql/mysql-router
MySQL Router版本
到目前为止,MySQL Router大的版本衍化如下所示,大版本下还有很多小版本,这里不做展开介绍。
MySQL Router 2.0 -> MySQL Router 2.1 -> MySQL Router 8.0 -> MySQL Router 8.2
MySQL Router版本的衍化,会有一些新的功能和特性变化,例如,MySQL Router 8.0版本新功能和变化:
- 添加了可选的 routing_strategy 配置选项。可用值为 first-available、 next-available、 round-robin和 round-robin-with-fallback。以前,这些策略被mode配置选项描述为调度模式,其中读写模式默认为first-available策略,只读模式默认为round-robin策略。这会保留这些模式的先前行为。
- 添加了--ssl-key和 --ssl-cert可选的引导命令行选项。它们直接使用对应的MySQL客户端,并指定客户端证书和私钥,方便客户端认证。当引导期间使用的根帐户是使用 REQUIRE X509 创建的时,这很有用,这需要客户端在登录时对自己进行身份验证。
- 添加了新的 connect_timeout 和 read_timeout 元数据配置文件选项。这些在 [DEFAULT] 命名空间下定义并影响内部操作,例如元数据服务器连接。
- Bootstrap 现在接受 InnoDB 集群的任何成员,并自动查找并重新连接到可写主节点。以前,只有初级被接受。
- Bootstrap 现在接受该 --config选项并读取[logger] level 选项的定义。
- 并发客户端连接的最大数量从大约 500 增加到超过 5000,这个限制现在取决于操作系统。为实现这一点,基于 select() 的 fd 事件调用被 poll()(或 Windows 上的 WSAPoll())取代。MySQL Router 8.0.22 将此限制增加到大约 50,000;有关详细信息,请参阅 [IO] backend 和 threads 配置选项。
- 添加了一个新的mysqlrouter_plugin_info实用程序以帮助调试 MySQL 路由器插件。它提供插件版本、描述、ABI 版本、要求和函数指针等信息
更多关于MySQL Router的版本衍化,功能与特性,建议参考最新的官方文档
https://dev.mysql.com/doc/relnotes/mysql-router/8.0/en/news-8-0-35.html
https://dev.mysql.com/doc/relnotes/mysql-router/8.2/en/news-8-2-0.html
MySQL Router原理
MySQL Router一般承担着负载均衡,读写分离,故障转移功能,官方文档的架构图如下所示:
MySQL Router跟集群结合的架构图
MySQL Router可以作为MySQL InnoDB Cluster的一部分,也可以脱离InnoDB Cluster而单独实施,即MySQL 5.6等版本数据库仍然可以使用Router作为其中间代理曾,Router的核心原理为:
1、MySQL Router作为一个流量转发层,它的架构层面,位于Application与MySQL Servers之间。
2、其功能角色,类似于Nginx、LVS等,MySQL Servers作为Router的“upstream”(NAT模式);Application不再直连MySQL Servers,而是与Router相连。根据Router的配置,将会把应用程序的READ、WRITE请求转发给下游的MySQL Servers。
3、当下游有多个MySQL Servers,无论主、从,那么它可以对READ、WRITE请求进行负载均衡。(loadbalance)
4、当下游某个MySQL Server失效时,Router可以将其从Active列表中移除,当其online后再次加入Active列表,即提供了Failover特性。
5、当MySQL Servers集群拓扑变更时,比如增减Slaves节点,我们只需要修改Router的配置即可,无需修改Application中JDBC URL配置,因为Application配置的为Router地址而非MySQL Servers的原始地址;即“数据库集群迁移”对Application是透明的。
6、Router支持集中式部署,即一个Group通常有多个Router节点,但是MySQL官方并没有提供Router的HA,即Router每个节点均为独立,它们之间互不通信,无Leader角色,无选举机制。那么当某个Router节点失效,Application层面需要借助MySQL Connector的高级特性,比如:failover、loadbalance等协议来实现Failover功能。简单而言,Router中间件与Connector的高级协议互相协作,才能够实现请求在Router集群之间的负载均衡、Failover等。
7、Router中间件,本身不会对请求“拆包”(unpackage),所以我们无法在Router中间件上实现比如“SQL审计”、“隔离”、“限流”、“分库分表”等。但是Router提供了plugin机制,你可以开发自己的plugin来扩展Router的额外特性。(C语言)
8、如果你的MySQL Servers为5.7+版本,且构建为InnoDB Cluster模式,那么Router还能基于metaCache(metaServers)机制,感知MySQL Servers的主从切换、从库增减等集群拓扑变更,而且基于变更能够实现Master自动切换、Slaves列表自动装配等。比如Master失效后,Cluster将会自动选举一个新的Master,此时Router不需要任何调整、可以自动发现此新Master进而继续为Application服务。
9、考虑到Router集中式部署可能引入“额外的部署成本”、“性能降级”、“连接数上限”等问题,我们通常建议大家基于“Agent”方式部署,即部署在Application宿主机器上,潜在的问题就是自动化运维设施需要即备。
10、Router通常是解决“MySQL集群规模性迁移”:比如跨机房部署、流量迁移、异构兼容,或者解决MySQL集群规模性宕机时快速切换等。如果仅仅是为了解决日常的节点增减、读写分离、Failover等,我们仍然建议使用mysql-connector-j支持的“replication”、“loadbalance”协议来实现,基于客户端,而且轻量级。
注释:上面这部分原理介绍摘抄自Mysql Router核心原理及优缺点总结[1]
MySQL Router的配置文件中,通过参数参数mode控制MySQL Router的调度,只有两个参数,一个read-write,一个read-only。对于read-write模式,它一般采用“首个可用”(first-available)算法,优先使用列表中第一个MySQL Server,当第一个MySQL Server不可达时,将会转而访问列表中第二个MySQL Server,依次进行,如果参数列表中所有Server都不可访问,那么此端口上的请求将会中断,此端口将不能提供服务,早期版本中,此算法只遍历一次列表,即逐个验证列表中的Server,不会循环。一旦所有的Servers依次验证且不可用后,本条路由策略将不能继续服务,内置状态设定为aborted,即使此后MySQL Servers恢复上线,也不能继续对Client提供服务,因为它不会与Servers保持心跳检测。对于Router而言,直接拒绝Client连接请求,只有重启Router节点才能解决。从MySQL Router 8.0.29开始,它提供了参数unreachable_destination_refresh_intervalc参数,它用来控制多少秒后,重新检测那些无法访问的MySQL Server,也就是说Router会循环访问列表中的Server,不会只循环一次了。到了MySQL Router 8.0.32,又新增了参数error_quarantine_interval和error_quarantine_threshold来替换unreachable_destination_refresh_intervalc参数。
对于read-only模式:MySQL Router采用“轮询”算法,依次选择Server新建连接,如果某个Server不可达,将会重试下一个Server,如果所有的Server都不可达,那么此端口上的请求将中断,即读操作将不可用。同时Router将会持续与每个Server保持心跳探测,当恢复后重新加入Active列表,此后那些新建连接请求将可以分发给此Server。
当前官方文档关于mode参数的选项有4个,具体如下所示:
• round-robin:为了实现负载均衡,每个新连接都以循环方式与下一个可用服务器建立连接。
• round-robin-with-fallback:为了实现负载均衡,每个新连接都以循环方式与下一个可用的辅助服务器建立连接。如果辅助服务器不可用,则主列表中的服务器将以循环方式使用。
• first-available:新连接被路由到列表中的第一个可用服务器。如果发生故障,则使用下一个可用的服务器。这个循环一直持续到所有服务器都不可用。
• next-available: 和first-available一样 ,因为新连接被路由到列表中的第一个可用服务器。与first-available不同的是,如果服务器被标记为无法访问,那么它将被丢弃并且永远不会再次用作目的地
此策略向后兼容 MySQL Router 2.x 模式的读写行为。其限制包括:
• 列表中所有节点被抛弃后,无法重新将服务器添加回列表中。与其他策略不同的是,它不会每error_quarantine_interval秒去探测无法到达的服务器的可用性。
• 重新启动MySQLRouter后,所有那些被Router丢弃/抛弃的服务器的信息都将丢失,并且所有服务器都将再次重新可用。
• 元数据缓存不支持next-available路由策略,因为next-available功能使用静态路由
MySQL Router安装
MySQL Router对操作系统有一些基本要求:
- Hardware:最低要求是 1 个 CPU 核心和 256 MB 的内存;建议使用 4+ CPU 内核和 4+ GB 的内存。
- Disk Space: 最低要求是 100 MB。
- External libraries:大多数外部依赖项,例如 protobuf 和 rapidjson,都捆绑在 MySQL Router 包中。一个例外是 OpenSSL,它仅为 Windows 版本捆绑。包管理器应解决 OpenSSL 依赖关系并根据需要安装正确的 OpenSSL 版本。
MySQL Router安装有源码安装,二进制包安装、yum或apt安装方式。安装方式也没有什么太大的优劣之分,一般选择自己习惯或喜欢的安装方式。
下面这里简单介绍一下二进制包安装方式,其它方式的安装都非常简单。
1:解压安装介质
$ cd /data/soft
$ tar xvf mysql-router-8.0.35-linux-glibc2.28-x86_64.tar.xz -C /opt/mysql
$ cd /opt/mysql/
$ ln -s mysql-router-8.0.35-linux-glibc2.28-x86_64/ router
2:环境变量设置
编辑 ~/.bash_profile文件,加入下面配置(根据实际情况调整)
export PATH=$PATH:/opt/mysql/router/bin
执行source ~/.bash_profile 命令使之生效。
3:验证是否安装成功。
$ mysqlrouter –help
其它方式的安装更简单,如下所示:
Yum方式安装
$ sudo yum install mysql-router
APT方式安装
$ sudo apt-get install mysql-router
Yum本地方式安装
$ sudo yum localinstall xxxx
MySQL Router配置
MySQL Router参数
如果是手工配置MySQL Router的化,需要手工配置mysqlrouter.conf,如果是bootstrap模式的化,则会自动配置参数,虽然不用了解MySQL Router中的每一个参数,但是我们还是必须了解一些基本的参数,方便管理和深入理解MySQL Router,当然,更多详细参数建议阅读官方文档。
[DEFAULT]
# 日志文件存放的位置/目录
logging_folder = /data/mysql-router/logs
# MySQL Router插件的位置/目录
plugin_folder = /data/mysql-router/lib/mysqlrouter
# MySQL Router配置文件存放的位置/目录
config_folder = /data/mysql-router/conf
# MySQL Router运行时数据目录
runtime_folder = /var/run
# MySQL Router数据文件目录
data_folder = /data/mysql-router/data
# MySQL Router
keyring_path = /var/lib/keyring-data
master_key_path = /var/lib/keyring-key
[logger]
# MySQL Router日志级别
level = INFO
# 日志文件名称
filename = mysqlrouter.log
# 日志时间戳精度
timestamp_precision = second
# 主节点故障转移配置
[routing:basic_failover]
# To be more transparent, use MySQL Server port 3306
# 绑定IP地址
bind_address = 192.168.7.101
# 写节点的端口
bind_port = 7001
routing_strategy = first-available
# 模式为读写模式
mode = read-write
# 主节点地址:可以配置一个或多个,建议配置多个,因为主库有可能会宕机或切换,Router则会依次查找
destinations = 192.168.7.103:3306,192.168.7.104:3306, 192.168.7.105:3306
# 从节点负载均衡配置
[routing:secondary]
# 绑定IP地址
bind_address = 192.168.7.102
# 监听端口
bind_port = 7002
# 连接超时时间设置
connect_timeout = 3
# 最大连接数设置
max_connections = 1024
# 后端MySQL Server
destinations = 192.168.7.104:3306, 192.168.7.105:3306
routing_strategy = round-robin
# 模式为只读模式
mode = read-only
也可以使用下面这样的配置
[routing:primary]
# Router的绑定地址
bind_address = 192.168.7.101
# Router监听端口
bind_port = 7001
# MySQL服务器
destinations = 192.168.7.103:3306,192.168.7.104:3306, 192.168.7.105:3306
# 路由策略
routing_strategy = first-available
# 模式:读写模式
mode = read-write
# 连接超时时间设置
connect_timeout=6
[routing:secondary]
# Router的绑定地址
bind_address = 192.168.7.102
# Router监听端口
bind_port = 7002
# MySQL服务器
destinations = 192.168.7.104:3306, 192.168.7.105:3306
# 路由策略
routing_strategy = round-robin
# 模式:只读模式
mode = read-only
# 连接超时时间设置
connect_timeout=6
MySQL Roouter的配置/部署主要有下面两种种方式,这里简单介绍一下。
简单模式:
简单模式不支持failover,无需结合InnoDB Cluster使用(其实也可以用于MGR等),可用于MySQL主从模式. 一般需要手工配置参数。你可以从安装路径下找一个模板或者你自己定义的模板,根据实际情况配置相关参数
例如,sample_mysqlrouter.conf位于下面安装路径:
/opt/mysql/mysql-router-8.0.35-linux-glibc2.28-x86_64/share/doc/mysqlrouter
cp sample_mysqlrouter.conf /data/mysql-router/conf/mysqlrouter.conf
启动MySQL Router:
$ nohup mysqlrouter --config=/data/mysql-router/conf/mysqlrouter.conf &
bootstrap模式bootstrap模式支持failover,但是必须结合InnoDB Cluster使用,在--directory指定的路径下自动生成安装目录,配置文件里的端口为6446和6447
前提条件:InnoDB Cluster已经配置好(MGR),MySQL Shell已经安装。
初始化:
mysqlrouter --bootstrap icadmin@xxxx:3306 --directory /data/mysqlrouter --account router --user mysql --name gsprouter --conf-bind-address="xxx.xxx.xxx.xxx" --account-host="xxx.xxx.xxx.%" --force-password-validation
下面这里使用一个简单的例子
$ mysqlrouter --bootstrap icadmin@mysqldb01:3306 --directory /data/mysqlrouter --name='gsprouter' --force-password-validation
Please enter MySQL password for icadmin:
# Bootstrapping MySQL Router 8.0.35 (MySQL Community - GPL) instance at '/data/mysqlrouter'...
- Creating account(s) (only those that are needed, if any)
- Verifying account (using it to run SQL queries that would be run by Router)
- Storing account in keyring
- Adjusting permissions of generated files
- Creating configuration /data/mysqlrouter/mysqlrouter.conf
# MySQL Router 'gsprouter' configured for the ClusterSet 'yicticcset'
After this MySQL Router has been started with the generated configuration
$ mysqlrouter -c /data/mysqlrouter/mysqlrouter.conf
ClusterSet '*****' can be reached by connecting to:
## MySQL Classic protocol
- Read/Write Connections: localhost:6446
- Read/Only Connections: localhost:6447
## MySQL X protocol
- Read/Write Connections: localhost:6448
- Read/Only Connections: localhost:6449
上面命令初始化MySQL Router时,没有指定参数—account的话,初始化会在数据库创建一个账号给MySQL Router使用。所以一般建议指定账号名。
bootstrap模式初始化MySQL Router时,它会在参数—directory指定目录下生成下面文件夹或文件。自动帮你配置了参数文件mysqlrouter.conf
$ tree
.
├── data
│ ├── ca-key.pem
│ ├── ca.pem
│ ├── keyring
│ ├── router-cert.pem
│ ├── router-key.pem
│ └── state.json
├── log
│ └── mysqlrouter.log
├── mysqlrouter.conf
├── mysqlrouter.key
├── mysqlrouter.pid
├── run
├── start.sh
└── stop.sh
3 directories, 12 files
MySQL Router启动/关闭
启动MySQL Router的方式有多种,如下所示:
1:start.sh脚本启动
bootstrap模式引导的MySQL Router都会生成start.sh和stop.sh脚本,可以用start.sh启动MySQL Router
$ /data/mysqlrouter
$ sh start.sh
2:mysqlrouter脚本启动
$ mysqlrouter --config=/data/mysql-router/conf/mysqlrouter.conf &
3:服务启动
$ sudo service mysqlrouter start
或
$ sudo systemctl start mysqlrouter.service
当然,不管是用service或systemd启停MySQL Router,我们都必须配置,我们以systemd服务为例,我们编辑配置/usr/lib/systemd/system/mysqlrouter.service
[Unit]
Description=MySQL Router
After=syslog.target
After=network.target
[Service]
Type=simple
User=mysql
Group=mysql
PIDFile=/data/mysqlrouter/mysqlrouter.pid
ExecStart=/opt/mysql/router/bin/mysqlrouter -c /data/mysqlrouter/mysqlrouter.pid
Restart=on-failure
PrivateTmp=true
[Install]
WantedBy=multi-user.target
然后执行下面命令
# systemctl daemon-reload
# systemctl enable mysqlrouter.service
# systemctl status mysqlrouter.service
# systemctl start mysqlrouter.service
启动MySQL Router后,可以通过下面命令查看/验证其监听端口是否开启。
$ netstat -ntlp |grep mysqlrouter
$ ps -ef | grep mysqlrouter | grep -v grep
MySQL Router的关闭
1:stop.sh脚本关闭
$ sh stop.sh
2:kill命令关闭
$ ps -ef | grep mysqlrouter | grep -v grep #找到mysqlrouter进程
$ kill xxxx
3:服务关闭
$ sudo service mysqlrouter stop
或
$ sudo systemctl stop mysqlrouter.service
MySQL Router功能测试
Router读写分离测试
端口6446对应RW端口
$ for ((i=0;i