关于linux:Pod进程内存缓存分析

41次阅读

共计 6562 个字符,预计需要花费 17 分钟才能阅读完成。

背景

在应用 kubernetes 过程中,能够通过kubectl top pod 命令能够查看到各个 Pod 内存应用状况,从而发现与 Pod 过程理论应用内存不统一,具体情况如下:

Java 利用部署在 kubernetes 中,配置的 JVM 参数为 -Xmx2048m -Xms2048m Pod memory request 设置为 3G,memory limit 为 4G

查看目前 Pod 已应用内存

# kubectl top pods         
gateway-5bf49bcb7-7mj99           98m          3046Mi 

而后咱们通过 top 命令进行查看内存应用状况

top - 15:29:03 up 140 days, 13:13,  0 users,  load average: 0.49, 0.46, 0.51
Tasks:   5 total,   1 running,   4 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.8 us,  1.8 sy,  0.0 ni, 93.8 id,  0.5 wa,  0.0 hi,  0.1 si,  0.0 st
MiB Mem :  32011.6 total,    239.0 free,  13934.4 used,  17838.2 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.  17679.0 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND           
    8 root      20   0 7761.2m   2.0g  15.2m S  10.3   6.3  77:27.35 java             
    1 root      20   0    2.3m   0.7m   0.5m S   0.0   0.0   0:00.01 sh               
    7 root      20   0    5.5m   1.7m   1.3m S   0.0   0.0   0:00.00 run.sh           
 1349 root      20   0    5.8m   2.2m   1.6m S   0.0   0.0   0:00.02 bash             
 1355 root      20   0    9.5m   1.8m   1.3m R   0.0   0.0   0:00.01 top 

通过如上操作能够看出,通过kubectl top pods 能够看到应用内存为 3046M, 而通过 top 命令能够应用内存为 2.0G,由此能够看出 Pod 内存要高于理论应用内存。

Pod 内存指标详解

通过kubectl top pods 获取监控指标数据都是 Prometheus metrics 组件来实现,接下来介绍下比拟罕用的监控指标;

  • kube_pod_container_resource_limits Pod 内存限度
  • kube_pod_container_resource_requests Pod 所需内存
  • container_memory_working_set_bytes Pod 理论应用内存,也是 limit 限度时的 oom 判断根据
  • container_memory_rss Pod 过程应用内存

Linux 缓存机制引入

缓存机制介绍

在 Linux 零碎中,为了进步文件系统性能,内核利用一部分物理内存调配出缓冲区,用于缓存零碎操作和数据文件,当内核收到读写的申请时,内核先去缓存区找是否有申请的数据,有的话间接返回,如果没有则通过驱动程序间接操作磁盘。

缓存机制长处: 缩小零碎调用次数,升高 CPU 上下文切换和磁盘拜访频率

CPU 上下文切换: CPU 给每个过程肯定的服务工夫,当工夫片用完后,内核从正在运行的过程中发出处理器,同时把过程以后运行状态保留下来,而后加载下一个工作,这个过程叫做上下文切换。本质上就是被终止运行过程与待运行过程的过程切换。

查看缓存区及内存应用状况

# free -m
              total        used        free      shared  buff/cache   available
Mem:           3790        1914         126           3        1750        1579
Swap:             0           0  
  • total 总内存
  • used 已应用内存
  • free 闲暇内存
  • shared 多个过程共享的内存总额
  • buff/cache 缓存占用内存
  • available 可用内存大小

从下面的命令结果显示中能够看出:总内存为 4G, 已应用 1914M,残余 126M, 不少的人都是这么看的。

但其实这样不能作为理论的使用率,因为有了缓存机制,具体算法如下:

闲暇内存 =free(126)+buffers(0)+cached(1750)
已用内存 =total(3790)- 闲暇内存

buffers 和 cached

缓存(cached) 是把读取过的数据保存起来,从新读取时若命中(找到须要的数据)就不要去读硬盘了,若没有命中就读硬盘。其中的数据会依据读取频率进行组织,把最频繁读取的内容放在最容易找到的地位,把不再读的内容一直往后排,直至从中删除。

