масштабуючи Elasticsearch на прикладі кластера з індексами в кілька терабайт

Низька швидкість пошукових запитів
Працюючи над пошуковим движком по соціальної інформації (ark.com ), ми зупинили свій вибір на Elasticsearch, так як за відгуками він був дуже легкий у налаштуванні і використанні, мав відмінні пошукові можливості і, в цілому, виглядав як манна небесна. Так воно і було до тих пір, поки наш індекс не виросла до більш-менш пристойних розміром ~ 1 мільярда документів, розмір з урахуванням реплік вже перевалив за 1,5 ТБ.
 
Навіть банальний
Term query
міг зайняти десятки секунд. Документації по ES не так багато, як хотілося б, а гуглінг даного питання видавав результати 2х-річної давності по зовсім не актуальним версіями нашого пошукового движка (ми працюємо з 0.90.13 — що теж не досить стара річ, але ми не можемо дозволити собі опустити весь кластер, оновити його, і запустити заново на поточний момент — тільки роллінг рестарт).
 
 Низька швидкість індексації
 
Друга проблема — ми індексуємо більше документів в секунду (близько 100к), ніж Elasticsearch може обробляти. Тайм-аути, величезне навантаження на Write IO, черги з процесів в 400 одиниць. Все виглядає дуже страшно, коли дивишся на це в Marvel.
 
Як вирішувати ці проблеми — під катом
 
 

масштабуючи кластер Elasticsearch

 
 Вихідна ситуація:
 
 
     
  • 5 data nodes, http enabled:
      
       
    • 100 GB RAM
    •  
    • 16 cores

    •  
    • 4 TB HDD (7200 RPM, seagate)
    •  
      
  •  
  • Індекси:
      
       
    • від 500 до 1 млрд документів, всього 5 штук
    •  
    • кількість primary Шардена від 50 до 400 (тут ми тестували різні стратегії індексування — Ця установка дуже важлива)

    •  
    • репліки — від 2 до 5
    •  
    • розмір індексу до 1,5 терабайт
    •  
      
  •  
 
 Збільшуємо швидкість індексування в Elasticsearch
 
Ця проблема виявилося не такою складною і інформації в інтернеті по ній трохи більше.
 
Чекліст, який потрібно перевірити:
 
     
  • refresh_interval
    — як часто оновлюються дані для пошуку, чим частіше, тим більше Write IO вам потрібно
  •  
  • index.translog.flush_threshold_ops
    — через скільки операцій скидати дані на диск
  •  
  • index.translog.flush_threshold_size
    — скільки даних повинні бути додані в індекс перед скидання на диск
  •  
 
Докладна документація тут: www.elasticsearch.org / guide / en / elasticsearch / reference / current / indices-update-settings.html
 
У першу чергу ми збільшили refresh_interval до 30 секунд, і фактично збільшили пропускну здатність практично до 5000 документів в секунду. Пізніше поставили flush_threshold_ops в 5000 операцій, а розмір до 500 мб. Якщо хочете, то можна погратися з кількістю реплік, Шарден і так далі, але це не буде давати настільки великої різниці. Так само зверніть увагу на threadpool, якщо вам необхідно збільшити кількість паралельних запитів до бази, хоча найчастіше цього не потрібно.
 
 Збільшуємо швидкість запитів в Elasticsearch
 
Тепер переходимо до складної частини. Знаючи розмір нашого індексу і постійні потреби в перезавантаженні кластера (оновлення версій, мейнтенанс машин), а також беручи до уваги пости на зразок цього: gibrown.wordpress.com/2014/02/06/scaling-elasticsearch-part-2-indexing / ми вирішили, що розмір шарда в нашому індексі не перевищуватиме 1-2 ГБ. З урахуванням RF3, наш індекс (ми розраховуємо на 1,5 млрд документів), враховуючи що 0,5 млрд наших документів займають близько 300 ГБ без урахування реплік, ми створили в індексі 400 Шардена і порахували що все буде добре — швидкість ребута буде досить висока: нам не потрібно буде читати блоки даних по 50-60 ГБ, а також реплицировать їх, блокуючи таким чином відновлення маленьких Шардена, та й швидкість пошуку по маленьким Шардам вище.
 
