【OceanBase诊断调优】—— KVCache 排查手册

原文链接:OceanBase分布式数据库-海量数据 笔笔算数

本文介绍 KVcache 相关问题的排查方法。

KVCache 相关概念

在进行排查前,需要了解几个概念。

  • pin

    一个 cache 块 ( memblock ) 被 pin 住,表示它正在被引用。

    cache 的由多个定长的块组成,每个块称为一个 memblock 。每个 memblock 中存放了多个 KV ,使用者通过 KV 指针来读取 KV 。容易理解,在使用指针的过程中,需要保证指针的安全,也即需要 pin 住存放 KV 的 memblock ,保证它不被释放。cache 内部通过引用计数来实现,cache 每向外吐出一个 KV 指针,都要对 KV 所在的 memblock 的引用计数加 1 ( pin 住这个 memblock ) ,当不再使用 KV 指针时,引用计数减 1 。也就是说,当引用计数大于 0 时,说明有人正在读其中的内存,那这个 memblock 就不能被释放,反之如果等于 0 ,则释放是安全的。

    简而言之,如果一个 memblock 被 pin 住,那么它不能被释放。

  • sync wash

    sync wash 指 cache 腾出自身内存给租户使用的过程。 从 1 可知,如果一个 memblock 没有被 pin ,那么它是可以被释放的。sync wash 就是 cache 找到没有被 pin 的 memblock ,释放内存,腾给租户使用。

  • cache 大小无上限

    cache 的大小在一个租户内是无上限的。 为了最大化利用租户内存,在租户内不限制 cache 的大小,理论上 cache 最大可以占满一个租户的内存。但是 cache 的内存比较特殊,在租户需要内存时,会触发 cache 的 sync wash ,腾出内存给租户使用。

常见问题

ret=-4273 can not find enough memory block to wash

首先 4273 不是 cache 的问题,4273 报错表示在 sync wash 过程中发现 cache 中所有的 memblock 都被 pin 了,没有内存可以释放。 导致 4273 的原因可能有:

  • cache 本身已经被榨干了,没有内存可以 wash ,所以就找不到不被 pin 的 memblock。

  • cache 本身还有内存,但是都被 pin 住了,无法 wash 出来;这个原因又分为两种情况:

    • 确实有需要较多 cache 的 SQL 在执行。
    • cache handle 引用计数有泄漏。

排查的思路就是逐步确认是哪个原因导致的 4273 ,步骤如下:

  1. 查看当时 cache 的大小。

    * 通过 MEMORY 日志,memory 日志可以看到租户的 cache_hold ,这个字段记录了 cache 的总大小。
    * 通过 CACHE 日志,可以看到当时各个 cache 的大小。
    * 通过虚拟表 `__all_virtual_kvcache_info`,各版本都有,但是是实时数据,需要在案发时查询。
    

    如果此时 cache 大小很少,说明此时 cache 本身已经被榨干,wash 不出内存符合预期,应该查看当时租户的内存分布,看看其他 mod 是否符合预期,否则进入第二步。

  2. 判断是否存在泄漏。

    这一步是通过查看 cache 的大小能否降下来,来区分是 cache handle 引用计数有泄漏还是确实有需要较多 cache 的 SQL 在执行。

    对于 OceanBase 数据库 V4.0 及以后版本,可以停止所有查询后尝试手动 flush cache ,如果 cache 能降下来,则说明没有泄漏,是确实有需要较多 cache 的 SQL 在执行导致。

    手动 flush 需要直连到 OBServer 节点上执行,如果可以 flush 干净 ( 可能需要手动 flush 多次 ) ,则表示没有泄漏,对比 flush 前后 __all_virtual_kvcache_info 表中 size 的变化来判断。也可以通过查询 __all_virtual_kvcache_store_memblock 虚拟表来直接查看所有 memblock 引用计数,看是否有异常。

    select * from __all_virtual_kvcache_store_memblock where ... order by ref_count desc limit 10;
    

    对于 OceanBase 数据库 V4.0 之前版本,只能通过日志查看在 4273 报错后,cache 的大小是否降下去过,如果能降下去,则说明一定没有泄漏,如果没降下去过,则无法判断。( 因为之前版本手动 flush 并不会立即释放 cache 的内存,而是通过降低其访问热度,通过后台 wash 线程慢慢刷出去。 )

    如果是较多 cache 的 SQL 在执行导致,规避方案是,将 cache 用量较大的操作分散在租户内存压力较小的时候执行,如果仍有报错,尝试对租户内存进行扩容,增大内存。 如果是 cache handle 引用计数有泄漏导致,则需要复现问题,排查泄漏的路径。

cache 占用内存较高

