网易cetus初探--读写分离
Posted 破产DBA
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网易cetus初探--读写分离相关的知识,希望对你有一定的参考价值。
什么是cetus?
前段时间淘宝买了个贴纸,觉得这个飞上天的鲸鱼很漂亮,后来查到这货是“鲸鱼座”,在与网易女神确认了这货原来有个英文名字--“cetus”,于此便有了后来的cetus的测试与使用。
cetus是由网易乐得DBA团队用C语言开发的一款mysql中间件,提供了读写分离和分库两个版本,应用程序可几乎不做修改透明的通过cetus访问数据库群集,实现数据库的高可用以及水平扩展。
笔者通过将近一周的深入体验,各种场景折腾,各种压力测试,发现这款中间件产品的是非常不错的, 在与cetus成员交流的过程也感受到了 :他们是一群对技术要求极致,乐于分享的团队,每每遇到问题,都能在第一时间得到解答,非常NICE! cetus团队没有止步在仅仅是对外宣讲cetus,他们也在用实际行动帮助用户使用落地,看产品好坏,很大一部分还需要看这个团队是否都有一致的方向及热情, 这勾起了我很大的兴趣,毕竟这样的太少了!最近一段时间加强了cetus测试工作,发现cetus有很多独特的地方,配置简单,日志详尽,可在线修改配置,对SQL类型支持多,在读写分离模式下几乎能在不修改应用的情况直接运行,能在硬件资源较小的情况下依然能稳定运行等等...总之这是一款可以信赖的产品。
cetus版本分为读写分离和分库版本,在安装,配置与使用上有些区别,本次测试使用的读写分离版本。
cetus读写分离能做什么
提到cetus就不得不提cetus读写分离版本能实现的主要功能了:
连接池;
在Cetus启动时,使用默认用户自动创建到后端的连接,请求过来不需要临时建立连接并切换数据库,提升效率。
读写分离;
cetus能结合sql解析,根据分流策略将查询发到后端的只读从库上,从而减少主库查询负载,提升系统性能,开启监控后,可以配置参数slave-delay-down和slave-delay-recover,自动将从库状态down或up,而不影响系统的整体可用性。
TCP流式;
这是cetus很大一个卖点,cetus对内存的需求很小,对于结果集比较大的查询,cetus采用tcp stream流式,不需要先缓存完整结果集才转发给客户端,以避免内存炸裂问题,降低内存消耗,提高性能。
状态监控;
开启监控功能后,Cetus会定期和后端进行通信,检测后端数据库的存活状态和主从延迟时间等。可通过登录管理端口SELECT * FROM backends查看。
动态修改cetus参数;
cetus开放了管理端口,可动态修改cetus各项参数,无需重启服务即可完成。
综上:通过cetus我们能实现数据库端的透明访问,并通过读写分离,从库状态自动启停来实现负载均衡及改善后端数据库高可用,让DBA省心,让开发无忧。
cetus架构图示
前端应用通过连接访问cetus群集(使用LVS实现,实际可考虑部署到数据库节点上),后端mysql可以使用MHA或MGR架构实现高可用,再通过cetus实现数据库的读写分离透明访问。
cetus读写分离版本安装
安装前的准备工作
修改linux 最大文件限制数:
echo ulimit -n 65535 >>/etc/profile
source /etc/profile #加载修改后的profile
ulimit -n #显示65535,修改完毕!安装依赖包
yum install cmake gcc glib2-devel flex mysql-devel gperftools-libs -y安装cetus
下载安装包
mkdir cetus cd cetus git clone https://github.com/Lede-Inc/cetus.git源码编译
mkdir build/ cd build/ CFLAGS='-g -Wpointer-to-int-cast' cmake ../ \ -DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_INSTALL_PREFIX=/usr/local/cetus \ -DSIMPLE_PARSER=ON make install
注意事项及关键参数:
cmake ../ 这里../是指上一层,如果指定错了将无法继续
CFLAGS='-g -Wpointer-to-int-cast' 在可执行程序中包含标准调试信息,
CMAKE_BUILD_TYPE变量可以选择生成 debug 版和或release 版的程序,
CMAKE_INSTALL_PREFIX变量确定软件的实际安装目录的绝对路径,
SIMPLE_PARSER变量确定软件的编译版本,设置为ON则编译读写分离版本,否则编译分库版本。
读写分离版本配置
后端数据库配置架构
本次仅做功能性验证,故在笔记本上创建了1个虚拟机,上面部署两个数据库实例做主从,同时cetus也运行在这个虚机上。
由于cetus需要监控主从延迟时间,使用的方法是不停的在主库写入当前时间,然后到从库查询时间,比较时间差异,原理上类似pt-heart工具,在运行前需要创建对应的数据库及表,否则cetus的监控及从库自动上下线无法使用。
create database proxy_heart_beat;use proxy_heart_beat;
CREATE TABLE `tb_heartbeat` (
`p_id` varchar(128) NOT NULL,
`p_ts` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
PRIMARY KEY (`p_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
创建cetus连接的而用户cetus_app,加上所有库的权限,特别注意别忘了把心跳表的权限也加上:
GRANT ALL PRIVILEGES ON `proxy_heart_beat`.* TO 'cetus_app'@'%'
cetus用户密码参数文件配置:users.json
此文件记录的是后端数据库连接使用的用户和密码,以及对应的cetus对外提供访问使用的密码
[root@mysql-node1 cetus]# cd /usr/local/cetus[root@mysql-node1 cetus]# cat conf/users.json
{ "users":
[{
"user": "cetus_app",
"client_pwd": "cauUAX123321",
"server_pwd": "cauUAX123321"
}]
}
cetus变量处理配置文件参数文件配置:variables.json
配置允许发送的值和静默处理的值,一般无需配置,默认即可
[root@mysql-node1 cetus]# cat conf/variables.json
{ "variables": [
{ "name": "sql_mode",
"type": "string-csv",
"allowed_values": ["STRICT_TRANS_TABLES", "NO_AUTO_CREATE_USER", "NO_ENGINE_SUBSTITUTION"]
},
{ "name": "connect_timeout",
"type": "string",
"allowed_values": ["*"],
"silent_values": ["10", "100"]
}
]
}
cetus启动配置文件:proxy.conf
这是最关键的读写分离版本的启动配置文件,在启动Cetus时需要加载,关键的参数以及在以下代码中注明
[root@mysql-node1 cetus]# cat conf/proxy.conf
[cetus]
# 是否通过守护进程启动
daemon = true
# Loaded Plugins
plugins=proxy,admin
# 定义启动进程数量,建议配置成cpu核数
worker-processes=8
#启动tcp stream,无需等响应收完就发送给客户端
enable-tcp-stream= true
# cetus对外服务端口及后端主从数据库配置
proxy-address=0.0.0.0:6001
proxy-backend-addresses=10.231.34.195:3306
proxy-read-only-backend-addresses=10.231.34.196:3306
# cetus管理端口及用户名和密码
admin-address=0.0.0.0:7001
admin-username=admin
admin-password=admin123
#默认数据库,用户名
default-db=cetus
default-username=cetus_app
#初始连接池及最大连接池大小,需要注意的是这个参数是针对每1个cetus进程而言的
#比如当前配置:8进程*50=400 意味着cetus一启动就需要申请400个连接
#最大连接配置:8进程*400=3200 意味着后端数据库至少要配置比3200还要多的数据库连接参数才不会报错
default-pool-size=50
max-pool-size=400
#自动减少空闲连接,后端连接最大存活时间默认是2小时,现修改为1小时
reduce-connections=true
max-alive-time=3600
#每个后端返回结果集的最大数量
max-resp-size=10485760
#慢查询日志阈值(毫秒)
long-query-time=1000
#读写比例,主库50%,从库50%(所有的从库一起算)
read-master-percentage=50
max-open-files= 65536
plugin-dir=lib/cetus/plugins
log-level=debug
#以下两项要特别注意:
#一定要与服务的脚本文件里参数一致,否则服务启动会报错
#开启debug模式的cetus生成的日志文件量还是挺可观的,如果必须,一定要配置到容量大,速度快的磁盘上面
pid-file =cetus6001.pid
log-file=/lhdata/cetus/cetus_6001.log
#从库延迟及下线阈值时间设置
disable-threads=false
check-slave-delay=true
slave-delay-down=60
slave-delay-recover=1
# 当Proxy进程意外终止,会自动启动一个新进程
keepalive=true
verbose-shutdown=true
log-backtrace-on-crash=true
特别要注意的是cetus参数文件proxy.conf一定要设置成660才能启动,否则报错
chmod 660 proxy.conf
手动启动cetus
bin/cetus --defaults-file=conf/proxy.conf
cetus配置系统服务
#进入cetus源码文件夹
[root@mysql-node1scripts]# cd cetus-master/scripts/
[root@mysql-node1scripts]# cp cetus.service /etc/init.d/cetus
#修改关键参数,CETUS_HOME,CETUS_PID,CETUS_LOG一定要与实际配置成一致
[root@mysql-node1scripts]# vim /etc/init.d/cetus
#!/bin/bash
# chkconfig: - 30 21
# description: Cetus service.
# Source Function Library
./etc/init.d/functions
STARTTIMEOUT=12
STOPTIMEOUT=60
# Cetus Settings
CETUS_HOME=/usr/local/cetus
CETUS_CONF=${CETUS_HOME}/conf/proxy.conf
CETUS_SBIN=${CETUS_HOME}/bin/cetus
CETUS_PID=${CETUS_HOME}/cetus6001.pid
CETUS_LOG=/lhdata/cetus/cetus_6001.log
CETUS_EXEC=${CETUS_HOME}/libexec/cetus
CETUS_DAEMON="0"
...
#现在就可以通过服务的方式启动,关闭cetus了
[root@mysql-node1scripts]# service cetusstatus
Usage:/etc/init.d/cetus {start|stop|restart}
cetus使用测试
启动关闭
#cetus启停
[root@mysql-node1 scripts]# service cetus stop
Stopping cetus (via systemctl): [ OK ]
[root@mysql-node1 scripts]# service cetus start
Starting cetus (via systemctl): [ OK ]
#cetus端口确认,服务端口6001,管理端口7001
[root@mysql-node1 scripts]# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:6001 0.0.0.0:* LISTEN 21038/cetus
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 4452/sshd
tcp 0 0 0.0.0.0:7001 0.0.0.0:* LISTEN 21032/cetus
tcp 2 0 127.0.0.1:32000 0.0.0.0:* LISTEN 2671/java
tcp6 0 0 :::3306 :::* LISTEN 3314/mysqld
#可以看到,已经启动了9个cetus,为什么会比配置的8个多1个呢?,因为多了1个cetus守护进程
[root@mysql-node1 scripts]# ps -ef | grep cetu[s]
root 21032 1 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21033 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21034 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21035 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21036 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21037 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21038 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21039 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
root 21040 21032 0 16:42 ? 00:00:00 /usr/local/cetus/libexec/cetus --defaults-file=/usr/local/cetus/conf/proxy.conf
简单SQL测试
打开后端数据库的general_log参数,查看最终在哪个实例上执行
--进入客户端mysql -h 192.168.113.201 -P 6001 -ucuser -pXXX
---以下都在读库执行
cuser@6001(none) 12:19:05>use cetus
Database changed
cuser@6001cetus 12:19:10>show tables;
+-----------------+
| Tables_in_cetus |
+-----------------+
| test |
+-----------------+
1 row in set (0.01 sec)
cuser@6001cetus 12:19:14>select * from test;
#所有写操作都会在主库执行#这里发现写操作后第1个select也会优先在主库上执行,后续都会在从库执行
cuser@6001cetus 12:19:33>insert into test values(4);
Query OK, 1 row affected (0.01 sec)
--insert后第一次select在主库
cuser@6001cetus 12:19:38>select * from test;
--insert后第二次在从库执行
cuser@6001cetus 12:19:45>select * from test;
#只要是显示指定了事务,事务必在主库执行
cuser@6001cetus 12:22:47>begin ;
cuser@6001cetus 12:24:23>select * from test where id=1;
cuser@6001cetus 12:24:31>select * from test2 where id=1;
cuser@6001cetus 12:24:37>commit;
#通过添加hints可以手动配置指定主库还是从库,需要在连接是加-c
##不过需要注意的是开启了显示事务后hints是无效的
mysql -h 192.168.113.201 -P 6001 -ucuser -papppw -c
select /*# mode=READWRITE */ id from test;
select /*# mode=READ */ id from test;
从库延迟测试
故意制造1个长更新,检查主从延迟超过60s后会发生什么
##cetus检测到从库超过阈值,自动将从库“逐出”
(pid=24449) 2018-12-08 08:35:05: (critical) Check slave delay no data:select p_ts from proxy_heart_beat.tb_heartbeat where p_id='/usr/local/cetus/conf_289583606_427107461'(pid=24449) 2018-12-08 08:35:05: (message) change backend: 10.231.34.196:3306 from type: readonly, state: down to type: readonly, state: down
(pid=24449) 2018-12-08 08:35:05: (critical) Slave delay 70.647 seconds. Set slave to DOWN.
主从延迟降低后,检查cetus判断:
#可以看到cetus自动将从库加入到cetus群集中,此时从库又可以被使用了!
(pid=24662) 2018-12-08 08:54:30: (message) change backend: 10.231.34.196:3306 from type: readonly, state: online to type: readonly, state: online
(pid=24661) 2018-12-08 08:54:30: (message) Slave delay 0.030 seconds. Recovered. Set slave to UP.
资源占用测试
通过使用sysbench对cetus进行长时间的只读,读写测试,发现对cpu和内存占用比想象中的要低很多。这样是不是也就意味着cetus可直接放到数据库服务器上运行了呢(穷的话)?
cpu占用图
内存占用图
总结
cetus性能优越,读写分离基本上能满足绝大部分场景需求,下一篇将对cetus基准压力测试做一个汇总,cetus很棒
以上是关于网易cetus初探--读写分离的主要内容,如果未能解决你的问题,请参考以下文章