高性能数据访问中间件 OBProxy(三):问题排查和服务运维

本文涉及的产品
性能测试 PTS,5000VUM额度
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 1 引言上篇文章我们讲解了 OBProxy 的安装部署,在实践时,大家还可能因为机器环境、操作顺序不对等问题导致安装部署失败,这时候可以到OceanBase的开源社区 问答板块提问,会有专业的工程师回答你的问题。完成了 OBProxy 的安装部署后,就可以使用 OBProxy 访问 OceanBase 数据库了。如果刚开始使用 OBProxy ,排查问题和运维 OBProxy 是大家将要遇到的

1 引言 上篇文章我们讲解了 OBProxy 的安装部署,在实践时,大家还可能因为机器环境、操作顺序不对等问题导致安装部署失败,这时候可以到OceanBase的开源社区 问答板块提问,会有专业的工程师回答你的问题。完成了 OBProxy 的安装部署后,就可以使用 OBProxy 访问 OceanBase 数据库了。 如果刚开始使用 OBProxy ,排查问题和运维 OBProxy 是大家将要遇到的拦路虎。因此,本章我们将详细讲解问题排查手段和服务运维方法,让大家更轻松的使用 OBProxy ,并成为 OBProxy 的专家。 OBProxy 是数据库访问链路上重要的一环,结合本文内容,大家可以举一反三,多多思考分布式系统的链路追踪、问题排查等内容,这对理解分布式系统有很大的帮助。好了,现在我们开始吧!

2 问题排查 大部分情况下,排查问题是一个团队合作的工作,下面我们会介绍一些规范和思路,方便大家交流问题和解决问题。

2.1 描述问题 遇到问题时,我们首先需要描述清楚问题。比如在OceanBase开源社区问答板块,描述问题模版如下:

这里推荐大家按照要求填写,填写相关内容也利于大家将问题想的更清楚。对于问题描述部分,可以包含以下两点: ●问题时间:对于不好复现问题,时间信息有利于进行问题梳理,方便对齐问题 ●客户端报错:客户端报错包含丰富的信息(SQL、堆栈、执行时间等),对排查问题非常有帮助;当有结论时,也可以前后对照,进一步验证结论

2.2 分析问题 描述完问题后,对于问题排查人员,就需要分析问题。在分析问题前,首先要全局了解数据库访问链路,主要包含以下模块:

从全局再去看局部,思路会更清晰,对于OBProxy,和各个模块都有交互,大家有空也可以多学习下应用、LB和ObServer的知识。 当分析问题时,按照从前往后(从应用端开始)的顺序一个个分析,先确定哪个模块的问题,再确定模块的具体问题。 下面再介绍一些低效的问题排查方法,大家尽量避免: ●客户说应用使用数据库报错,直接去OBProxy的日志目录搜索WARNERROR级别日志,如果日志打印不规范或者WARN/ERROR日志太多,这种方法就十分的低效,甚至和客户问题没任何关系。 ●客户说有数据库连接断了,我跳过了中间环节,直接从OceanBase数据库开始排查,结果未发现问题。

2.3 归类问题 本小节对 OBProxy 常见问题进行归类,方便大家在分析 OBProxy 模块时有更好的思路。从业务视角去看,OBProxy的问题主要包含以下几类:

●登录失败:绝大部分都是某个地方配置出现问题,比较容易复现和排查 ●SQL执行:出现问题种类很多,有些疑难问题很难排查 ○返回错误:后端服务返回明确的错误码,根据错误码去ObServer和OBProxy断排查 ○慢SQL:需要确定每个模块的耗时,找到瓶颈点去优化,除了2.2中的模块,网络也是一个重要因素 ○断连接:和慢SQL类似,需要先排查哪个模块主动断开连接(主动发送FIN报文),然后排查具体模块

2.4 总结 经过前面内容介绍,大家就有了问题排查的方法论,但这只是万里长征第一步,因为文章篇幅有限,没有在继续深入介绍下去,后面有一些简单例子,方便大家了解,大家还需要不断的实战总结,才能成为高手,面对问题可以做到游刃有余。