如前文所述,cache 在租户内是无上限的,所以理论上无论 cache 占多大内存,只要能被 sync wash ,就是符合预期的。 判断能否 sync wash 出来需要参考问题 1 中判断 cache 大小能否降下来的方法,能降下来就是能 sync wash 出来。

cache 预热

OceanBase 数据库 V4.0 及以后的版本支持 cache 预热功能,之前版本没有此功能。 为缓解 compaction 后的性能抖动,在 compaction 时会将新生成的微块放入 cache 中,进行预热。 预热并不会将所有新生成的微块都预热进 cache ,而是根据租户的内存情况进行预热。现有策略下,data block cache 使用租户空闲内存的 5% ,index block 使用租户空闲内存的 2% 。 data block 和 index block 按照不同的优先级被预热进 cache ,按照中间层索引树的等级分配不同的优先级,越接近根节点的 block 优先级越高。

wash

cache 腾出自身内存的过程称为 wash ,cache 的 wash 行为分为同步 wash 和异步 wash 两种。 同步 wash 就是上文提到的 sync wash,同步腾出内存,这里不再赘述。 异步 wash 由一个后台 wash 线程完成,wash 线程会定期地根据每个租户的内存压力 ( 包括租户大小、当前 cache 大小、租户当前空闲内存等 ) 计算出租户应该 wash 出的 cache size ,然后再根据每个 memblock 的访问热度从低到高 wash 。如果压力不大,计算结果可能是 0,不做 wash ,可以根据如下日志来判断,如果有则表示 wash 线程异步 wash 了 memblock。

COMMON_LOG(INFO, "Wash memory, ","tenant_id", wash_iter->first,"cache_size", tenant_wash_info->cache_size_,"lower_mem_limit", tenant_wash_info->lower_limit_,"upper_mem_limit", tenant_wash_info->upper_limit_,"min_wash_size", tenant_wash_info->min_wash_size_,"max_wash_size", tenant_wash_info->max_wash_size_,"mem_usage", lib::get_tenant_memory_hold(wash_iter->first),"reserve_mem", static_cast<int64_t>((static_cast<double>(tenant_wash_info->upper_limit_)) * tenant_reserve_mem_ratio_),"wash_size", tenant_wash_info->wash_size_);

wash 线程的异步 wash 实际上是减去 memblock 原始的引用计数,等待引用计数减为 0 时执行释放,因此:

  • 异步 wash 并不能立即释放 memblock ,需要等待不被 pin 。
  • 如果有引用计数泄漏泄漏,wash 线程一样不能 wash memblock。

手动 flush

手动 flush cache 表示手动清理指定 cache , 命令如下,目前只能在 sys 租户下执行,需要直连要 flush 的 OBServer 节点。

alter system flush kvcache [tenant tenant_name [cache 'cache_name']];

cache_name 可以在 __all_virtual_kvcache_info 中查到,常用的 cache_name 有 :user_block_cache、index_block_cache、user_row_cache、fuse_row_cache、bf_cache。

OceanBase 数据库 V4.0 及以后版本,flush 包含了立即清空的功能,预期情况下,flush 之后 cache 应该是立即被清空(若内存占用太多,flush 只清理一部分内存)。如果发生 4274 的报错,是 cache 较多导致的超时问题,再次 flush 即可。

OceanBase 数据库 V4.0 之前版本,手动 flush 只会清除指定 cache 中 KV 的索引,索引删除后,对应的 KV 就无法再被访问到,其所在的 memblock 的热度就会持续降低,等待 wash 线程将其 wash 出去。

判断手动 flush 是否生效

无论新老版本,手动 flush 一定会清理掉全部的 kv_cnt ,可以观察 flush 前后 kv_cnt 是否清零过来判断手动 flush 是否生效。

select * from __all_virtual_kvcache_info where cache_name = '<cache_name>';

监控 cache handle ,排查引用计数泄漏