缓冲(buffers)是依据磁盘的读写设计额,把扩散的写操作集中进行,缩小磁盘碎片和硬盘的重复寻道,从而进步零碎性能。Linux 有一个守护过程定期清理缓存内存(即写入磁盘),也能够通过 sync 命令手动清空缓冲。举个例子吧:我这里有一个 ext2 的 U 盘,我往里面 cp 一个 3M 的 MP3,但 U 盘的灯没有跳动,过了一会儿(或者手动输出 sync)U 盘的灯就跳动起来了。卸载设施时会清空缓冲,所以有些时候卸载一个设施时要等上几秒钟。

批改 /etc/sysctl.conf 中的 vm.swappiness 左边的数字能够在下次开机时调节 swap 应用策略。该数字范畴是 0~100,数字越大越偏向于应用 swap。默认为 60,能够改一下试试。–两者都是 RAM 中的数据。

<u> 两者都是 RAM 中的数据,简略来说,buffer 是行将要被写入磁盘的,而 cache 是被从磁盘读出来的 </u>

buffer 是由各种过程调配的,被用在如输出队列等方面。一个简略的例子如某个过程要求有多个字段读入,在所有字段被读入残缺之前,过程把先前读入的字段放在 buffer 中保留。
cache 常常被用在磁盘的 I / O 申请上,如果有多个过程都要拜访某个文件,于是该文件便被做成 cache 以不便下次被拜访,这样可进步零碎性能。

Cache:缓冲区,高速缓存,是位于 CPU 与主内存间的一种容量较小但速度很高的存储器。

因为 CPU 的速度远高于主内存,CPU 间接从内存中存取数据要期待肯定工夫周期,Cache 中保留着 CPU 刚用过或循环应用的一部分数据,当 CPU 再次应用该局部数据时可从 Cache 中间接调用, 这样就缩小了 CPU 的等待时间, 进步了零碎的效率。Cache 又分为一级 Cache(L1 Cache)和二级 Cache(L2 Cache),L1 Cache 集成在 CPU 外部,L2 Cache 晚期个别是焊在主板上, 当初也都集成在 CPU 外部,常见的容量有 256KB 或 512KB L2 Cache。它是依据程序的局部性原理而设计的,就是 cpu 执行的指令和拜访的数据往往在集中的某一块,所以把这块内容放入 cache 后,cpu 就不必在拜访内存了,这就进步了访问速度。当然若 cache 中没有 cpu 所须要的内容,还是要拜访内存的。从内存读取与磁盘读取角度思考,cache 能够了解为操作系统为了更高的读取效率,更多的应用内存来缓存可能被再次拜访的数据。

Cache 并不是缓存文件的,而是缓存块的(块是 I / O 读写最小的单元);Cache 个别会用在 I / O 申请上,如果多个过程要拜访某个文件,能够把此文件读入 Cache 中,这样下一个过程获取 CPU 控制权并拜访此文件间接从 Cache 读取,进步零碎性能。

Buffer:缓冲区,一个用于存储速度不同步的设施或优先级不同的设施之间传输数据的区域

通过 buffer 能够缩小过程间通信须要期待的工夫,当存储速度快的设施与存储速度慢的设施进行通信时,存储慢的数据先把数据寄存到 buffer,达到肯定水平存储快的设施再读取 buffer 的数据,在此期间存储快的设施 CPU 能够干其余的事件。

Buffer:个别是用在写入磁盘的,例如:某个过程要求多个字段被读入,当所有要求的字段被读入之前曾经读入的字段会先放到 buffer 中。Buffer 是依据磁盘的读写设计的,把扩散的写操作集中进行,缩小磁盘碎片和硬盘的重复寻道,从而进步零碎性能。linux 有一个守护过程定期清空缓冲内容(即写入磁盘),也能够通过 sync 命令手动清空缓冲。

cache 是高速缓存,用于 CPU 和内存之间的缓冲;
buffer 是 I / O 缓存,用于内存和硬盘的缓冲;

cache 最后用于 cpu cache,次要起因是 cpu 与 memory,因为 cpu 快,memory 跟不上, 且有些值应用次数多,所以放入 cache 中,次要目标是,重复使用,并且一级 \ 二级物理 cache 速度快,
buffer 次要用于 disk 与 memory,次要是爱护硬盘或缩小网络传输的次数(内存数据体现 dataSet).当然也能够进步速度(不会立刻写入硬盘或间接从硬盘中读出的数据马上显示),重复使用,最后最次要的目标是爱护 disk,

