ACMUG征集原创技术文章。详情请添加 A_CMUG或者扫描文末二维码关注我们的。有奖征稿,请发送稿件至:[email protected]。3306现金有奖征稿说明:知识无价,劳动有偿,ACMUG特约撰稿人有奖回报计划(修订版)
作者简介:周晓
13年开始TP-LINK做了2年Oracle DBA和系统运维工作。目前在六度人和科技任MySQL DBA,先后两次主导数据库整体迁移,帮助开发优化了大量SQL、提供结构设计建议,并组织培训。工作平时在工作中遇到的一些问题和处理经验,有空会写写放在个人博客上,也会在里面分享一些Python写的工具。
MySQL的高可用方案现在如 MHA, Galera, InnoDB Cluster,一旦在上游使用中间件之后,中间件本身可能成为单点。所以本文要介绍的是对于ProxySQL自身高可用的方案对比。首先ProxySQL自身是通过Angel进程的形式运行,即proxysql如果有崩溃,主进程会自动拉起来。但如果是无响应或者网络故障,则需要另外的机制去做到服务的高可用。本文总结了四种方法。
ProxySQL有关介绍,请参考: /2017/04/10/mysql-proxysql-install-config/
目录
1. 与应用一起部署
所有部署应用的地方,都会部署proxysql节点,当这个proxysql挂掉之后,只影响本机的应用。而且不需要多经过一层网络。但带来的问题是,如果应用节点很多,proxy的数量也会增加:
会导致proxysql的配置不容易管理
proxysql对后端db健康检查的请求成倍增加
限制每个用户或后端db的 max_connections 特性用不了
2. 集中式部署,多ip引用
后端一个db集群,对应中间两个以上的 proxysql 节点,前端应用配置多个ip地址,随机挑选一个使用,完全无状态。仅需要多经过一次网络代理。这种方式的好处是,不需要再对数据库这种基础服务,多引入一个软件来实现高可用(如下节的keepalive或consul),由应用端获取数据库连接的代码逻辑处理。
但是因为proxysql访问地址是写在配置文件里面的,如果一个节点挂掉,随机挑选还是会落地这个失败的节点。所以优化方案是,ip列表里面默认取某一个,失败之后再选取下一个重试。
示例代码:
python proxysql_addr_list = [192.168.1.175, 192.168.1.176, 192.168.1.177] proxysql_addr_list_len = 3 hostname = this_hostname_for_hash_loadbalance def get_dbconnection(): list_index = hash(hostname) % proxysql_addr_list_len dbconn = None try: dbconn = DBConnect(dbhost=proxysql_addr_list[ list_index ], dbport=3306) # timeout 1000ms except: if (list_index + 1) == proxysql_addr_list_len: list_index = -1 # like Circular Array dbconn = DBConnec(dbhost=proxysql_addr_list[ list_index + 1 ], dbport=3306) # if failed again, through exception return dbconn上述并不完美,比如可以改用环形数组轮巡,允许重试其它更多的ip。
能不能不进行多IP引用呢?
为了避免后端引用IP的单点,可以将上面第1种和这里的第2中结合起来,改进的部署方案:(见文后参考链接)即在原来的基础上,App上的proxysql后端,挂的还是ProxySQL集群。
我个人没有验证这样的方案,如果要用需要充分验证proxysql互连的时候,有没有bug。
3. 经典 keepalived
引入keepalived,通过VIP访问两个以上的proxysql节点,既可以减少一次网络传输,又可以实现proxysql自身的高可用,而且甚至不用关心脑裂的问题,因为proxysql配置完全一样,是无状态的,脑裂了也无妨。你也可能意识到,这种方式一次只能一个proxysql提供服务,另一个proxysql节点始终处于备用状态。如果配合LVS或haproxy做负载均衡,部署架构又会多出一层网络请求,而且越发复杂(VIP不在proxysql节点上漂,而是在两个lvs之间)。使用keepalived的前提是,局域网允许发组播包。这在阿里云ECS经典网络下是不允许的,如果有其它类似方式,如SLB也是可行的。目前测试环境采用是 haproxy + keepalived 的方式。
4. Consul服务发现
如果上面的方式都不适用,那么可以进一步考虑使用第三方的服务发现组件。
4.1 介绍
Consul用于实现分布式系统的服务发现与配置,我们将所有proxysql节点注册到consul上作为一个服务来提供,由 Consul agent Server 来判断proxysql节点的存活,每个应用节点上都安装 Consul agent Client 来供应用获取可用地址。这样部署架构的好处是:
不需要多一层负载均衡,多一层网络链路
不需要部署大量的proxysql节点
App或者ProxySQL节点上的Consul故障,不影响其它节点。Consul Server集群的天生具备高可用
ProxySQL故障会被Consul检查到,踢除故障节点,并通知给所有consul agent
可以利用Consul的DNS接口实现简单的负载均衡
其实consul所做的与本文第2节的类似:自动提出不可用的节点,只是一个是被动、手动,一个是主动、自动。下面简单演示一下。
4.2 部署示例
Consul Server节点的安装在此略过,网上有不少文章,直接进入到在ProxySQL节点安装配置Consul。
Consul agent:
apps-1: 10.0.201.168
apps-2: 10.0.201.220
apps-3: 10.0.201.156
ProxySQL node:每个节点上运行了两个proxysql进程 7033: crm0, 7133: crm1
proxysql-1 : 192.168.1.170
proxysql-2 : 192.168.1.171
配置 proxysql 节点上的Consul
配置 proxysql-1 节点上的Consul:
$ sudo vim /etc/consul.d/config.json { "data_dir": "/opt/consul", "datacenter": "Office_test", "log_level": "INFO", "node_name": "proxysql-1", "retry_join": [ "10.0.201.168", "10.0.201.220", "10.0.201.156" ], "telemetry": { "statsd_address": "10.0.201.34:8125", "statsite_prefix": "proxysql-1" }, "dns_config": { "only_passing": true } "acl_datacenter": "Office_test", "acl_default_policy": "deny", "encrypt": "XXXXxxxx==" } $ sudo vi /etc/consul.d/proxysql.json {"services": [ { "id": "proxysql_crm0", "name": "proxysql", "address": "192.168.1.170", "port": 7133, "tags": ["test", "crm0"], "check": { "interval": "5s", "tcp": "192.168.1.170:7033", "timeout": "1s" }, "enableTagOverride": false, "token": "xxxxxxxx-xxxx" }, { "id": "proxysql_crm1", "address": "192.168.1.170", "name": "proxysql", "port": 7133, "tags": ["test", "crm1"], "check": { "interval": "5s", "tcp": "192.168.1.170:7133", "timeout": "1s" }, "enableTagOverride": false, "token": "xxxxxxxx-xxxx" } ]}启动consul
sudo consul agent -config-dir /etc/consul &查看日志
proxysql-2 节点上的Consul配置根据上面的内容去改。
4.4 使用方式
先来看下效果:
[root@proxysql-1 ~]# dig @127.0.0.1 -p 8600 crm0.proxysql.service.consul SRV ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.62.rc1.el6_9.2 <<>> @127.0.0.1 -p 8600 crm0.proxysql.service.consul SRV ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65293 ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 2 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;crm0.proxysql.service.consul. IN SRV ;; ANSWER SECTION: crm0.proxysql.service.consul. 0 IN SRV 1 1 7033 proxysql-1.node.office_test.consul. crm0.proxysql.service.consul. 0 IN SRV 1 1 7033 proxysql-2.node.office_test.consul. ;; ADDITIONAL SECTION: proxysql-1.node.office_test.consul. 0 IN A 192.168.1.170 proxysql-2.node.office_test.consul. 0 IN A 192.168.1.171 ;; Query time: 3 msec ;; SERVER: 127.0.0.1#8600(127.0.0.1) ;; WHEN: Fri May 26 17:01:38 2017 ;; MSG SIZE rcvd: 157看到域名 crm0.proxysql.service.consul 解析出来有两个可用地址 192.168.1.170,192.168.1.171,SRV记录还带出了端口信息(其实这里的端口对每个proxysql是固定/已知的,所以可不用SRV记录搜索)。
在应用端想要连接proxysql使用的方式大致有3种:
DNS接口
需要将各自开发语言的DNS解析库嵌入到项目,指定 127.0.0.1:8600 为dns地址来解析上面的 crm0.proxysql.service.consul 域名。这种方式会增加开发的复杂度。
另一种方式是将应用服务器的默认DNS Server配置成本地consul的内置dns地址,并且consul设置 recursors 选项,来处理解析 consul. 以外的域名。这样对运维改动比较大。
"recursors": [ "10.143.22.116", "10.143.22.118", "114.114.114.114" ]HTTP接口
通过 API 的方式获取services信息:
$ curl -X GET :8500/v1/health/service/proxysql?tag=crm1&passing=true可以获取到 crm1 库的proxysql所有健康的 Node 和 Service 信息,然后任取一个使用。
但并不需要每一次访问proxysql都需要请求api,可以定时(如每隔10s)去请求,缓冲在本地或者变量里;在处理数据库连接的时候发现连接ProxySQL错误,则再主动触发一次向Consul请求新的地址,再重连。
需要考虑的是访问API的地址如果是IP,往往也是单点。另者,java这类jvm语言修改配置后往往需要重启,也不简单。
consul-template直接生成数据库连接的配置文件
consul-template通过事先定义好的模板,根据发现服务的健康状态,生成最新可用的配置文件,然后下发。
如果大但的想一下,各个服务或者语言的配置文件并不相同,直接生成一份 hosts 文件是最简单的,然后通过配置管理工具统一下发应用。也不需要关心是否需要重启应用。
consul watchConsul watch 功能,可以检测到service变化之后,主动调用一个脚本,脚本可以去更新数据库配置信息,根据需要决定是否重启,后者生成hosts。与consul-template思想是相同的。
因为 watch 是通过阻塞式HTTP长连接请求的方式,实时获取到service的监控状态,所以有问题时反馈还比较及时。
"watches":[{ "type": "service", "service": "proxysql", "tag": "crm0", "passingonly": true, "handler": "sh /tmp/consul_watch_test.sh" }]/tmp/consul_watch_test.sh 脚本里或者python,可以做一些更新数据库配置文件、发送邮件等工作。
参考
https://www.percona.com/blog/2016/09/16/consul-proxysql-mysql-ha/
https://www.percona.com/blog/2017/01/19/setup-proxysql-for-high-availability-not-single-point-failure/
https://www.slideshare.net/DerekDowney/proxysql-tutorial-plam-2016 (本文部分图片出自该PPT)
注:ACMUG收录技术文章版权属于原作者本人所有。如有疑问,请联系作者。看完转发,手留余香。关注我们,一起进步。
关注ACMUG,参与社区活动,交流开源技术,分享学习心得,一起共同进步。