OceanBase 数据库 V4.0 及之后版本,如果怀疑或确认 cache 引用计数有泄漏,可以通过如下方法诊断。

  1. binary 需要启用 ENABLE_DEBUG_LOG 编译选项。

  2. 打开监控,指定监控的 cache name 。

    alter system set leak_mod_to_check = 'cache_name';
    
  3. 查看泄漏 backtrace 。

    select * from __all_virtual_kvcache_handle_leak_info where tenant_id = tenant_id order by hold_count desc limit 10;
    

    在 OceanBase 数据库 V4.3 及以后版本虚拟表更名为 __all_virtual_storage_leak_info,并且新增配置项 _storage_leak_check_mod 用于指定泄漏监控的内容。

    这里简单介绍一下监控的实现方法。cache 对外吐出的引用计数都包含在 cache_handle 中,一个 cache_handle hold 住 1 个引用计数,所以在 cache 对外吐出 cache_handle 时,记录一条 backtrace ,在 cache_handle reset 时,消除记录。所以最后遗留下来未释放的 backtrace 很大可能就是泄漏的 backtrace 。

    根据记录方式可以知道,只要当前 cache 外部有 cache_handle ,那就会被记录 backtrace ,所以任何路径在持有 cache_handle 期间都会被记录,需要抓到持有时间过长或不符合预期的堆栈才是泄漏的堆栈。

    如果事先没有开启 cache handle 监控,可以通过 __all_virtual_kvcache_store_memblock 虚拟表简要确认一下问题,这张表会输出当前 server 上所有 memblock 的信息。 (OceanBase 数据库 V 4.3 及以后版本使用新的虚拟表)

    select * from __all_virtual_kvcache_store_memblock where ... order by ref_count desc limit 10;
    

    关注 ref_count 列,这一列表示 memblock 的当前的引用计数,目前当 memblock 没有被引用时,这里拿到的引用计数为 2 ( 初始引用计数为 1 ,查 memblock 信息时需要先加引用计数做保护,因此为 2 ) 。在确保某 memblock 当前不会被 pin 的前提下,ref_count 大于 2 的 memblock 都可以认为有引用计数泄漏。

泄漏检测扩展 (OceanBase 数据库 V4.3 及以后版本)

OceanBase 数据库 V4.3 及以后版本,新增存储层的泄漏检测功能,目前支持的检测内容有 cache handle、io handle、storage iter ,同时,新增配置项 _storage_leak_check_mod 用于配置泄漏检测的内容,有效值分别为 cache_name / all_cache / io_handle / storage_iter ,默认为空串,设定成空串或其他值时,关闭监控。

同时,__all_virtual_kvcache_handle_leak_info 虚拟表更名为 __all_virtual_storage_leak_info

检测步骤使用新的配置和虚拟表即可:

  1. binary 需要启用 ENABLE_DEBUG_LOG 编译选项。

  2. 打开监控,指定监控的内容。

    alter system set _storage_leak_check_mod = 'cache_name' | 'all_cache' | 'io_handle' | 'storage_iter' ;
    
  3. 查看泄漏 backtrace。

    select * from __all_virtual_storage_leak_info where ... order by hold_count desc limit 10;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/14552.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HAL库点LED灯

文章目录 一、创建CubeMX项目操作步骤1.STM32CubeMX创建工程2.选择芯片3.Pinout & Configuration配置4.Clock Configuration配置5.Project Manager配置 二、实验&#xff08;一&#xff09;LED流水灯1.Keil修改代码2.实验现象3.keil波形仿真 &#xff08;二&#xff09;2只…

代码随想录(栈和队列)

用栈实现队列&#xff08;Leetcode232&#xff09; package 栈和队列;import java.util.ArrayList; import java.util.Stack; 思路&#xff1a;1、用一个栈stack2来存压入的数&#xff0c;当要pop或peek操作时再压入stack中&#xff0c;实现队列顺序2、不是每次pop都从stack2中…

没有CAN硬件,在Linux下模拟使用Socket CAN

即使没有实际的CAN硬件,我们仍然可以在Linux下使用socketcan进行模拟。这可以通过使用虚拟的CAN接口(vcan)来实现。vcan接口是Linux内核提供的虚拟CAN总线接口,适用于开发和测试socketcan应用。 以下是如何设置和使用vcan接口的步骤: 1. 加载vcan模块 首先,你需要确保…

变量命名的艺术:让你的代码更具可读性

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言&#xff1a;为何变量命名如此重要&#xff1f; 二、变量命名的基本规则 1. 避免数…

卷爆短剧出海:五大关键,由AIGC重构

短剧高温下&#xff0c;谈谈AIGC的助攻路线。 短剧&#xff0c;一个席卷全球的高温赛道。 以往只是踏着霸总题材&#xff0c;如今&#xff0c;内容循着精品化、IP化的自然发展风向&#xff0c;给内容、制作、平台等产业全链都带来新机&#xff0c;也让短剧消费走向文化深处&am…

Docker仅需3步搭建免费私有化的AI搜索引擎-FreeAskInternet!

简介 FreeAskInternet 是一个完全免费、私有且本地运行的搜索引擎&#xff0c;并使用 LLM 生成答案&#xff0c;无需 GPU。用户可以提出问题&#xff0c;系统会进行多引擎搜索&#xff0c;并将搜索结果合并到ChatGPT3.5 LLM中&#xff0c;并根据搜索结果生成答案。 什么是 Fr…

重学java 39.多线程 — 线程安全

逐渐成为一个情绪稳定且安静成长的人 ——24.5.24 线程安全 什么时候发生&#xff1f; 当多个线程访问同一个资源时&#xff0c;导致了数据有问题&#xff0c;出现并发问题&#xff0c;数据不能及时更新&#xff0c;导致数据发生错误&#xff0c;出现线程安全问题 多线程安全问…