По початку, кількість документів в індексі було невеликим (100-200 млн) і швидкість запиту становила всього 100-200 мс. Але як тільки практично всі Шардена були заповнені хоча б невеликою кількістю документів, ми почали значно втрачати в продуктивності запитів. Комбінуючи все це з високим навантаженням на IO через постійну індексації, ми могли і взагалі не виконати його.
 
У даному випадку ми здійснили 2 помилки:
 
1. Створили дуже багато Шарді (ідеальна ситуація 1 ядро ​​- 1 шард)
2. Наші дата ноди були і нодамі-балансер з включеним http — сериализация і десеріалізацію даних займає досить багато часу
 
Тому ми почали експериментувати.
 
 Добавялем ноди-балансувальників в Elaticsearch
 
Першим і очевидним кроком для нас було додаванням, так званих,
balancer nodes
в Elasticsearch. Вони можуть виробляти агрегованих результатів запитів по інших Шардена, у них ніколи не буде перевантажений IO, так як вони не виконують читання і запису на диск, і ми розвантажимо наші data nodes.
 
Для деплоя ми використовуємо chef і відповідний elasticsearch cookbook, тому створивши всього пару додаткових ролей, з наступними настройками:
 
 
name "elasticsearch-balancer"
description "Installs and launches elasticsearch"

default_attributes(
	"elasticsearch" => {
		"node" => {
			"master" => false,
			"data" => false
		}
	}
)

run_list("services::elasticsearch")

 
Ми благополучно запустили 4 балансувальника. Картина трохи покращилася — ми більше не спостерігали перевантажених нод з димлячими жорсткими дисками, але швидкість запитів була все ще низька.
 
 Збільшуємо кількість data nodes в Elasticsearch
 
Тепер ми згадали, що кількість Шардена, яке було у нас (400) жодним чином не позначається на поліпшенні продуктивності, а лише посилює її, тому що занадто більше кількість Шарден знаходиться на 1 машині. Провівши прості обчислення ми отримуємо, що 5 машин адекватно підтримають тільки 80 Шарді. Враховуючи кількість реплік, то їх у нас взагалі 1200.
 
Так як наш спільний парк машин (80 нод) дозволяє додавання досить великої кількості нод і основна проблема в них — це розмір HDD (всього 128Гб), то ми вирішили додати відразу близько 15 машин. Це дозволить працювати з ще 240 Шарден більш ефективно.
 
Крім цього ми наткнулися на декілька цікавих налаштувань:
 
*
index.store.type
— за умовчанням ставиться в niofs, а по бенчмарк продуктивність нижче ніж у mmapfs — ми переключили його на mmapfs (дефолтний стор в 1.x)
*
indices.memory.index_buffer_size
— збільшили до 30%, а кількість RAM під Java Heap навпаки зменшили до 30 ГБ (було 50%), так як з mmapfs нам потрібно набагато більше оперативки для кеша операційної системи
 
І звичайно ж, в нашому випадку було обов'язково включити настройку контролю за розташуванням Шарден на основі вільного місця:
 
 
curl -XPUT localhost:9200/_cluster/settings -d '{
    "transient" : {
        "cluster.routing.allocation.disk.threshold_enabled" : true
    }
}'

 
Після пари днів переносу Шардена і перезапуску старих серверів з новими налаштуваннями, ми провели тести і НЕ кешовані запити (Term Query, що не фільтри) виконувалися не більше 500 мс. Дана ситуація все ще не ідеальна, але ми бачимо, що додавання дата нод і підгін кількості ядер під кількість Шарден виправляє ситуацію.
 
 Що ще слід врахувати при масштабування кластера
 
При роллінг рестарт кластера, обов'язково вимикайте можливість перенесення Шарден:
cluster.routing.allocation.enable = none
, в старих версіях трохи інша настройка.
 
Якщо виникли питання під час прочитання — буду радий обговорити.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.