3 OBProxy日志 解决OBProxy的问题时,有三大法宝:OBProxy 日志、linux命令(网络命令、系统命令和文本命令)和监控平台OCP。其中linux命令和监控平台的知识点十分通用,网络上资料很多,大家可以自学,掌握后对大家排查问题帮助很大。 本节我们主要介绍和 OBProxy 关系比较紧密的日志部分,OBProxy 的日志有多种类别,我们将介绍每种日志个作用,帮助大家排查问题。

3.1 错误日志 错误日志的文件名叫做 obproxy_error.log,错误日志会记录执行错误的请求,包括 OBProxy 自身错误和 OBServer 返回错误。我们以select obproxy_error from dual做测试,其中obproxy_error字段没有加引号,会被当作列处理,导致执行失败。客户端报错如下:

MySQL [test]> select obproxy_error from dual;
ERROR 1054 (42S22): Unknown column 'obproxy_error' in 'field list'

打开obproxy_error.log,内容如下:

2022-07-11 10:26:09.358231,undefined,,,,ob9988.zhixin.lm.xx.xx.xx.xx:sys:test,OB_MYSQL,,,COM_QUERY,SELECT,failed,1054,select obproxy_error from dual,42423us,454us,0us,41222us,Y0-7F4B1EF653A0,,,,0,xx.xx.xx.xx:33041,Unknown column 'obproxy_error' in 'field list'

# 日志通过逗号分隔,如果SQL中有逗号,会通过%2C替代,通过tr ',' '\n'替换结果如下
1,2022-07-11 10:26:09.358231    #日志打印时间
2,undefined           # sharding模式下逻辑租户名
3,                    # 无需关注,内部使用
4,                    # 无需关注,内部使用
5,                    # sharding模式下逻辑库名
6,ob9988.zhixin.lm.xx.xx.xx.xx:sys:test  # 物理库信息(cluster:tenant:database)
7,OB_MYSQL         # 数据库类型
8,                 # 逻辑表名
9,                 # 物理表名
10,COM_QUERY       # SQL 命令(COM_QUERY、COM_STMT_PREPARE等)
11,SELECT          # SQL 类型
12,failed          # 执行结果(success/failed)
13,1054            # 错误码(succ时为空)
14,select obproxy_error from dual  # SQL语句
15,42423us         # 执行总耗时(ms,包括内部 SQL 执行耗时
16,454us           # 预执行时间
17,0us             # 建立连接时间
18,41222us         # 数据库执行时间
19,Y0-7F4B1EF653A0 # OBProxy内部日志trace_id
20,           # 无需关注,内部使用
21,           # 无需关注,内部使用
22,           # 无需关注,内部使用
23,0          # 无需关注,内部使用
24,xx.xx.xx.xx:33041  # 路由到的ObServer的地址信息
25,Unknown column 'obproxy_error' in 'field list' # 报错信息

从第12行可以看到执行失败,从第27行可以看到执行SQL的OBServer的地址信息,第28行有报错信息,就可以确定时数据库执行失败。

3.2 审计日志 审计日志的文件名叫做 obproxy_digest.log,审计日志记录执行时间大于参数 query_digest_time_threshold 阈值(默认 100ms)的请求和错误响应请求。对于3.1中的例子,我们从obproxy_digest.log中也可以看到日志。

2022-07-11 10:26:09.358221,undefined,,,,ob9988.zhixin.lm.xx.xx.xx.xx:sys:test,OB_MYSQL,,,COM_QUERY,SELECT,failed,1054,select obproxy_error from dual,42423us,454us,0us,41222us,Y0-7F4B1EF653A0,,,,0,xx.xx.xx.xx:33041

除了执行错误SQL,我们使用select sleep(3) from dual模仿慢SQL,执行后,查看obproxy_digest.log,可以看到OBProxy执行花费了409us,ObServer执行花了3039883us。内容如下:

2022-07-11 14:32:51.758265,undefined,,,,ob9988.zhixin.lm.xx.xx.xx.xx:sys:test,OB_MYSQL,,,COM_QUERY,SELECT,success,,select sleep(3),3041116us,409us,0us,3039883us,Y0-7F4B1CEA13A0,,,,0,xx.xx.xx.xx:33041