纹理映射技术在AI去衣中的艺术与科技融合

引言&#xff1a; 在数字图像处理的世界里&#xff0c;AI去衣技术正逐步揭开其神秘的面纱。这门技术结合了深度学习的智能算法与图形学的先进手段&#xff0c;以实现对图像中衣物的智能识别与处理。在这一过程中&#xff0c;纹理映射技术发挥着至关重要的作用。本篇博客将深入探…

变量命名的艺术:从蛇形到驼峰

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、蛇形命名法的魅力 二、类名和模块名的特殊规则 三、驼峰命名法的魅力与挑战 四、保持…

【kubernetes】探索k8s集群中kubectl的陈述式资源管理

目录 一、k8s集群资源管理方式分类 1.1陈述式资源管理方式&#xff1a;增删查比较方便&#xff0c;但是改非常不方便 1.2声明式资源管理方式&#xff1a;yaml文件管理 二、陈述式资源管理方法 2.1查看版本信息 2.2查看资源对象简写 2.3配置kubectl自动补全 2.4node节点…

初始Java篇(JavaSE基础语法)—— 内部类

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaSE 目录 内部类的概念 内部类的种类 使用举例&#xff1a; 1. 静态内部类&#xff1a; 2. 实例内部类 3. 局部内部类 4. 匿名内部…

1分钟带你搞定Pandas DataFrame运算

1. DataFrame之间的运算 在运算中自动对齐不同索引的数据 如果索引不对应&#xff0c;则补NaN DataFrame没有广播机制 导包 # 导包import numpy as npimport pandas as pd 创建 DataFrame df1 不同人员的各科目成绩&#xff0c;月考一 # 创建DataFrame二维数组df1 pd.Da…

想要修改Excel表格内容,怎么移除编辑权限?

在使用Excel进行数据处理和管理时&#xff0c;我们经常会遇到需要保护工作表以防止误操作的情况。有时可能碰到“被保护单元格不支持此功能”的提示&#xff0c;本文将详细介绍这个问题的解决方案&#xff0c;帮助你取消单元格保护&#xff0c;使用所需的功能。 一、取消单元格…

leetcode刷题记录:前缀和

https://labuladong.online/algo/problem-set/perfix-sum/#%E8%A7%A3%E6%B3%95%E4%BB%A3%E7%A0%81-3 适用范围&#xff1a;快速、频繁地计算一个索引区间内的元素之和 303 区域和检索&#xff1a;数组不可变 https://leetcode.cn/problems/range-sum-query-immutable/ class …

【Unitydemo制作】音游制作—排行榜逻辑Json存储

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

GQL 来了!ISO/IEC 正式发布 GQL 数据库国际标准!

历时四年筹备&#xff0c;超过20个国家的标准和技术专家参与制定&#xff0c;ISO/IEC GQL &#xff08;图查询语言&#xff09;标准于2024年4月12日正式发布&#xff01; 作为国际标准化组织&#xff08;ISO&#xff09;继 1987年 发布SQL后&#xff0c;唯一发布的数据库查询语…

瑞米派Ubuntu系统移植指南-米尔RemiPi

1.概述 Linux系统平台上有许多开源的系统构建框架&#xff0c;这些框架方便了开发者进行嵌入式系统的构建和定制化开发&#xff0c;目前比较常见的有Buildroot, Yocto, OpenEmbedded等等。 同时更多的传统的桌面系统也加入到嵌入式环境体系中&#xff0c;如Ubuntu&#xff0c…

Marin说PCB之POC电路layout设计仿真案例---03

今天天中午午休的时候&#xff0c;我刚要打开手机的准备刷抖音看无忧传媒的学生们的“学习资料”的时候&#xff0c;看到CSDN -APP上有提醒&#xff0c;一看原来是一位道友发的一个问题&#xff1a; 本来小编最近由于刚刚从国外回来&#xff0c;手上的项目都已经结束了&#xf…

如何制作正方形,给 placeholder 换颜色,多行省略号,纯css小三角,清除浮动,清除 margin,隐藏滚动条,隐藏 number 小图标

https://www.npmjs.com/package/sass-runtime-tool yarn add sass-runtime-tool -D # or npm i -D sass-runtime-tool use "sass-runtime-tool/all.scss" as *;// 改变 placeholder 的颜色和大小 .input {include placeholder(red) {font-size: 12px;} } /* 或者 *…

一个模板元函数来检查一个类是否有一个特定的成员

通过创建一个模板元函数来检查一个类是否有一个特定的成员。以下是一个例子&#xff1a; #include <type_traits>template<typename T, typename void> struct has_type_member : std::false_type {};template<typename T> struct has_type_member<T, s…