Free 中的 buffer 和 cache:(它们都是占用内存):
buffer : 作为 buffer cache 的内存,是块设施的读写缓冲区
cache: 作为 page cache 的内存, 文件系统的 cache

如果 cache 的值很大,阐明 cache 住的文件数很多。如果频繁拜访到的文件都能被 cache 住,那么磁盘的读 IO bi 会十分小。

<u> 上面通过一些简略艰深的例子来阐明下 Cache 和 Buffer 缓存之间的区别:</u>

1)Cache 缓存

假如某地产生了自然灾害(比方地震),居民缺衣少食,于是派救火车去给若干个居民点送水。救火车达到第一个居民点,开闸放水,老百姓就拿着盆盆罐罐来接水。如果说救火车在一个居民点停留 100 分钟放完了水,而后从新储水花半个小时,再开往下一个居民点。这样一个白天来来来回回的,也就是 4 - 5 个居民点。

但咱们想想,救火车是何等存在,如果把水龙头齐全关上,其弱小的水压能轻易冲上 10 层楼以上,10 分钟就能够把水全副放完。但因为居民是拿盆罐接水,100% 关上水龙头那就是给人洗澡了,所以只能关上一小部分(比方 10% 的流量)。但这样就升高了放水的效率(只有原来的 10% 了),10 分钟变 100 分钟。

那么,咱们是否能改良这个放水的过程,让救火车以最高效率放完水、尽快赶往下一个居民点呢?
办法就是:在居民点建蓄水池。
救火车把水放到蓄水池里,因为是以 100% 的效率放水,10 分钟完结而后走人。居民再从蓄水池里一点一点的接水。

咱们剖析一下这个例子,就能够晓得 Cache 的含意了。

救火车要给居民送水,居民要从救火车接水,就是说居民和救火车之间有交互,有分割。
但救火车是 ” 高速设施 ”,居民是 ” 低速设施 ”,低速的居民跟不上高速的救火车,所以救火车被迫升高了放水速度以适应居民。
为了防止这种状况,在救火车和居民之间多了一层 ” 蓄水池(也就是 Cache)”,它一方面以 100% 的高效和救火车打交道,另一方面以 10% 的低效和居民打交道,这就解放了救火车,让其以最高的效率运行,而不被低速的居民拖后腿,于是救火车只须要在一个居民点停留 10 分钟就能够了。
所以说,蓄水池是 ” 活雷锋 ”,把高效留给他人,把低效留给本人。把 10 分钟留给救火车,把 100 分钟留给本人。

从以上例子能够看出,所谓 Cache,就是 ” 为了补救高速设施和低速设施之间的矛盾 ” 而设立的一个中间层。因为在事实里经常出现高速设施要和低速设施打交道,后果被低速设施拖后腿的状况。Cache 的存在是为了解决什么问题?速度太慢了,要 加快速度!

以 PC 为例。CPU 速度很快,但 CPU 执行的指令是从内存取出的,计算的后果也要写回内存,但内存的响应速度跟不上 CPU。CPU 跟内存说:你把某某地址的指令发给我。内存听到了,但因为速度慢,迟迟不见指令返回,这段时间,CPU 只能鸿鹄之志的期待了。这样一来,再快的 CPU 也施展不了效率。
怎么办呢?在 CPU 和内存之间加一块 ” 蓄水池 ”,也就是 Cache(片上缓存),这个 Cache 速度比内存快,从 Cache 取指令不须要期待。当 CPU 要读内存的指令的时候先读 Cache 再读内存,但一开始 Cache 是空着的,只能从内存取,这时候确实是很慢,CPU 须要期待。但从内存取回的不仅仅是 CPU 所须要的指令,还有其它的、以后不须要的指令,而后把这些指令存在 Cache 里备用。CPU 再取指令的时候还是先读 Cache,看看外面有没有所需指令,如果碰巧有就间接从 Cache 取,不必期待即可返回(命中),这就解放了 CPU,进步了效率。(当然不会是 100% 命中,因为 Cache 的容量比内存小)

2)Buffer 缓存

