Lichen Liu

与其感慨路难行,不如马上出发

  • 主页
所有文章 友链 关于我

Lichen Liu

与其感慨路难行,不如马上出发

  • 主页

NUMA 内存策略 preferred 的效果

2020-02-20

和聂工一起在如何在硬件资源有限的情况下尽量多的运行虚拟机的泥潭中苦苦挣扎。

想利用numa 的优势,但又因为内存资源总是不够,使用strict 的策略可能会导致oom,只好允许进程跨numa node 使用内存。
当在一台启用了numa 的物理机上,通过libvirt 的xml 给虚拟机添加内存策略preferred 后,期待的是它会先使用preferred 的node 上的内存,只有这个node 上的内存不足时,才考虑使用其他node.
但实际部署下来,经常发现很多进程在两个node 上都有内存,但通过numastat -m 来看其实preferred 的node 上往往还有不少可释放的buffer/cache 等。

后来查询得知这个行为和zone_reclaim_mode 有关。当zone_reclaim_mode 为0 时,如果当前zone 的内存低于low 水线,会倾向于从其他zone 申请内存,而所有的zone 按照numa 访问代价排成一个list,按顺序依次检查这些zone 的free pages 和low 水线的关系,并尝试分配内存。
当zone_reclaim_mode 为1 时,会倾向于先对当前zone 进行内存回收,回收一部分buffer/cache 后如果满足需求则从当前zone 进行分配。

从代码上来看,通过alloc_pages_nodemask 分配内存时,会调用get_page_from_freelist 函数,而当该函数分配不出page 时,则进入alloc_pages_slowpath.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// mm/page_alloc.c
/*
* This is the 'heart' of the zoned buddy allocator.
*/
struct page *
__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,
nodemask_t *nodemask)
{
...
unsigned int alloc_flags = ALLOC_WMARK_LOW;
...
if (!prepare_alloc_pages(gfp_mask, order, preferred_nid, nodemask, &ac, &alloc_mask, &alloc_flags)) // 这里根据preferred 的node id 构建zone list,存在ac 中。
return NULL;
...
page = get_page_from_freelist(alloc_mask, order, alloc_flags, &ac);
if (likely(page))
goto out;
...
page = __alloc_pages_slowpath(alloc_mask, order, &ac);
out:
...
}

只观察get_page_from_freelist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 // mm/page_alloc.c
/*
* get_page_from_freelist goes through the zonelist trying to allocate
* a page.
*/
static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,
const struct alloc_context *ac)
{
...
for_next_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx,// 遍历已经通过访问代价排序的zone list
ac->nodemask) {
...
mark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK); // 这里的alloc_flags 是从__alloc_pages_nodemask 传进来的参数,是ALLOC_WMARK_LOW 和其他flags 或起来的结果。
if (!zone_watermark_fast(zone, order, mark, // 这里会检查free pages 是否低过low 水线。不低于low 水线可以直接尝试从该zone 分配内存。
ac_classzone_idx(ac), alloc_flags)) {
...
if (node_reclaim_mode == 0 || // 低于low 水线的情况下,检查node_reclaim_mode,如果为0 或zone 不允许reclaim 则跳过该zone.
!zone_allows_reclaim(ac->preferred_zoneref->zone, zone))
continue;

ret = node_reclaim(zone->zone_pgdat, gfp_mask, order); // 其他情况下开始对该zone 进行reclaim.
switch (ret) {
case NODE_RECLAIM_NOSCAN:
/* did not scan */
continue;
case NODE_RECLAIM_FULL:
/* scanned but unreclaimable */
continue;
default:
/* did we reclaim enough */
if (zone_watermark_ok(zone, order, mark, // reclaim 到足够的内存时,尝试从该zone 分配内存。
ac_classzone_idx(ac), alloc_flags))
goto try_this_zone;

continue;
}
}
try_this_zone:
page = rmqueue(ac->preferred_zoneref->zone, zone, order, // rmqueue 已经是尝试从当前zone 分配内存了。
gfp_mask, alloc_flags, ac->migratetype);
...
}

因此看来使用preferred 的模式时,由于buffer/cache 的存在free pages 会变少,而free 在low 以下时如果zone_reclaim_mode 为0 就会从其他zone 分配内存,所以看起来是多数进程在每个node 上都有点内存。而当zone_reclaim_mode 为1 时,倾向于先回收本zone 的buffer/cache,这个过程会导致sar 中的pgscand 上涨。

参考:https://engineering.linkedin.com/performance/optimizing-linux-memory-management-low-latency-high-throughput-databases#reproduce

  • Linux
  • numa

扫一扫,分享到微信

微信分享二维码
/dev 下的null, zero, random等文件是怎么来的
在linux kernel 源码中搜索syscall 的实现
© 2023 Lichen Liu
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • Linux
  • golang
  • xml
  • omitempty
  • test
  • art
  • AWS
  • Kernel
  • bonding
  • sk_buff
  • kernel
  • libvirt
  • libvirt-go
  • numa
  • ping
  • arp
  • 输入法
  • ovs
  • font
  • manjaro
  • 坑
  • 北京
  • 旅游

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 北京周末

    2023-03-22

    #北京#旅游

  • manjaro kde 升级后中文字体变成方块

    2021-02-18

    #font#manjaro#坑

  • sk_buff 简介

    2020-10-26

    #Linux#sk_buff#kernel

  • 使用ct_state 实现出口放行防火墙

    2020-05-15

    #ovs

  • /dev 下的null, zero, random等文件是怎么来的

    2020-03-07

    #Linux#Kernel

  • NUMA 内存策略 preferred 的效果

    2020-02-20

    #Linux#numa

  • 在linux kernel 源码中搜索syscall 的实现

    2020-02-20

    #Linux

  • 一次ping 遇到Invalid argument 报错的问题

    2020-02-11

    #Linux#ping#arp

  • Linux 网络bond mode 4 的xmit_hash_policy layer3+4 到底是如何hash 的

    2020-01-10

    #Linux#bonding

  • golang xml 如何忽略空结构体

    2020-01-09

    #golang#xml#omitempty

  • libvirt-go 的一个坑

    2020-01-07

    #golang#libvirt#libvirt-go

  • 在AWS 的Amazon Linux 上下载源码

    2019-12-23

    #Linux#AWS#Kernel

  • 中文测试

    2019-12-23

    #test#输入法

  • Hello world

    2019-12-18

    #test#art

  • 肥叉烧
  • 安全大手子
  • 物理学博士
  • 一个愣头青
普通上班族,会一点Linux, 想学SDN