0
3
0
0
专栏/.../

我的内存去哪儿了?

 TiDBer_jYQINSnf  发表于  2025-04-18

背景:

今天有一个 tidb 用户反馈,为什么我的内存还没用到节点的规格(64G) 就 OOM 了。

我们的环境是基于 K8S 部署的

image.png

带着这个问题做了一番搜索,总算是能回答用户的问题了。

1. 监控面板的内存值是怎么来的:

首先看这个面板指标的定义:

avg(process_resident_memory_bytes{k8s_cluster="$k8s_cluster", tidb_cluster=~"$tidb_cluster.*", component=~".*tikv"}) by (instance)



tikv 这个指标采集的内容:









tikv 的内存计算方式:

1.从 /proc/self/stats 里获取 rss 字段,是进程实际在内存中使用占用的页数

2.拿这个页数乘以 PageSize,计算出字节数

也就是说这个值只计算了 TiKV 自己进程用的内存。

2. k8s 是根据什么值进行 OOM kill 的?

经过搜索得到 k8s 会依据 container_memory_working_set_bytes 值去 OOMKilled pod

那么 container_memory_working_set_bytes 的值都包括什么?

从网上借一个图,因为 tikv 不是 java 程序,所以没有 JVM 内存





那么关键问题就在于 k8s 把 cache file 计算在内是不是合适?

关于这个的讨论 issue 如下:

https://github.com/kubernetes/kubernetes/issues/43916

3. cache 的内存到底对 tikv 有没有用?

既然无法改变 k8s oom kill 的行为,那么 cache 的这些文件该不会全是 tikv 写的 log 吧?到底对 tikv 的 io 加速有没有用呢?

又找到了一个 vmtouch 工具。

根据 vmtouch 的结果查看:

总共缓存了 27G 的数据:





其中 raft-engine 的 raftlog 占了 6G





rocksdb 的 sst 文件占用了 19G





这两部分占了大头。

tikv 是 raft 3 副本的,按 tikv 的写逻辑:

数据首先写入 raft-engine,在写入的同时向其他 2 节点同步 raft-log, raft-log 同步完后 apply 进 kv-db. 一般情况下, raft-log 不会再从磁盘读,但是如果要新加一个 raft-peer ,就需要拿 raft-log + kv-db 中的数据向新的 peer 同步数据,这 6G 的作用不是那么明显。

但是 raft log 随着都 apply 进 kv-db, 也会不断的 gc,也就是说写入量不那么大的情况下,这些文件会比较少,文件被删掉的话自然这些内存就释放出来了。

另外一部分: rocksdb 的 sst 文件缓存有没有用呢?

根据 rocksdb 的原理,数据首先写入 memtable,然后 flush 到磁盘, 形成 sst 文件,标记为 level0 层的文件,然后这些 sst 会在 compact 到下一层的时候读取一遍,然后合并成新的文件,老的 sst 就删掉了。也就是说缓存的文件大概率会在 compact 的时候用到。这样说的话,内存也没浪费,即使没有 compact ,文件缓存到内存中,查询数据的时候也会用到。

结论:

由此可以得出结论,64G 的内存几乎全部服务于 tikv 的读写数据,是有一些浪费,但是也没那么严重。业务方不能说我们少给内存了😜。

参考:

http://mysql.taobao.org/monthly/2020/09/01/

https://blog.csdn.net/u010657094/article/details/138510248

https://github.com/kubernetes/kubernetes/issues/43916

0
3
0
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论