引言
OceanBase 作为一款分布式关系型数据库,随着 Observer 集群的规模不断扩大,如果直连 ObServer,停机/上下线机器的概率也会随之增加, OBProxy 便是在这种情况下应运而生,以解决分布式数据库系统的 SQL 路由、高可用等问题。
OBProxy,全称为 OceanBase Database Proxy,是 OceanBase 数据库专用的服务代理。使用 OBProxy 可以屏蔽后端 ObServer 集群本身的分布式带来的复杂性,让访问分布式数据库像访问单机数据库一样简单。为此,我们筹划了高性能的数据访问中间件——OBProxy 专题,包括九篇文章,将从 OBProxy 的部署、原理、功能、架构、问题排查、最佳实践等方面一次性讲透,让你真正地对 OBProxy 知其然知其所以然。
上一篇文章是我们 OBProxy 系列文章的首篇,主要解读了 OBProxy 的功能模块和详细的特性,本章主要聚焦安装部署部分。实际使用中,大家通过 obdeploy 工具就会自动安装部署完成 OBProxy,本文我们将详细介绍背后的原理,并总结生产环境的安装部署经验,内容更偏实战,学习本文后大家无需通过 Obdeploy 工具就可以安装部署OBProxy,那么我们开始吧。
1 安装步骤
OBProxy 的安装十分简单,对硬件资源要求不高,一般不容易遇到问题。下面以流程图方式说明安装步骤:
1.1 检查安装环境
1.1.1 平台适配
OBProxy 推荐安装在 x86_64 平台和 arm 平台。目前,OBProxy 在 x86_64 平台运行最久、最稳定、性能表现最佳。近两年我们也测试发现 OBProxy在 arm平台可以很好的工作。当前,在蚂蚁集团生产环境,已经有一批OBProxy 运行在 arm 平台机器上了。
1.1.2 操作系统
OBProxy 当前支持 Linux 系统,暂不支持 Windows 系统和其它系统。对于 Linux 系统,OBProxy 的配置项enable_strict_kernel_release
控制对操作系统版本检查,检查不通过会导致启动失败,关键日志如下:
[2021-10-13 10:38:17.235062] WARN [PROXY] get_kernel_release_by_uname (ob_config_server_processor.cpp:1039) [2060][Y0-0] [lt=14] [dc=0] unknown uname release(uinfo.release="4.18.0-80.el8.x86_64", ret=-4016)
大家可以使用 uname 命令查看内核信息,该选项目前只允许 el 系列和 alios 系列通过,检查策略偏保守型,可能会产生一些误报。其它 linux 系统如果遇到上面问题,我们可以通过关闭该配置项予以解决。
1.1.3 硬件资源
OBProxy 启动成功后,CPU 占用 0.7c 左右,内存占用百余兆。当遇到请求流量后,CPU和内存使用会增加。
资源使用情况如下:
- CPU:随着请求量增加,CPU使用率会增加,QPS也会接近线性增加,直到CPU满负载,QPS会基本恒定。
- 内存:内存使用量主要和连接数有关,随着连接数增加,内存使用会变多,配置项
client_max_connections
会控制允许的客户端连接数,默认最多支持8192个客户端连接,超过该数值会导致客户端连接失败。 - 磁盘:磁盘主要用来存放配置文件和日志文件,其中日志文件对磁盘的使用比较多,当磁盘使用量超过80%后,OBProxy会主动清理日志文件。
1.2 选择合适版本
如果只是学习使用,一般安装最新的版本即可。如果是生产环境,建议大家关注下每个版本的功能迭代和 bugfix 情况。无论什么项目,阅读 Release Notes 是一个很好的习惯,可以帮助大家避坑和掌握每个版本的功能支持情况,做到心中有数。
OBProxy 的代码已经开源,在 OceanBase 开源项目中找到 OBProxy 项目,点击 Releases 可以查看每个版本的详细信息。OBProxy 每个版本都经过了功能测试、压力测试和性能测试,大家可以放心使用。
1.3 通过 Obdeploy 安装
Obdeploy 是我们推荐的社区安装工具,除了安装 ObServer,也会安装 OBProxy,默认会安装最新版本,如果安装前想指定 OBProxy 版本,需在配置文件中指定,配置文件中 OBProxy 的配置可参考下面内容:
obproxy-ce:
version: 3.2.3
# Set dependent components for the component.
# When the associated configurations are not done, OBD will automatically get the these configurations from the dependent components.
depends:
- oceanbase-ce
servers:
- 192.168.1.5
global:
listen_port: 2883 # External port. The default value is 2883.
prometheus_listen_port: 2884 # The Prometheus port. The default value is 2884.
home_path: /root/obproxy
# oceanbase root server list
# format: ip:mysql_port;ip:mysql_port. When a depends exists, OBD gets this value from the oceanbase-ce of the depends.
# rs_list: 192.168.1.2:2881;192.168.1.3:2881;192.168.1.4:2881
enable_cluster_checkout: false
# observer cluster name, consistent with oceanbase-ce's appname. When a depends exists, OBD gets this value from the oceanbase-ce of the depends.
# cluster_name: obcluster
skip_proxy_sys_private_check: true
enable_strict_kernel_release: false
# obproxy_sys_password: # obproxy sys user password, can be empty. When a depends exists, OBD gets this value from the oceanbase-ce of the depends.
# observer_sys_password: # proxyro user pasword, consistent with oceanbase-ce's proxyro_password, can be empty. When a depends exists, OBD gets this value
安装好后,可以通过obd cluster display
查看部署情况,参考下述例子。通过该命令我们可以看到OBProxy 信息,其中 port 2883 表示提供 SQL 服务的端口是2883,也就是 JDBC URL 中需要填写的 PORT。
[root@xx.xx.xx.xx obtest]$obd cluster display obtest
Get local repositories and plugins ok
Open ssh connection ok
Cluster status check ok
Connect to observer ok
Wait for observer init ok
+--------------------------------------------------+
| observer |
+----------------+---------+------+-------+--------+
| ip | version | port | zone | status |
+----------------+---------+------+-------+--------+
| 172.30.199.109 | 3.1.3 | 2881 | zone1 | active |
| 172.30.199.110 | 3.1.3 | 2881 | zone2 | active |
| 172.30.199.111 | 3.1.3 | 2881 | zone3 | active |
+----------------+---------+------+-------+--------+
Connect to obproxy ok
+--------------------------------------------------+
| obproxy |
+----------------+------+-----------------+--------+
| ip | port | prometheus_port | status |
+----------------+------+-----------------+--------+
| 172.30.199.109 | 2883 | 2884 | active |
+----------------+------+-----------------+--------+
1.4 安装后检查
上面命令obd cluster display
已经做了状态检查。使用终端登录到 OBProxy 进程所在机器,通过ps -ef | grep obproxy
命令查看进程信息。
[root@observer109 ~]# ps -ef | grep obproxy | grep -v grep
admin 6868 1 0 May20 ? 00:02:09 bash /home/admin/obproxy/obproxyd.sh /home/admin/obproxy 172.30.199.109 2883 daemon
admin 6901 1 0 May20 ? 00:44:11 /home/admin/obproxy/bin/obproxy --listen_port 2883
这里可以看到两个进程,obproxyd.sh 进程和 obproxy 进程。obproxy 就是 OBProxy 的进程名。obproxyd.sh是OBProxy 的守护脚本,负责启动 obproxy ,对 obproxy 做健康检查,如果 obproxy 进程不存在会主动拉起进程。
安装后,如果想确定 OBProxy 的版本,有三种方法:
- 新版本 OBProxy 的目录会带版本号,如 obproxy-3.2.3目录名表示3.2.3版本的 OBProxy
- 在 OBProxy 的目录下执行
./bin/obproxy -V
查看 - 使用 root@proxysys 账号登录后,执行
show proxyinfo binary
查看
方法 2 的结果如下,版本是 3.2.3:
[root@observer109 obproxy]# ./bin/obproxy -V
./bin/obproxy -V
obproxy (OceanBase 3.2.3 2)
REVISION: 6-local-99faebfc7130b70ad0f56330a28cab6a32ec9a33
BUILD_TIME: Mar 30 2022 01:53:08
方法 3 的结果如下,版本是 3.2.6:
MySQL [(none)]> show proxyinfo binary\G
*************************** 1. row ***************************
name: binary info
info: ObProxy-OceanBase 3.2.6-5902.el7
version:RELEASE_7U
MD5:
REVISION:5902-local-f6b6e366ce8ed7611a05c2fc4701c791f26e0356
BUILD_TIME:May 23 2022 09:19:44
2 目录介绍
安装完成后,除了查看进程信息,另一个比较重要的点是查看目录结构。进入到 OBProxy 目录下(一般为/home/admin/obproxy
),通过 ls 命令查看。
OBProxy 目录结构如下:
[root@observer109 obproxy]# ls -alrt
total 44
drwxrwxr-x 2 admin admin 4096 May 12 14:55 lib
drwx------ 8 admin admin 4096 May 12 14:55 ..
drwxrwxr-x 2 admin admin 4096 May 12 14:55 bin
drwxrwxr-x 2 admin admin 4096 May 12 14:57 sharding-config
drwxrwxr-x 2 admin admin 4096 May 12 14:57 control-config
drwxrwxr-x 2 admin admin 4096 May 12 14:57 log
drwxrwxr-x 2 admin admin 4096 May 12 14:57 run
drwxrwxr-x 10 admin admin 4096 May 20 13:43 .
-rw-r--r-- 1 admin admin 910 May 20 13:43 obproxyd.sh
drwxrwxr-x 2 admin admin 4096 May 20 13:44 .conf
drwxrwxr-x 2 admin admin 4096 May 23 17:27 etc
比较重要的目录和文件包括:
- bin目录:保存 obproxy 的二进制文件
- etc目录和 .conf 目录:保存配置信息,.conf 是 etc 的备份,如果etc目录被删除,会使用.conf中的内容
- sharding-config目录:保存sharding相关的配置文件
- log目录:保存日志文件的目录,磁盘占用最大,日志文件也分为多种,帮助排查定位问题
- obproxyd.sh:守护脚本,内容简单,大家可以通过阅读脚本代码了解实现原理
3 OBProxy 重启和退出
了解 OBProxy 的重启和退出机制,大家可以更灵活地使用 OBProxy,如进行版本升级、特性验证等。
OBProxy启动需要指定集群信息,有两种方式:
- 设置配置项
obproxy_config_server_url
,内容为 OCP 的地址,访问该地址可以获得集群信息 - 通过启动配置参数指定集群中机器的 IP 和 PORT,也叫做 rslist 方式,该方式只支持访问一个集群
接下来我们以 rslist 方式举例。
3.1 OBProxy 重启
本节内容我们不通过 Obdeploy 启动,直接通过二进制方式启动,大家通过 rpm 获取到 OBProxy 二进制后可以按照步骤操作,启动命令如下:
./bin/obproxy -p 2883 -r '192.168.1.1:2881' -c 'cluster1' -o enable_strict_kernel_release=false,work_thread_num=8
主要选项如下:
- -p:指定服务监听端口号,一般使用2883
- -r:此处使用的是 rslist 方式启动,直接指定 ObServer 的 IP 和 PORT,这里需要注意 ObServer 有一个 RPC端口和一个 SQL 端口,需要使用 SQL 端口,一般是 2881
- -c:访问的集群名字,对应 ObServer 进程的 -n 选项,也可以通过 SQL 查询 OceanBase 数据库获得集群名;如果通过 OBProxy 代理多个集群,只能使用指定 OCP 对应 URL 的方式
- -o:后面是配置项信息,可以首次启动指定,格式为
k1=v1,k2=v2
,和前面几个选项不同,此选项非必须
通过上面命令就可以启动 obproxy 进程了。需要注意的是,无论是使用 obproxy 二进制的绝对路径还是相对路径,都需要在 OBPRoxy 目录下执行上面命令。如果启动失败,前往 log/obproxy.log 文件中查看 WARN 和 ERROR 信息可很快定位问题。
第一次启动后,就会在etc和.conf目录下生成配置文件并将配置信息持久化,下次如果重新启动,直接执行./bin/obproxy
命令即可。
如果还想用默认配置,需要执行rm -rf etc .conf
删除持久化的配置信息,然后执行首次启动命令。
通过日志succ to init logger
可以确定启动时间,该日志只在启动时打印一次。
3.2 OBProxy 退出
OBProxy 进程退出后,obproxyd.sh 将在 1s 内重新拉起 OBProxy,有时根本察觉不到 OBProxy 退出过。在生产环境,该机制可以快速恢复服务,起到止血作用。
退出主要分为主动退出和异常退出两种情况。主动退出比较简单,目前无专门的运维命令,直接使用 kill 命令杀掉进程即可。
对于异常退出,常见的情况有三种:
-
内存使用太多:OBProxy 本身对内存使用做了限制,通过配置项
proxy_mem_limited
控制,默认为2G,内存使用超过该配置值后 OBProxy 会主动退出,这样好处是防止 OOM 情况。但坏处是如果大小设置不合理会导致系统有剩余内存,OBProxy 也会退出,可以通过在 obproxy.log 中搜索memroy is out of limit
确定是这种情况。 -
进程core掉:通过 dmesg 命令和在 core 文件目录查看可以确认。core行为都是非预期的,需要排查。名字中包含obproxy、ET_NET、ET_TASK、ET_BLOCKING、ET_GRPC和ASYNC_LOG的 core 文件都是 OBProxy 进程产生的。
-
被信号中止:通过搜索关键日志
receive signal
确定信号值,这种问题排查较困难,需要确定系统执行过的操作命令。
对于 OBProxy,一般查询启动时间确认是否重启过,查看启动时间的方法有很多,如下面例子:
$ls -l /proc/`pidof obproxy` -d
dr-xr-xr-x 8 zhixin.lm users 0 May 23 10:29 /proc/100277
3.3 小结
非生产环境安装时,重启和退出是一件比较简单的事情。但在生产环境,这件事至关重要。服务退出会影响现有连接和请求执行,客户端报误。如果重启很慢,意味着服务不能快速恢复,但大家不用担心 OBProxy 的启动速度,1s 内便可以提供正常服务。
为了加深大家理解,我们结合实际遇到的问题,举个例子:
左边部分是 Java 程序执行逻辑,右边是 obproxy 进程的退出和重启情况,从上往下表示时间从早到晚,请问到第四个圆圈时间点,应用程序表现是什么?
相信大家已经有答案了,executeQuery 会抛出异常。但真实场景中,我们一般只能看到 executeQuery 执行失败,需要排查问题才能发现 OBProxy 发生过重启,并且 executeQuery 失败原因不止上面一种情况,排查起来比较麻烦,后面连接管理章节会有更多内容。
4 部署
在满足1.1中的安装环境要求后,OBProxy 就可以安装部署了,生产环境部署主要考虑 3个因素:
- 交付方式:OBProxy 有 rpm 包和 docker 两种形式,Obdeploy 和 OCP 都是通过 rpm 部署,蚂蚁内部 PASS平台通过 docker 方式启动
- 数量:我们对 OBProxy 的数量没有做任何限制,但真实部署时,OBProxy 的数量和 APP 或 ObServer 的数量有一定关系,这取决于具体的部署方式
- 部署方式:不同部署方式背后反映的是 RT 和资源抢占,有客户端部署、ObServer 端部署和独立部署三部分,这对性能至关重要
下面我们将结合实际场景做详细介绍。
4.1 部署在应用端
结合云原生技术,OBProxy 以 sidecar 方式和 APP 一起部署在同一个物理机上。APP 和 OBProxy 的数量满足1:1关系。OBProxy 和 OceanBase 数据库直连,中间没有负载均衡。实践证明,这种方式性能是最好的,同时需要注意,这里需要 APP、OBProxy 和 ObServer 之间的网络互通。
因为 APP 和 OBProxy 的个数是1:1的对应关系,因此这种部署方式会导致 OBProxy 的容器特别多,达到成千上万个,所以这种方式依赖底层的 k8s 等基础设施。
4.2 部署在 ObServer 端
部署在 ObServer 端是指在部署 ObServer 的机器上部署一个 OBProxy 进程,这样 ObServer 和 OBProxy 的数量满足 1:1 关系。与 4.1 对比,OBProxy 数量和 APP 没有了对应关系。除了一台 ObServer 部署一个 OBProxy,也可以一个 zone 内部署一个 OBProxy。
下图是专有云很常见的部署形态,和部署在应用端相比,有如下区别:
- 多了 LB 组件做 OBProxy 的负载均衡,链路更长
- APP 和 OBProxy 之间没有明确的一一对应关系,排查问题会困难些
- OBProxy 部署在 ObServer 所在机器,压力情况下会有机器的CPU/MEM资源抢占
4.3 独立部署
独立部署是指专门为 OBProxy 找一台机器部署。此时 OBProxy 的数量和 APP、ObServer 都没有关系,根据具体业务需求确定 OBProxy 的数量。对于 OBProxy 的部署机型,一般推荐选择小机型即可,如云上使用 16c16g 的ecs。独立部署后,ObServer 和 ObProxy 之间不存在资源抢占,可以更好地管理 OBProxy,将 OBProxy 做成资源池对外服务,目前公有云使用了该部署方式。
4.4 小结
部署方式和真实的物理环境、业务需求等相关。上面我们对不同部署方式的优缺点都做了介绍,大家可以根据实际业务需求选择合适的方案部署,服务业务才是最重要的。
5 总结
首篇文章我们和大家一起快速入门了 OBProxy,相信大家对 OBProxy 不再陌生。本章从安装和部署两个方面介绍,帮助大家使用更加丝滑。安装部分我们需要掌握一些避坑知识点,前文详细描述了可能遇到的问题。部署方式看似是一件很简单的事情,但上了生产环境后就大不一样,背后有很多考量和“纠结点”,大家也可以从实际出发,多想想其中面临的困难以及应对挑战的方法。
在上面内容中,我们还提到了需要注意或修改enable_strict_kernel_release
和proxy_mem_limited
配置项的值。接下来,我们还会在设置上进行优化,逐步提高 OBProxy 的易用性,打磨一个开箱即用的好产品。
好了,期待下期再见!
6 课后互动
6.1 上期互动
问题:使用 OBProxy 后,大家访问数据库的代码需要做哪些改动?
答案:很多同学都答对了,无需修改访问数据库代码就可以访问,非常方便。大家也可能注意到,访问 OceanBase 数据库的用户名十分的复杂,有格式要求,名字的背后和 OceanBase 数据库的架构息息相关,后面章节会做介绍。
6.2 本期互动
obproxyd.sh 脚本对 OBProxy 进程做了探活,请问探活方法是什么?除了脚本中的方法,还有哪些探活方法?这些方法有什么优缺点,请举例说明。在问答区与我们互动吧~