Выделение памяти слишком медленное

Я запускаю какой-то сервис с интенсивным использованием памяти на AWS (экземпляры m4.15xlarge и m5.12xlarge) и заметил, что в определенных условиях (обычно после определенного ограничения памяти) время, необходимое для выделения дополнительной памяти, резко увеличивается (до 50 раз).

Когда это происходит, htop показывает 100% в режиме ядра (красный), а perf top выглядит так:

  62.82%  [kernel]                                           [k] pageblock_pfn_to_page                                                              
  15.21%  [kernel]                                           [k] clear_page_c_e                                                                     
   5.78%  [kernel]                                           [k] get_pfnblock_flags_mask                                                            
   3.06%  [kernel]                                           [k] compaction_alloc                                                                   
   1.59%  [kernel]                                           [k] clear_huge_page                                                                    
   1.49%  [kernel]                                           [k] _raw_spin_lock                                                                     
   1.41%  [kernel]                                           [k] async_page_fault                                                                   
   1.29%  a.out                                              [.] memTest                                                                            
   0.99%  [kernel]                                           [k] get_page_from_freelist                                                             
   0.85%  [kernel]                                           [k] compact_zone                                                                       
   0.69%  [kernel]                                           [k] try_charge                                                                         
   0.51%  [kernel]                                           [k] error_entry                                                                        
...

В обычном режиме это выглядит так:

  66.29%  [kernel]                                           [k] clear_page_c_e
   7.05%  [kernel]                                           [k] clear_huge_page
   3.91%  a.out                                              [.] memTest
   3.66%  [kernel]                                           [k] _raw_spin_lock
   3.12%  [kernel]                                           [k] async_page_fault
   2.68%  [kernel]                                           [k] get_page_from_freelist
   1.93%  [kernel]                                           [k] _cond_resched
   1.49%  [kernel]                                           [k] try_charge
   1.12%  [kernel]                                           [k] error_entry
   1.01%  [kernel]                                           [k] retint_user
   0.93%  [kernel]                                           [k] handle_mm_fault
   0.77%  [kernel]                                           [k] mem_cgroup_try_charge
   0.67%  [kernel]                                           [k] pmd_pfn
   0.66%  [kernel]                                           [k] __rmqueue.isra.80
...

Я не совсем понимаю, что вызывает поведение. Иногда это довольно сложно воспроизвести, но иногда это происходит постоянно.

У меня есть предположение, что это связано с виртуализацией AWS (поэтому тот факт, что проблема носит периодический характер, я связываю с тем, что происходит на «соседях») (см. Обновление ниже ). Мне также не удалось воспроизвести проблему на машине m5.metal.

Мне удалось воспроизвести проблему с помощью простой программы на C, которая выделяет и инициализирует память в цикле:

void memTest(long chunk, long total) {
    struct timeval prev, cur = {0,0}, lastProgress = {0,0};
    int i, j;
    int num = total / chunk;
    int p, progress = -1;
    uint8_t *data[num];

    get_now(&prev);

    for (i = 0; i < num; i++) {
        data[i] = malloc(chunk);
        for (j = 0; j < chunk; j += 4096) {
            data[i][j] = rand()%265;
        }

        get_now(&cur);
        add(delta(&prev, &cur));
        prev = cur;

        p = (i * 20) / num * 5;

        if (p != progress) {
            if (lastProgress.tv_sec == 0) {
                printf("%s: %02d%%\n", format(&cur), p);
            } else {
                double elapsed = delta(&lastProgress, &cur);
                printf("%s: %02d%% (%gms)\n", format(&cur), p, elapsed);
            }
            lastProgress = cur;
            progress = p;
        }
    }
}
m5.12xlarge$ ./a.out --total 182714368000 --chunk 16777216
2019-03-27 05:03:22.805827: 00%
2019-03-27 05:03:25.035575: 05% (2229.75ms)
2019-03-27 05:03:27.244955: 10% (2209.38ms)
2019-03-27 05:03:29.458160: 15% (2213.2ms)
2019-03-27 05:03:31.665313: 20% (2207.15ms)
2019-03-27 05:03:33.871949: 25% (2206.64ms)
2019-03-27 05:03:36.075955: 30% (2204.01ms)
2019-03-27 05:03:38.284512: 35% (2208.56ms)
2019-03-27 05:03:40.489039: 40% (2204.53ms)
2019-03-27 05:03:42.697444: 45% (2208.41ms)
2019-03-27 05:03:44.902268: 50% (2204.82ms)
2019-03-27 05:03:47.110703: 55% (2208.43ms)
2019-03-27 05:03:49.315001: 60% (2204.3ms)
2019-03-27 05:03:51.523370: 65% (2208.37ms)
2019-03-27 05:03:53.728535: 70% (2205.16ms)
2019-03-27 05:03:55.936081: 75% (2207.55ms)
2019-03-27 05:03:58.141149: 80% (2205.07ms)
2019-03-27 05:04:00.349740: 85% (2208.59ms)
2019-03-27 05:04:02.553894: 90% (2204.15ms)
2019-03-27 05:04:04.762675: 95% (2208.78ms)
2019-03-27 05:04:41.470692: 100% (36708ms) .  <---

На этот раз мне удалось решить проблему только близко к пределу памяти, но я смог получить ее даже на 20Gb (из доступных 186Gb).

Я был бы очень признателен, если бы кто-нибудь мог пролить свет на то, что происходит, и как избавиться от этого эффекта.

Обновление:

Я еще немного поиграл с этой проблемой и в настоящее время обвиняю поддержку прозрачных огромных страниц (THP), которая была включена (always) на m5.12xlarge и отключена (madvise) на m5.metal. После переключения настроек на машинах я смог получить проблему на m5.metal, и проблема исчезла на m5.12xlarge.


person Sergey Zimin    schedule 27.03.2019    source источник
comment
Инстансы Amazon EC2 изолированы от соседей. Память не перегружена, поэтому соседи никогда не повлияют на процессор, память или доступ к диску.   -  person John Rotenstein    schedule 27.03.2019
comment
@JohnRotenstein, я думаю, вы правы, а моя гипотеза неверна. Я немного поиграл, и похоже, что проблема вызвана прозрачной поддержкой огромных страниц. . Я проверил, что эта функция включена на m5.12xlarge и отключена на m5.metal.   -  person Sergey Zimin    schedule 27.03.2019


Ответы (1)


Как указано в разделе Обновление, проблема, по-видимому, вызвана прозрачной огромной страницей (THP). Проблема уже была обнаружена MongoDB и некоторыми другими ссылка, ссылка и рекомендуется к отключению.

Есть множество вопросов о том, как отключить THP на stackoverflow и stackexchange. Например:

person Sergey Zimin    schedule 27.03.2019