一次k8s node節(jié)點(diǎn)負(fù)載高的問題

發(fā)現(xiàn)k8s某一個(gè)節(jié)點(diǎn)負(fù)載較高,但是查看內(nèi)存、CPU、IO一切都正常


image.png
image.png

最后通過執(zhí)行dmesg查看系統(tǒng)日志,發(fā)現(xiàn)以下幾行

[716542.548123] SLUB: Unable to allocate memory on node -1 (gfp=0x8050)
[716542.548127]   cache: buffer_head(3379:6ce139bebcf4c4f6181a32767d2c5414c0769f9da75a5888f1b643a567350c71), object size: 104, buffer size: 104, default order: 0, min order: 0
[716542.548130]   node 0: slabs: 0, objs: 0, free: 0
[716547.247467] ___slab_alloc: 107 callbacks suppressed

大致可以理解為無法給緩存申請(qǐng)內(nèi)存。這個(gè)SLUB是個(gè)什么東西呢

linux內(nèi)核內(nèi)存模型

然后深入了解了一下內(nèi)核內(nèi)存模型。一共有以下4種

  1. 伙伴系統(tǒng)(大對(duì)象)
    物理連續(xù)內(nèi)存,指數(shù)增加的連續(xù)頁,優(yōu)點(diǎn)快速合并

  2. slab
    cpu高速緩存中,slab列表(池)分配小對(duì)象

  3. slob
    適合嵌入式系統(tǒng)

  4. slub(2.6.24以上)
    slab升級(jí)版,簡化了數(shù)據(jù)結(jié)構(gòu)。分配優(yōu)先級(jí)1.緩存池 2.cpu未分配的緩存 3.node、也就是伙伴系統(tǒng)

看了一下__slab_alloc.c 的源碼

static void *__slab_alloc(struct kmem_cache *s,
        gfp_t gfpflags, int node, void *addr, struct kmem_cache_cpu *c)
{
    void **object;
    struct page *new;

    gfpflags &= ~__GFP_ZERO;

    if (!c->page)                                                          (a)
        goto new_slab;

    slab_lock(c->page);
    if (unlikely(!node_match(c, node)))                                (b)
        goto another_slab;

    stat(c, ALLOC_REFILL);

load_freelist:
    object = c->page->freelist;
    if (unlikely(!object))                                                (c)
        goto another_slab;
    if (unlikely(SlabDebug(c->page)))
        goto debug;

    c->freelist = object[c->offset];                                    (d)
    c->page->inuse = s->objects;
    c->page->freelist = NULL;
    c->node = page_to_nid(c->page);
unlock_out:
    slab_unlock(c->page);
    stat(c, ALLOC_SLOWPATH);
    return object;

another_slab:
    deactivate_slab(s, c);                                                (e)

new_slab:
    new = get_partial(s, gfpflags, node);                              (f)
    if (new) {
        c->page = new;
        stat(c, ALLOC_FROM_PARTIAL);
        goto load_freelist;
    }

    if (gfpflags & __GFP_WAIT)                                           (g)
        local_irq_enable();

    new = new_slab(s, gfpflags, node);                                 (h)

    if (gfpflags & __GFP_WAIT)
        local_irq_disable();

    if (new) {
        c = get_cpu_slab(s, smp_processor_id());
        stat(c, ALLOC_SLAB);
        if (c->page)
            flush_slab(s, c);
        slab_lock(new);
        SetSlabFrozen(new);
        c->page = new;
        goto load_freelist;
    }
    if (!(gfpflags & __GFP_NORETRY) &&
                (s->flags & __PAGE_ALLOC_FALLBACK)) {
        if (gfpflags & __GFP_WAIT)
            local_irq_enable();
        object = kmalloc_large(s->objsize, gfpflags);                (i)
        if (gfpflags & __GFP_WAIT)
            local_irq_disable();
        return object;
    }
    return NULL;
debug:
    if (!alloc_debug_processing(s, c->page, object, addr))
        goto another_slab;

    c->page->inuse++;
    c->page->freelist = object[c->offset];
    c->node = -1;
    goto unlock_out;
}
如果沒有本地活動(dòng) slab,轉(zhuǎn)到 (f) 步驟獲取 slab 。
如果本處理器所在節(jié)點(diǎn)與指定節(jié)點(diǎn)不一致,轉(zhuǎn)到 (e) 步驟。
檢查處理器活動(dòng) slab 沒有空閑對(duì)象,轉(zhuǎn)到 (e) 步驟。
此時(shí)活動(dòng) slab 尚有空閑對(duì)象,將 slab 的空閑對(duì)象隊(duì)列指針復(fù)制到 kmem_cache_cpu 結(jié)構(gòu)的 freelist 字段,把 slab 的空閑對(duì)象隊(duì)列指針設(shè)置為空,從此以后只從 kmem_cache_cpu 結(jié)構(gòu)的 freelist 字段獲得空閑對(duì)象隊(duì)列信息。
取消當(dāng)前活動(dòng) slab,將其加入到所在 NUMA 節(jié)點(diǎn)的 Partial 隊(duì)列中。
優(yōu)先從指定 NUMA 節(jié)點(diǎn)上獲得一個(gè) Partial slab。
加入 gfpflags 標(biāo)志置有 __GFP_WAIT,開啟中斷,故后續(xù)創(chuàng)建 slab 操作可以睡眠。
創(chuàng)建一個(gè) slab,并初始化所有對(duì)象。
如果內(nèi)存不足,無法創(chuàng)建 slab,調(diào)用 kmalloc_large(實(shí)際調(diào)用物理頁框分配器)分配對(duì)象。

根據(jù)源碼和日志,可以看出應(yīng)該是NUMA無法從node0申請(qǐng)內(nèi)存,導(dǎo)致每次都調(diào)用kmalloc_large,對(duì)性能消耗特別大。

很有可能是Cgroup的BUG,由于機(jī)器重啟了,問題暫時(shí)沒有更加深入排查,待下次復(fù)現(xiàn)的時(shí)候繼續(xù)排查

相關(guān)鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容