# 日志分析
1,2022-07-11 14:32:51.758265    #日志打印时间
2,undefined          # sharding模式下逻辑租户名
3,                   # 无需关注,内部使用
4,                   # 无需关注,内部使用
5,                   # sharding模式下逻辑库名
6,ob9988.zhixin.lm.100.88.147.179:sys:test  # 物理库信息(cluster:tenant:database)
7,OB_MYSQL         # 数据库类型
8,                 # 逻辑表名
9,                 # 物理表名
10,COM_QUERY       # SQL 命令(COM_QUERY、COM_STMT_PREPARE等)
11,SELECT          # SQL 类型
12,success         # 执行结果(success/failed)
13,                # 错误码(succ时为空)
14,select sleep(3) # SQL语句
15,3041116us       # 执行总耗时(ms,包括内部 SQL 执行耗时
16,409us           # 预执行时间
17,0us             # 建立连接时间
18,3039883us       # 数据库执行时间
19,Y0-7F4B1CEA13A0 # OBProxy内部日志trace_id
20,                # 无需关注,内部使用
21,                # 无需关注,内部使用
22,                # 无需关注,内部使用
23,0               # 无需关注,内部使用
24,xx.xx.xx.xx:33041  # 路由到的ObServer的地址信息

对于审计日志比较重要的是第14行记录了执行的SQL,15~16记录了详细的执行时间,如果数据库执行慢第18行的时间就会很长。

3.3 慢日志 慢日志的文件名叫做obproxy_slow.log,慢日志记录执行时间大于 slow_query_time_threshold阈值(默认 500ms)的请求。如上节SQL select sleep(3) from dual在obproxy_slow.log中也有记录,内容如下:

2022-07-11 14:32:51.758270,undefined,,,,ob9988.zhixin.lm.xx.xx.xx.xx:sys:test,OB_MYSQL,,,COM_QUERY,SELECT,success,,select sleep(3),3041116us,409us,0us,3039883us,Y0-7F4B1CEA13A0,,,,0,xx.xx.xx.xx:33041

慢日志的日志格式和审计日志的格式相同,此处不在介绍。 对于慢SQL,在obproxy.log也会有记录,关键字是Slow Query,obproxy.log中记录的信息更加详细,如上面的SQL,搜索obproxy.log得到:

[2022-07-11 14:32:51.758195] WARN  [PROXY.SM] update_cmd_stats (ob_mysql_sm.cpp:8425) [74744][Y0-7F4B1CEA13A0] [lt=7] [dc=0] Slow Query: ((
client_ip={127.0.0.1:50422},   // 发送SQL的客户端地址
server_ip={xx.xx.xx.xx:33041}, // SQL被路由到的目标BOServer
obproxy_client_port={xx.xx.xx.xx:52052},  // 和OBServer连接的本地地址
server_trace_id=Y81100B7C0535-0005E3460FBBE3CD-0-0, // 目标OBServer中执行过程中的trace id
route_type=ROUTE_TYPE_NONPARTITION_UNMERGE_LOCAL, // SQL使用的路由策略
user_name=root,         // 用户名
tenant_name=sys,        // 租户名
cluster_name=ob9988.zhixin.lm.100.88.147.179,  // 集群名
logic_database_name=,  // 逻辑库名
logic_tenant_name=,    // 逻辑租户名
ob_proxy_protocol=0,   // 协议类型
cs_id=14,         // client login时看到的connection id, proxy分配
proxy_sessid=7230691598940700681, // client 访问ob时内部记录connection id
ss_id=21, 
server_sessid=3221588238,  // SQL在目标observer中的connection id, observer 分配
sm_id=14, 
cmd_size_stats={
    client_request_bytes:20,  // client发给proxy的请求包大小
    server_request_bytes:38,  // OBProxy发给目标observer的请求包大小
    server_response_bytes:0,  // 目标observer发给proxy的响应包大小
    client_response_bytes:71}, // OBProxy发给client的响应包大小
cmd_time_stats={
    client_transaction_idle_time_us=0, // 在事务中该条SQL与上一条SQL执行结束之间的间隔时间, 即client事务间隔时间
    client_request_read_time_us=97, // OBProxy从client socket读取请求包的耗时
    client_request_analyze_time_us=95, // OBProxy分析client的SQL耗时
    cluster_resource_create_time_us=0, // OBProxy创建集群资源耗时(仅首次访问集群时需要创建)
    pl_lookup_time_us=0, // 根据SQL获取涉及路由表的耗时
    pl_process_time_us=0,  // 对涉及路由表的进行筛选排序的耗时
    congestion_control_time_us=21,  // 根据SQL获取涉及黑名单信息的耗时
    congestion_process_time_us=3,  // 对涉及黑名单的进行检查过滤的耗时
    do_observer_open_time_us=55,  // 对目标observer获取可用连接的耗时, 包含connect_time
        server_connect_time_us=0,  // 对目标observer创建连接的耗时
    server_sync_session_variable_time_us=0,  // 对选择的目标连接进行初始化的耗时, 包括saved_login, 同步db, 同步系统变量, 同步last_insert_id, 同步start_trans
        server_send_saved_login_time_us=0,  // 对选择的目标连接进行saved login耗时
        server_send_use_database_time_us=0,  // 对选择的目标连接同步db耗时
        server_send_session_variable_time_us=0,  // 对选择的目标连接同步已修改的系统变量耗时
        server_send_all_session_variable_time_us=0,  // 对选择的目标连接同步所有系统耗时
        server_send_last_insert_id_time_us=0, // 对选择的目标连接同步last_insert_id耗时
        server_send_start_trans_time_us=0,   // 对选择的目标连接同步start_trans/begin耗时
    build_server_request_time_us=23,  // 构建对目标server的请求包的耗时
    plugin_compress_request_time_us=0,   // 对请求包进行压缩耗时
    prepare_send_request_to_server_time_us=409,  // OBProxy接受到客户端请求,到转发到observer执行前总计时间,正常应该是前面所有时间之和
    server_request_write_time_us=32,  // OBProxy向目标server socket发送请求包的耗时
    server_process_request_time_us=3039883,   // 目标server该执行SQL的耗时
    server_response_read_time_us=67,   // OBProxy从目标server socket读取响应包的耗时
    plugin_decompress_response_time_us=59, // 对响应包进行解压缩耗时
    server_response_analyze_time_us=70,  // 对响应包进行分析的耗时
    ok_packet_trim_time_us=0, // 对响应包trim掉最后一个ok包的耗时
    client_response_write_time_us=185,  // OBProxy向client socket发送响应包的耗时
    request_total_time_us=3041116},  // OBProxy处理该请求总时间, 等于前面所有耗时之和
sql=select sleep(3)   //client的请求SQL
)

上面内容非常的详细,更方便定位慢SQL问题。其中request_total_time_us记录了执行的总耗时,对于每个部分的含义,大家可以参考第一篇中讲的SQL执行流程去对应。

3.4 统计日志  统计日志的文件名叫做obproxy_stat.log。 统计日志默认每分钟(monitor_stat_dump_interval参数控制)输出一次。通过该日志可以查看OBProxy一分钟内SQL的执行情况,举个例子,查看OBProxy是否有请求流量,看该日志记录即可。参考例子如下:

2022-07-11 10:26:59.499204,undefined,,ob9988.zhixin.lm.xx.xx.xx.xx:sys:test,OB_MYSQL,SELECT,success,,1,1,0,0,41480us,332us,40369us

# 日志分析
1,2022-07-11 10:26:59.499204   #日志打印时间
2,undefined      # sharding模式下逻辑租户名
3,               # sharding模式下逻辑库名
4,ob9988.zhixin.lm.xx.xx.xx.xx:sys:test  # 物理库信息(cluster:tenant:database)
5,OB_MYSQL  # 数据库类型
6,SELECT    # SQL 类型
7,success   # 执行结果(success/failed)
8,          # 错误码(succ时为空)
9,1         # 总请求数量
1           # 30 ms ~ 100 ms 请求数量
0           # 100 ms ~ 500 ms 请求数量
0           # 大于 500 ms 请求数量
41480us     # 执行总耗时(ms,包括内部 SQL 执行耗时)
332us       # 预执行时间
40369u      # 数据库执行时间

3.5 主日志 主日志的文件名叫做obproxy.log,有DEBUG、TRACE、INFO、ERROR四种级别,通过syslog_level参数控制,当需要进一步排查问题原因时,通过trace_id字段可以过滤得到一个session上的所有日志,查看obproxy.log 要求对 OBProxy 的代码实现非常熟悉,有一定技术难度。感兴趣同学可以OBProxy 源代码

3.6 总结 OBProxy 的日志在排查问题时非常的有用,掌握上面内容可以应对大部分的 OBProxy 问题。本节对日志格式做了介绍,并结合例子进一步说明,相信大家可以快速掌握。

4 服务运维 OBProxy有一个管理员账号root@proxysys,为了安全,我们对该账号的登录地址做了限制,要求大家本机登录进行运维操作。下面我们将从配置管理和内部命令两方面做详细介绍。

4.1 配置管理 OBProxy的配置参数参考文档参数说明。使用root@proxysys登录,就可以查看和修改配置项:

# 查看日志级别
MySQL [(none)]> show proxyconfig like '%syslog_level%';
+--------------+-------+-----------------------------------------------------------------------------------+-------------+---------------+
| name         | value | info                                                                              | need_reboot | visible_level |
+--------------+-------+-----------------------------------------------------------------------------------+-------------+---------------+
| syslog_level | DEBUG | specifies the current level of logging: DEBUG, TRACE, INFO, WARN, USER_ERR, ERROR | false       | USER          |
+--------------+-------+-----------------------------------------------------------------------------------+-------------+---------------+

# 修改日志级别为INFO
MySQL [(none)]> alter proxyconfig set syslog_level = INFO;
Query OK, 0 rows affected (0.01 sec)

对于show proxyconfig的输入,各字段含义如下: ●name:配置名,所有配置项名字可以从参数说明文档获取 ●value:配置内容,主要是整型和字符串格式。当内容不合法时会报错 ●info:描述配置参数的具体信息 ●need_reboot:表示参数是否重启生效。这里需要注意有些参数虽然不需要重启,但有时只对新的连接生效

4.2 内部命令 内部命令只在 OBProxy 上执行,不会转发给ObServer,主要用于获取 OBProxy 的内部状态或者修改内部行为。这部分内容和原理关系紧密,本节只做简要介绍,后续大家对 OBProxy 有更深入了解后可以再学习。

命令名

作用

show processlist

查看当前连接

kill [connection] proceselist_id

杀掉一个连接

show proxyinfo binary

查看OBProxy版本信息

show proxyinfo idc

查看LDC路由时的机房信息

show proxyroute [like 'cluster [tenant [db [table]]]']

查看路由表

show proxycongestion [all] [clustername]

查看黑名单

show proxymemory

查看OBProxy的模块内存使用

show proxymemory objpool

查看c++中类对象内存占用

5 总结 本章内容是对 OBProxy 的问题排查总结,这些方法凝聚了 OBProxy 开发同学多年的心血,经过了大量的实战检验。不仅可以用来学习,也可以作为手册,当遇到 OBProxy 问题时翻阅查看相关内容说明,希望能够帮助到大家!

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5月前
|
存储 缓存 中间件
|
5月前
|
消息中间件 存储 监控
|
4月前
|
缓存 运维 监控
打造稳定高效的数据引擎:数据库服务器运维最佳实践全解析
打造稳定高效的数据引擎:数据库服务器运维最佳实践全解析
|
4月前
|
运维 安全 Cloud Native
核心系统转型问题之分布式数据库和数据访问中间件协作如何解决
核心系统转型问题之分布式数据库和数据访问中间件协作如何解决
|
5月前
|
存储 C++ 容器
开发与运维数组问题之C++标准库中提供数据容器作为数组的替代如何解决
开发与运维数组问题之C++标准库中提供数据容器作为数组的替代如何解决
56 5
|
5月前
|
运维
开发与运维数据问题之LangChain增强大语言模型的能力如何解决
开发与运维数据问题之LangChain增强大语言模型的能力如何解决
43 1
|
5月前
|
API 运维
开发与运维数据问题之LangChain帮助处理长篇报告如何解决
开发与运维数据问题之LangChain帮助处理长篇报告如何解决
67 1
|
5月前
|
监控 搜索推荐 机器人
开发与运维数据问题之LangChain帮助提升GPT-4的实用性的如何解决
开发与运维数据问题之LangChain帮助提升GPT-4的实用性的如何解决
50 1
|
5月前
|
监控 C++ 运维
开发与运维数据问题之实现商业版和开源版在发送可观测数据方面的差异如何解决
开发与运维数据问题之实现商业版和开源版在发送可观测数据方面的差异如何解决
58 1
|
5月前
|
设计模式 监控 Go
开发与运维C++问题之C++部分原有的数据发送能力如何解决
开发与运维C++问题之C++部分原有的数据发送能力如何解决
27 1