比如说吐鲁番的葡萄熟了,要用大卡车装葡萄运出去卖果园的姑娘采摘葡萄,当然不是前手把葡萄摘下来, 后手就放到卡车上,而是须要一个两头过程 ” 箩筐 ”:摘葡萄→放到箩筐里→把箩筐里的葡萄倒入卡车。也就是说,尽管最终目标是 ” 把葡萄倒入卡车 ”,但两头必须要通过 ” 箩筐 ” 的转手,这里的箩筐就是 Buffer。是 ” 临时寄存物品的空间 ”。
留神 2 个关键词:临时,空间
再换句话说,为了实现最终目标:把葡萄放入卡车的空间,须要临时把葡萄放入箩筐的空间。

以 BT 为例,BT 下载须要长时间的挂机,电脑就有可能 24 小时连轴转,但 BT 下载的数据是碎片化的,体现在硬盘写入上也是碎片化的,因为硬盘是机械寻址器件,这种碎片化的写入会造成硬盘长时间高负荷的机械运动,造成硬盘过早老化损坏,当年有大量的硬盘因为 BT 下载而损坏。于是新出的 BT 软件在内存里开拓了 Buffer,数据临时写入 Buffer,攒到肯定的大小(比方 512M)再一次性写入硬盘,这种 ” 化零为整 ” 的写入形式大大降低了硬盘的负荷。这就是:为了实现最终目标:把数据写入硬盘空间,须要临时写入 Buffer 的空间。

3)二者之间的区别总结

Cache 和 Buffer 的相同点:都是 2 个层面之间的中间层,都是内存。
Cache 和 Buffer 的不同点:Cache 解决的是工夫问题,Buffer 解决的是空间问题。
为了进步速度,引入了 Cache 这个中间层。
为了给信息找到一个暂存空间,引入了 Buffer 这个中间层。
为了解决 2 个不同维度的问题(工夫、空间),凑巧取了同一种解决办法:退出一个中间层,先把数据写到中间层上,而后再写入指标。
这个中间层就是内存“RAM”,既然是存储器就有 2 个参数:写入的速度有多块(速度),能装多少货色(容量)
Cache 利用的是 RAM 提供的高读写速度,Buffer 利用的是 RAM 提供的存储容量(空间)。

简言之:

  • Buffer(缓冲区)是零碎两端处理速度均衡(从长时间尺度上看)时应用的。它的引入是为了减小短期内突发 I / O 的影响,起到流量整形的作用。比方生产者——消费者问题,他们产生和耗费资源的速度大体靠近,加一个 buffer 能够对消掉资源刚产生 / 耗费时的忽然变动。
  • Cache(缓存)则是零碎两端处理速度不匹配时的一种折衷策略。因为 CPU 和 memory 之间的速度差别越来越大,所以人们充分利用数据的局部性(locality)特色,通过应用存储系统分级(memory hierarchy)的策略来减小这种差别带来的影响。
  • 假设当前存储器拜访变得跟 CPU 做计算一样快,cache 就能够隐没,然而 buffer 仍然存在。比方从网络上下载货色,刹时速率可能会有较大变动,但从长期来看却是稳固的,这样就能通过引入一个 buffer 使得 OS 接收数据的速率更稳固,进一步缩小对磁盘的挫伤。

Pod 过程内存缓存解释

目前曾经对 Linux 缓存已有了大略理解,接下来咱们对 Pod 内存进行剖析了!

首先咱们通过 kubectl top pods 查看的内存指标对应的是 Prometheus metrics 组件的container_memory_working_set_bytes 指标(过程缓存应用内存 + 过程应用内存),在 kubernetes 集群中同时做为 Pod HPA 弹性伸缩与 limit 限度(oom) 的判断根据,当 Pod 内存行将达到内存限度则会回收内存。

# kubectl top pods         

gateway-5bf49bcb7-7mj99           98m          3046Mi 

能够构想下,如果 limit 限度的判断根据为过程理论应用内存,则 Pod 过程理论应用内存必定大于限度内存,这样会呈现什么状况呢?

答:如上状况,会导致 Pod 内存得不到限度,cache 缓存有限应用内存,得不到正当的回收。所以 Pod limit 限度应用container_memory_working_set_bytes 指标(过程缓存应用内存 + 过程应用内存)做为判断根据再好不过了

点击 “ 浏览原文 ” 获取更好的浏览体验!

正文完
 0