点击上方“IT那活儿”公众号--专注于企业全栈运维技术分享,不管IT什么活儿,干就完了!!!
OceanBase数据库迁移后高耗SQL问题分析 OceanBase数据库进程启动失败问题分析 OceanBase数据库DtlIntermRes内存问题分析 OceanBase数据库语句没有结果返回问题分析 OceanBase数据库程序报错分析 OceanBase数据库obproxy异常分析 OceanBase数据库oms链路延迟分析 OceanBase数据库提前转储问题分析 OceanBase数据库登录慢分析 OceanBase数据库至灾备集群后部分应用验证失败分析
OceanBase数据库迁移后高耗SQL
1.1 现象
某客户反馈有广播一直处理中,重发后处理成功,但第二次重发失败,导致1组生效广播回退,涉及多个号码。
检查携转应用主机和程序正常。因当晚Oracle库割接至OceanBase库,协调华为与OB工程师核查,发现OB库存在高耗SQL,执行耗时较长。OB工程师新建索引后,SQL性能恢复正常,广播恢复正常。
1.2 处置过程
经核查OB库中高耗SQL集中在访问携号转网广播表,通过对比高耗SQL在原Oracle库中的执行计划,发现该高耗SQL在Oracle库时可以走索引,但在服开OB库中执行计划为全表扫描。
经和OB原厂工程师确认,OceanBase中非前导列的索引不能提供匹配过滤,该组合索引的前导列(组合索引的第一列)不一致, OceanBase在处理SQL当where子句中不包含前导列时,OceanBase的执行计划只能是全表扫描。并且在4.x版本之前,没有index skip scan的扫描方式。也就意味着只要谓词条件是telnum=’xxx’都是无法走索引的,只能走全表扫描。
1.3 新炬建议
1)迁移前的全面性能测试
数据库迁移前,所有高频或关键业务SQL必须经过严格的性能测试,验证在新数据库中的执行效率,并重点测试索引优化是否符合预期。
2)针对差异优化SQL或数据结构
针对OceanBase的特性,必要时调整表结构或索引设计,避免因索引无法命中导致全表扫描,从而影响查询性能。
3)建立快速优化与响应机制
迁移后,应建立快速定位和优化高耗SQL的机制,包括监控工具和专业支持团队,以便在问题发生时能快速恢复性能。
4)加强多方协作与迁移规划
在数据库割接过程中,应确保应用开发团队、数据库迁移团队和目标数据库厂商的密切配合,共同识别潜在风险,制订应对方案,并在上线前完成充分的验证和预案设计。
OceanBase数据库进程启动失败
2.1 现象
某Oracle库割接到OceanBase库后,应用重启过程中发现有个进程无法启动,报错:invaild number。
怀疑和进程有使用mod(b,N)对号码取模,实现进程的并行执行,后续通过取消mod函数后,进程正常启动。
2.2 处置过程
经核查,在OB库中报错invaild number的SQL语句为:
select xxx from xx where a=? and mod(b,2)=?;
检查表字段为varchar2(32),表数据中因包含宽带类号码,是F开头,并非纯数字,当SQL扫描时,如果有使用到a字段的索引,筛选过滤后b只会剩下纯数字的11位号码,再取模就不会报错。但如果SQL走全表扫描,会扫到F开头号码,则会报错。
经测试该SQL在Oracle库中,不论是走索引还是全表扫描,均不会报错。
和OB原厂确认:
mod函数会对varchar2类型做隐式转换,OB库会最大抽取TO_CHAR(TO_NUMBER(b)*100,'FM9999999999990.00');而Oracle只会抽取b,最终满足子查询条件的数据都是可能转成number,因此Oracle执行不会报错,而OB会尝试把所有b转成number,因此可能报错。此缺陷在4.x中已修复。
2.3 新炬建议
1)全面测试迁移后的SQL兼容性
数据库割接过程中,尤其是涉及关键业务逻辑的SQL语句,需要全面测试其兼容性和性能表现,特别是函数调用和数据类型转换的细节处理。
2)优化数据设计以避免隐式转换问题
数据库表设计应尽可能避免字段类型与业务逻辑不匹配的情况,如将可能需要数值计算的字段定义为数字类型,而不是字符串类型,以减少隐式转换带来的问题。
3)及时关注数据库版本更新和缺陷修复
目标数据库(如OceanBase)可能存在已知缺陷,需要密切关注版本更新与修复说明,及时规划升级以避免旧版本问题对业务的影响。
4)加强测试阶段的数据覆盖率
测试阶段应确保数据覆盖率足够全面,包括边界条件和非预期输入的情况,例如混合数字和字母的字段内容,以便提前发现潜在问题。
OceanBase数据库DtlIntermRes内存问题
3.1 现象
从oracle环境进行国产化替换到OB后第二天,大量业务报错4013。通过sql检查内存模块发现DtlIntermRes内存模块异常增高。
3.2 处置过程
知识库有类似的记录,可以使用 hint *+ parallel(2) */ 开启并行,并行度大于 1 时是流式执行,不会写中间结果。时刻注意dtl模块占用,如果到了危险值,及时与业务沟通手动切主,减少影响。
根据研发提供的一些触发条件对关键算子来进行匹配,找到一些怀疑sql(等内存模块变化之后马上抓一部分sql),抓到的这部分的sqlid是问题sql的概率最大,我们可以都绑定/*+parallel(2)*/的outline。
这部分sql_id也可以分为两种:
一种以前没有outline;
另一种就是已经有outline。
对于没有outline的直接绑定/*+parallel(2)*/就可以了,已经有outline的sql在原有outlinedata的基础上加上/*+parallel(2)*/就可以了。
当上述OUTLINE绑定后,观察内存增长情况。本次案例中,DTL内存被控制住,所以怀疑点在上述的SQL_ID中,后续只要逐步放开OUTLINE,即可定位问题SQL(如果还未控制,可以排除已经绑定/*+parallel(2)*/的sqlid再多次抓一下)。
3.3 新炬建议
1)内存泄漏的根本原因,Batch Rescan优化问题
在batch rescan优化的过程中,如果上一个batch的数据没有读完(例如上方有limit语句,或者nested semi/anti join操作),并且batch大小会变化(尽管默认batch大小是8192行,但数据不足时可能会小于这个值),就会导致上一个batch尾部的一些中间结果没有被及时释放。这是造成内存泄漏的根本原因。
2)触发条件的确定
与研发团队的深入交流后,基本确定了三个触发条件:
nested loop join或subplan filter走了px batch rescan
这种情况下,执行计划中通常会出现px_batch_rescan算子。这个算子我们称之为a算子。
子条件一:
a算子处于subplan filter或nested loop semi/anti join的右支。
子条件二:
a算子处于nested loop join的右支,并且这个nested loop join算子上方存在limit语句。此时,我们称这个nested loop join算子为b算子。
nested loop join中的左支数据来自nl外部
执行计划中,相关算子的Outputs & filters中会出现range_cond([? = A.xxxx(0xff4fe085edc0)(0xff4fe085f750)])的标记。
这些触发条件的确定,为我们后续复现问题和进行针对性优化提供了重要依据。
3)问题复现与验证
在确定了触发条件后,可以尝试在测试环境中复现问题。通过构造符合触发条件的SQL语句,观察内存使用情况,验证问题的存在性。这有助于我们更好地理解问题的本质,并为后续的修复工作提供有力支持。
4)SQL优化
针对已经定位的问题SQL,进行针对性的优化。例如,调整SQL的写法,避免使用可能触发内存泄漏的算子组合;或者通过增加索引、调整表结构等方式,提高SQL的执行效率,减少内存占用。
5)监控与预警机制
加强数据库的监控与预警机制。通过实时监控内存模块的使用情况,及时发现潜在的内存泄漏问题。同时,建立预警机制,当内存使用达到危险值时,自动触发预警流程,以便快速响应和处理。
OceanBase数据库语句没有结果返回
4.1 现象
业务侧反馈程序中执行select substr(?, 9, 6) uniid from dual ;语句没有结果返回。
4.2 处置过程
收到业务人员反馈报错,生产环境根据业务测试SQL语句(select substr(?, 9, 6) uniid from dual;)从数据库侧抓取相关信息(传入参数值),根据业务侧抓取的参数值,通过在数据库gv$sql_audit视图中查询是否有值返回,但在数据库侧并未看出异常(是有数据返回的)。
与华为同事反馈后,业务侧开debug日志发现发现正常的号码和不正常的号码dam收到的报文不太一样。java程序中使用getColumnDisplaySize函数来获取 select substr(?, 9, 6) uniid from dual; 该条语句的字段长度,发现在日志报文中有时会不输出getColumnDisplaySize的值,但是报文中substr是有结果值的 ,输出的size是没有的,之后华为同事确认这里代码有判断getColumnDisplaySize获取值为0时,没有报文输出,且判断没有数据。所以导致了程序报错。
之后再测试环境测试该场景发现获取的值是固定的几个值,并进行了直连observer的测试,发现主zone的3个节点,每个节点的值是固定不变的(3个节点值不一样)怀疑有缓存,但无法确认缓存是在server端还是client端,之后重启了主zone来验证,发现主zone3个节点的值均被刷新,之后在用getColumnDisplaySize函数获取值又是不变的。之后又对集群合并,发现也是可以刷新的。在之后怀疑和执行计划缓存有关,刷新了plan cache后,也是可以刷新的。到这里也算是有结果了。 oracle这里没有问题是因为oracle 获取时获取的substr(?, 9, 6) 中截取的长度6,而ob是将第一次截取的实际长度来通过执行计划来缓存的。
之后找研发确认程序中的getColumnDisplaySize函数是通过plan_cache获取的,执行计划第一次生成时会记录到gv$plan_cache_plan_stat中,所以后面获取的长度都是一样的,也可以通过使用 *+use_plan_cache(none)*/来避免,这样每次获取都是新的。
4.3 新炬建议
1)加强全链路优化分析能力
本次故障排查过程中,我们深刻认识到加强全链路优化分析能力的重要性。从业务侧反馈到问题定位、优化策略实施再到后续验证与监控,每一个环节都需要我们具备全面的知识和技能。因此,我们将继续加强团队建设,提高团队成员的全链路优化分析能力。同时,我们也将加强与业务侧的沟通协作,共同推动系统的持续优化和改进。
2)深入理解底层机制与差异
本次故障还提醒我们,深入理解不同数据库系统的底层机制和差异至关重要。Oracle与OB在处理getColumnDisplaySize函数时的差异,正是由于我们对底层机制了解不够深入所导致的。
因此,我们将加强对不同数据库系统底层机制的学习和研究,以便更好地应对类似问题。同时,我们也将积极关注数据库领域的最新动态和技术发展,以便及时引入新技术和优化策略。
OceanBase数据库程序报错
5.1 现象
收到一线人员前台界面提示程序报错connection reset。
5.2 处置过程
1)与一线人员沟通操作流程
如果一次上传处理的数据量少于900条可以正常处理, 超过900条则报错。
2)根据业务侧提供的堆栈信息在obproxy日志中对应的cs_id所对应proxy trace_id进行过滤WARN,ERROR相关日志信息
发现 we cannot support packet which is larger than 16MB(ps_pkt_len=16777219, MYSQL_PACKET_MAX_LENGTH=16777215, ret=-4007) ,不支持超过16MB的数据包传输。
3)配合业务测试
通过直连的方式,在数据库确认直连可以插入,且使用lengthb查大小可以确认插入的大小确实超过16M大小。
业务侧确认在一次上传处理数据时是batch处理的,会将900条数据合并成一个数据包在进行上传,导致插入大小超过了proxy侧限制。
这边后续是业务改造处理。 ob研发是建议将proxy升级到4.3.1.0 BP1 hotfix1 来解决。
5.3 新炬建议
1)应用减少execute传的包大小
本次故障提醒我们,在应用层面,需要更加注意数据包的大小控制。尤其是在进行批量数据处理时,应该避免将过多的数据合并成一个数据包进行传输。
这样做不仅可能超出系统的处理能力,还可能引发类似的“connection reset”报错。因此,我们需要对应用进行优化,合理控制数据包的大小,确保其在系统可处理的范围内。
在具体实现上,可以考虑将大数据包拆分成多个小数据包进行传输,或者采用流式处理的方式,逐步将数据传输到系统中。同时,还需要对应用进行充分的测试,确保其在实际运行中能够稳定地处理各种大小的数据包。
2)优化数据处理逻辑
除了控制数据包大小外,我们还需要对应用的数据处理逻辑进行优化。在本次故障中,业务侧采用了batch处理的方式,虽然在一定程度上提高了处理效率,但也带来了数据包过大的问题。因此,我们需要重新评估和优化数据处理逻辑,确保其在提高处理效率的同时,不会引发类似的问题。
具体而言,可以考虑采用更加灵活的数据处理方式,如根据数据的实际情况动态调整batch的大小,或者采用更加高效的数据处理算法和技术手段。
3)proxy升级到4.3.1.0 BP1 hotfix1
针对本次故障中暴露出的proxy侧数据包大小限制问题,我们需要尽快将proxy升级到4.3.1.0 BP1 hotfix1版本。这一版本已经解决了数据包大小限制的问题,能够支持更大的数据包传输。通过升级proxy,我们可以从根本上解决当前的问题,避免类似的故障再次发生。
在升级过程中,需要充分测试新版本的稳定性和兼容性,确保其能够满足系统的实际需求。同时,还需要对升级过程进行详细的规划和记录,以便在出现问题时能够及时定位和解决。
4)加强系统监控与预警
为了避免类似的故障再次发生,我们还需要加强系统的监控与预警机制。通过实时监控系统的运行状态和数据传输情况,我们可以及时发现并处理潜在的问题。同时,还可以设置预警机制,当系统出现异常情况时能够及时发出警报,提醒相关人员进行处理。
在具体实现上,可以考虑采用专业的监控系统或工具,对系统的各项性能指标进行实时监控和分析。同时,还需要制定相应的预警策略和规则,确保在出现异常情况时能够及时发出警报并采取相应的处理措施。
OceanBase数据库obproxy异常
6.1 现象
生产环境单点登录的odc使用的元数据库的连接串指向ocp依赖的metadb某节点的obproxy,该metadb docker中的文件系统异常,导致docker 中运行的observer和obproxy均异常,单点登录odc无法连接到元数据库,odc服务也异常需要修改odc的元数据库连接串,同时还需要重建单节点metadb。
6.2 处置过程
1)修改odc容器中记录的元数据库ip
docker exec -it obodc bash
view bin/start-odc.sh
将main()函数中的ODC_DATABASE_HOST修改为需要设置的ip:
exit
docker restart obodc
2)oat不支持重建单节点metadb,使用antman重建(ocp版本3.3.4,依赖的metadb有oat和antman两种部署方式)
3)从其他节点cp OB2277_OBP230_x86_20220429镜像到异常节点主机并导入到docker
4)安装antman 1.4.3(异常节点之前安装过,用于部署单节点ocp),修改obcluster.conf文件
确保配置文件中observer启动参数部分与metadb其他节点一致。(cluster_id,cluster_name,zone_name等,其他节点的配置文件见/home/admin/oceanbase/etc/observer.config.bin)
5)删除旧的metadb容器
docker rmi ${container_id}
6)antman以配置文件启动metadb容器
/root/t-oceanbase-antman/install_OB_docker.sh ${容器名} ${当前节点主机ip} "metadb节点一ip:2882:2881;metadb节点二ip:2882:2881;metadb节点三ip:2882:2881"
7)检查observer启动是否正常
docker exec -it ${容器名}
tail -10f home/admin/oceanbase/log/observer.log
连到metadb sys租户查oceanbase.__all_server看server是否正常start service。
8)metadb镜像中集成了obproxy,之前metadb是用oat创建的,oat创建的metadb容器中的proxy记录的proxyro密码非默认密码xxxxx,proxy记录的proxyro密码和数据库中实际的不一致,导致通过该proxy无法连接到ob集群
需要先修改metadb数据库的proxyro@sys密码,然后同步修改每个proxy记录的proxyro密码:
mysql -P 2883 -h xx.xx.xx.xx -uroot@sys#nj_obcluster -pxxx
alter user proxyro@'%' identified by 'xxx';
mysql -P 2883 -h ${异常节点的proxy地址} -uroot@proxysys -p'P@Almy16'(这是3版本proxysys的默认密码)
alter proxyconfig set observer_sys_password='xxx';
mysql -P 2883 -h ${正常节点的obproxy地址1} -uroot@sys#nj_obcluster -pxxx
alter proxyconfig set observer_sys_password='xxx';
mysql -P 2883 -h ${正常节点的obproxy地址2} -uroot@sys#nj_obcluster -pxxx
alter proxyconfig set observer_sys_password='xxx';
6.3 新炬建议
1)生产环境高可用架构设计的重要性
本次故障处理过程凸显了生产环境高可用架构设计的重要性,在生产环境中,单点故障往往会导致整个系统或服务的中断,严重影响业务的正常运行。
因此,我们必须充分考虑到系统的高可用性和容错性,采用冗余设计、负载均衡、故障转移等技术手段来降低单点故障的风险。
2)针对元数据库的高可用性,我们可以采用多种方案来提高其稳定性和可靠性
例如,我们可以使用OceanBase集群来部署元数据库,利用其分布式架构和高可用特性来确保数据的可靠性和服务的连续性。此外,我们还可以考虑使用主从复制、读写分离等技术手段来进一步提高元数据库的可用性和性能。
3)在容器化部署的环境中,监控和恢复机制同样至关重要
我们应该建立完善的监控体系,实时监控容器的运行状态、资源使用情况以及网络连接等信息。
一旦发现异常情况,我们应该能够迅速定位问题并采取有效的恢复措施。例如,我们可以使用Docker的重启策略、日志收集与分析工具以及容器编排平台(如Kubernetes)的自动恢复功能来提高容器的可用性和恢复速度。
OceanBase数据库oms链路延迟
7.1 现象
oms迁移过程中,发现反向增量延迟2小时以上,查看日志发现有deadlock日志输出,导致链路延迟。
7.2 处置过程
在plsql通过语句查询,确认是否存在死锁,查询出具体的信息,确认存在死锁。
通过修改 Incr-Sync 增量同步组件中的并发参数workerNum":int 1 修改成1,使之串行化运行。
等待当前事务提交后,将并发参数workerNum":int 64 修改成原先值。
7.3 新炬建议
1)加强链路监控完善预警机制
本次故障暴露了我们在链路监控和预警机制方面的不足。未来,我们需要将加强对链路的监控关注,建立更为完善的预警机制。通过实时监控系统的运行状态、日志输出和性能指标,我们能够及时发现潜在的问题并采取有效的应对措施,从而最大限度地减少故障对业务的影响。
2)优化并发处理
虽然并发处理能够显著提高系统的处理能力和效率,但如果不加以合理控制,也可能引发死锁等性能问题。因此,我们需要根据系统的实际情况和业务需求,优化并发处理策略。例如,可以通过设置合理的并发度、采用更为高效的锁机制、优化事务处理流程等方式来降低死锁的发生概率。
OceanBase数据库提前转储
8.1 现象
慢SQL导致节点提前转储问题。
8.2 处置过程
1)OCP分析故障时间段memstore使用情况
发现memstore可用内存被挤占,导致计算出来的阈值下降,触发了节点提前转储。
2)从sqlaudit中捞取的可疑SQL
发现SQL缺少条件导致执行计划差,所需的中间结果集占用大量内存,导致租户内存不足。
3)收集故障信息后,针对问题触发SQL进行了限流
8.3 新炬建议
1)禁止未经测试的大结果集SQL生产上线
本次故障的发生,直接原因是某条SQL语句缺少筛选条件,导致生成了庞大的中间结果集。这提醒我们,在SQL语句上线之前,必须进行充分的测试,确保其执行计划合理、内存占用可控。对于可能产生大结果集的SQL语句,更要进行严格的审查和测试,避免其未经测试就直接在生产环境中使用。
2)业务侧严格遵守上线评审流程,未经评审通过的SQL不允许直接上线
技术评审团队需要对SQL语句的合理性、性能、内存占用等方面进行全面的评估,确保其符合系统要求和上线标准。
只有经过评审并获得通过的SQL语句,才允许上线运行。这一流程的实施,将有助于提高SQL语句的质量和稳定性,降低系统故障的风险。
OceanBase数据库登录慢
9.1 现象
用户反应登录很慢。
9.2 处置过程
1)黑屏尝试重复登录
发现有一部分会话连接很快,一部分会话连接会卡住很久。初步分析可能是用户使用F5转发时,对应obproxy宕机,ocp查看obproxy正常。
2)查看登录时间段的observer.log
发现有很多delete table from xxx语句,查找后发现均为临时表,查询官网后得知,3.2.4 BP5之前会有会话id复用的情况,上一次会话使用过多临时表后,下一次复用会删除临时表后才可使用,导致连接异常。
3)查看临时表和全局临时表
select table_name from __all_virtual_table where tenant_id = 1006 and table_type in (8,9);
还有部分连接异常情况为队列积压,查询语句为:
select svr_ip,tenant_id,req_queue_total_size from __all_virtual_dump_tenant_info where req_queue_total_size <> 0;
队列积压最高65535,可尝试重启积压observer解决。
9.3 新炬建议
1)登录均失败的排查方向一般与observer实例本身无关
在排查过程中,可首先检查obproxy机器是否hang住或性能异常。obproxy作为请求转发的关键组件,其性能状态直接影响用户登录速度。
2)部分会话登录很快而部分卡住的情况,可考虑是否与会话管理或临时表使用有关
在OceanBase的某些版本中,会话ID复用机制可能导致临时表删除开销过大,进而影响登录速度。因此,在排查过程中应关注临时表的使用情况和会话管理策略。
3)控制临时表数量
为避免临时表过多导致的性能问题,建议用户在使用临时表时注意控制数量。不要在同一会话中创建过多的临时表,以免增加删除开销和影响登录速度。
OceanBase数据库至灾备集群后部分应用验证失败
10.1 现象
OB灾备切换演练,灾备集群切换为主集群后,部分应用功能验证失败。
10.2 处置过程
分别进入主备集群查看主备角色已经切换成功。排查应用的数据库连接配置,数据库连接配置均为域名,域名解析也已切换至灾备机房IP。
ssh连接应用主机,netstat查看正在连接的会话,发现有很多会话还是访问的原主机房IP。ssh原主集群OB主机查看日志,发现仍有sql请求持续过来,但因为已切换为备集群只读模式,这些sql都执行失败了。
通知行方应用发现连接池存在长链接未关闭,持续提供数据库访问导致。咨询其他分行切换情况,也存在访问IP为原主机房,但应用任然可以正常入库至灾备集群。查看发现OBproxy的启动方式为RSlist,其他分行是configurl。
分析configurl方式,应用访问到OBproxy上后,OBproxy会通过configurl自动获取到当前主集群ID,将访问路由到当前主集群,所以不管是访问主机房还是灾备机房都会被正确路由。但是RSlist只会路由到当前集群,所以应用访问到主机房obproxy后是在本地集群执行,并没有路由到当前的主集群。
修改obproxy启动方式为configurl后,应用验证成功。
10.3 新炬建议
1)对连接池配置和状态引以重视
本次故障处理过程中,团队发现应用连接池存在长链接未关闭的问题。这提醒我们,在应用配置中,连接池的配置至关重要。在灾备切换等关键操作中,连接池的配置和状态管理需要得到足够的重视和关注。
2)架构设计和运维管理考虑组件配置间兼容性和可靠性
通过对比和分析,团队发现OBproxy的启动方式对灾备切换的成功与否具有重要影响。configurl方式能够自动获取当前主集群ID,并将访问路由到当前主集群,而RSlist方式则只能路由到当前集群。这一发现提醒我们,在数据库架构设计和运维管理中,需要充分考虑和测试不同组件和配置的兼容性和可靠性。
新炬运维避坑指南连载合集链接:

本文作者:秘而不宣(上海新炬中北团队)
本文来源:“IT那活儿”公众号





