首批通过分布式安全可靠测评,为关键业务系统打造
关于线程 hang 住 obstack 多线程卡在 ObSliceAlloc::free 的场景
更新时间:2024-01-22 01:56
问题现象
ObSliceAlloc 相关的 uint32_t 类型整数溢出,会导致 ObSliceAlloc::free 线程 hang 住,进而导致 500 租户队列积压,从而顶层可能表现出悬挂事务、租户分区无主、OBServer 节点 2881 连接 hang、Clog 回放积压等现象不定的严重问题。 相应的问题现象场景信息。
endless loop in ObSliceAlloc::free 日志信息如下。
#0 0x0000000005df2a12 in push (p=0x7fd5518284f0, this=0x7fd551820970) #1 free_item (first_free=<syntheticpointer>, p=0x7fd5518284f0, this=0x7fd5518208b0) #2 oceanbase::common::ObSliceAlloc::free (this=0x7fd7daac1130, p=0x7fd551828500) #3 0x000000000871e2f6 in retire (ptr=0x7fd551828500, this=0xed06200 <oceanbase::common::erb::ObExtendibleRingBufferBase<oceanbase::clog::ObILogExtRingBufferData*, oceanbase::common::erb::PtrSlot<oceanbase::clog::ObILogExtRingBufferData> >::get_val_ref()::val_ref>)大量分区无主, 且 OBServer cpu load 高, OBServer 日志中有大量如下日志。
WARN [CLOG] switch_state (ob_partition_log_service.cpp:2930) [xxxxx][xxxxx][xxxxx-xxxxx][lt=16][dc=0] switch_state wrlock failed(ref=-4023, partition_key=(tid:xxxxxx,....) WARN [CLOG] switch_state (ob_partition_log_service.cpp:2930) [xxxxx][xxxxx][xxxxx-xxxxx][lt=16][dc=0] switch_state wrlock failed(ref=-4023, partition_key=(tid:xxxxxx,....) WARN [CLOG] switch_state (ob_partition_log_service.cpp:2930) [xxxxx][xxxxx][xxxxx-xxxxx][lt=16][dc=0] switch_state wrlock failed(ref=-4023, partition_key=(tid:xxxxxx,....)500 租户队列满影响业务交易, 日志信息如下。
INFO [SERVER.OMT] ob_multi_tenant.cpp:803 [xxxxx][xxxxx][xxxxx-xxxxx][lt=45][dc=0] dump tenant info(tenant={id:500, compat_mode:0, unit_min_cpu:"xxxxx+xxx", unit_max_cpu:"xxxxx+xxx", slice:"xxxxx+xxx", slice_remain:"xxxxx+xxx", token_cnt:40, ass_token_cnt:40, lq_tokens:12, used_lq_tokens:0, stopped:false, idle_us:3149615, recv_hp_rpc_cnt:80193853780, recv_np_rpc_cnt:239, recv_lp_rpc_cnt:0, recv_mysql_cnt:0, recv_task_cnt:0, recv_large_req_cnt:0, tt_large_quries:0, actives:40, workers:40, nesting workers:7, lq waiting workers:0, req_queue:total_size=65537 queue[0]=65537 queue[1]=0 queue[2]=0 queue[3]=0 queue[4]=0 queue[5]=0 , large queued:0, multi_level_queue:total_size=0 queue[0]=0 queue[1]=0 queue[2]=0 queue[3]=0 queue[4]=0 queue[5]=0 queue[6]=0 queue[7]=0 , recv_level_rpc_cnt:cnt[0]=0 cnt[1]=0 cnt[2]=0 cnt[3]=0 cnt[4]=0 cnt[5]=0 cnt[6]=0 cnt[7]=0 })
问题原因
因
unit32_t溢出而导致ObSliceAlloc释放陷入死循环的已知 bug。ObSliceAlloc将 64k 的 block 切成若干个 slice,当一个 block 中长时间有(不同)slice 没归还时,该 block 便不能及时回收,被反复使用,与该block free相关的unit32_t类型的 push 值不断递增至溢出,进而导致ObSliceAlloc的 free 线程进入异常状态 (endless loop pause) ,hang 住。ObSliceAlloc把 64K 的 block 按要求的大小切成若干个定长的小块,在出问题的场景下小块内存是当log task用的。64K block头部会预留一个EmbedFixedQueue充当小块内存的free list。EmbedFixedQueue用两个uint32_t的整数当作push/pop下标,并且这两个下标只递增不递减,长时间运行后会导致uint32_t溢出,ObEmbedFixedQueue::push死循环,进而导致队列满。
问题的风险及影响
可能会产生多种问题,严重时会导致集群不可用。
影响的版本
OceanBase 数据库 V2.2.76 (oceanbase-2.2.76-20210716222653) 以下版本。
解决方法及规避方式
解决方法
升级至问题已修复版本,目前已修复的版本为 OceanBase 数据库企业版 V2.2.76 (oceanbase-2.2.76-20210716222653) 及以上版本。
临时解决方法: 重启 OBServer。参见 重启 OBServer 节点。