суббота, 26 сентября 2015 г.

Transparent Huge Pages

         Red Hat сделала "классную" фичу в ядре Linux называемую Transparent Huge Pages (THP).  Её суть в том что они пытаются научить приложения, не знающие ничего о huge pages работать с ними. Прозрачно подменяют обычные страницы памяти на huge pages. Все выглядит круто на бумаге, и даже в синтетических тестах - согласно их бенчмаркам THP на 10% ускоряют абстрактное приложение  http://www.slideshare.net/raghusiddarth/transparent-hugepages-in-rhel-6
        Но в реальной жизни получается несколько иначе. В некоторых случаях THP вызывает ничем не мотивированное увеличение потребления CPU в режиме ядра. Спасибо Oracle за то что они поделились своими наблюдениями - https://blogs.oracle.com/linux/entry/performance_issues_with_transparent_huge  К сожалению я еще не познал в достаточной мере кунг-фу linux perf, и надо сказать подобное поведение ядра поставило меня в тупик. 
          В общем всем советую добавить
echo never >> /sys/kernel/mm/redhat_transparent_hugepage/enabled

Elastic Search

      В последние пол года довольно много пришлось заниматься ElasticSearch. За это время многое о нем у знал, многое понял. Решил поделится со всеми своими открытиями.
      Первое и наверное самое главное. Обновления в ElasticSearch не real time. Под капотом там старые добрые lucene индексы, которые как были append-only так ими и остались. ElasticSearch очень крут тем что тебе не надо самому организовывать эту псевдо-реалтаймовость обновления индексов. Он сразу предоставляет тебе абстракции базы данных (get/update/delete), и дефолтное значение refresh_interval=1s некоторое время поддерживает данную иллюзию. Но во первых 1s время обновление это не реалтайм не разу, во вторых опыт показывает что при большой нагрузке эластик с таким refresh_interval очень плохо себя чувствует. Вы будете вынуждены либо группировать апдейты у себя в коде либо увеличивать refresh_interval.
   Второе: оптимальный размер jvm heap для эластика примерно половина доступной оперативки. Вторую половину оперативки он использует неявно, через кэши операционной системы.
    Третье: ElasticSearch очень чувствителен к сетевым проблемам. Как только случается сетевая задержка большая чем zen.discovery.timeout нода отваливается от кластера. Через  секунду она снова присоеденится к кластеру и начнет процесс восстановления. Будет скачивать с других нод шарды которые раньше на ней находились. Причем делает это ElasticSearch в несколько потоков чем очень не слабо нагружает кластер. Настолько не слабо что часто это приводит к тому что весь кластер складывается как карточный домик. Просто из-за того что сеть мигнула на одном из серверов. Возможно вам стоит ограничить количество шард которые ElasticSearch будет восстанавливать одновременно. Чем меньше параллельных потоков - тем меньше нагрузка на другие ноды. И тем больше время требуемое на присоединение ноды обратно. И обязательно посмотрите на zen.discovery.timeout - это значение должно соответствовать качеству вашей сети. 
        Четвертое: я бы очень НЕ рекомендовал вам использовать ноды с разной пропускной способностью в одном кластере. Эластик исходит из того что все ноды одинаковые и распределяет нагрузку соответствующим образом.  То есть размеры шард, их распределение по нодам. Как только самая слабая нода в кластере перестает справляться со своей нагрузкой - весь кластер встает колом. Если есть какая-то слабая нода - лучше либо вообще отцепить ее от кластера либо сделать ее вспомогательной нодой (не хранящей данные). 
             Пятое: важно выбрать правильный баланс между количеством реплик и затратами на обновление индекса и восстановлением кластера. Чем больше у вас реплик - тем большее время потребуется на восстановление кластера и тем больше ресурсов будут затрачивать обновление индексов.
             Шестое: Не питайте напрасных надежд - ElasticSearch это не база данных. Он не должен быть primary хранилищем данных. Смело ставьте action.write_consistency: one. Это очень сильно ускорит выполнение обновлений индекса.
             Седьмое: Ограничте размер threadpool.search.queue_size. Если кластеру плохо, то есть скорость обработки запросов  сильно меньше скорости их выполнения  какая бы ни была очередь - она наполняется моментально. Если эта очередь большая - она только отъесть оперативную память, которой и так не хватает в такие моменты. Мы прекрасно живем с threadpool.search.queue_size: 500 и примерно 30 000rps. 
        Восьмое: обратите внимание на  field data cache Его построение это очень затратная операция, если у вас интенсивно наполняется сбрасывается этот кэш - производительность будет очень страдать. Еще советую посмотреть на использование doc_value - возможно это избавит вас от многих проблем с памятью.
      Девятое: обратите внимание сколько аггрегаций делается в запросах к ElasticSearch. Аггрегации это довольно затратная операция, если есть способ уменьшить их количество - это сильно уменшит время выполнения запроса. 
           Десятое: про marvel наверное все знают, думаю нет смысла писать что это must have. Но кроме него есть еще один очень полезный плагин для ElasticSearch - HQ