Дизайн learner etcd
etcd Learner
Gyuho Lee (github.com/gyuho, Amazon Web Services, Inc.), Joe Betz (github.com/jpbetz, Google Inc.)
Передумови
Переналаштування членства було однією з найбільших операційних проблем. Розгляньмо поширені проблеми.
1. Новий член кластера перевантажує Лідера
Новий член etcd починає без даних, тому вимагає більше оновлень від лідера, поки не наздожене журнали лідера. Тоді мережа лідера більш ймовірно буде перевантажена, блокуючи або скидаючи такти лідера до послідовників. У такому випадку послідовник може вийти з тайм-ауту виборів і почати нові вибори лідера. Тобто кластер з новим членом більш вразливий до виборів лідера. І вибори лідера, і подальше розповсюдження оновлень новому члену схильні викликати періоди недоступності кластера (див. Рисунок 1).
2. Сценарії розділення мережі
Що, якщо станеться розділення мережі? Це залежить від розділення лідера. Якщо лідер все ще підтримує активний кворум, кластер продовжить працювати (див. Рисунок 2).
2.1 Ізоляція лідера
Що, якщо лідер стане ізольованим від решти кластера? Лідер контролює прогрес кожного послідовника. Коли лідер втрачає звʼязок з кворумом, він повертається до послідовника, що впливає на доступність кластера (див. Рисунок 3).
Коли новий вузол додається до 3-вузлового кластера, розмір кластера стає 4, а розмір кворуму стає 3. Що, якщо новий вузол приєднався до кластера, а потім сталося розділення мережі? Це залежить від того, в якому розділі новий член опиниться після розділення.
2.2 Розділення кластера 3+1
Якщо новий вузол опиняється в тому ж розділі, що і лідер, лідер все ще підтримує активний кворум з 3. Вибори лідера не відбуваються, і доступність кластера не порушується (див. Рисунок 4).
2.3 Розділення кластера 2+2
Якщо кластер розділений на 2 і 2, жоден з розділів не підтримує кворум з 3. У цьому випадку відбуваються вибори лідера (див. Рисунок 5).
2.4 Втрата кворуму
Що, якщо спочатку станеться розділення мережі, а потім буде додано нового члена? Розділений 3-вузловий кластер вже має одного відключеного послідовника. Коли додається новий член, кворум змінюється з 2 на 3. Тепер цей кластер має лише 2 активних вузли з 4, таким чином втрачаючи кворум і починаючи нові вибори лідера (див. Рисунок 6).
Оскільки операція додавання члена може змінити розмір кворуму, завжди рекомендується спочатку “видалити члена”, щоб замінити несправний вузол.
Додавання нового члена до 1-вузлового кластера змінює розмір кворуму на 2, негайно викликаючи вибори лідера, коли попередній лідер виявляє, що кворум не активний. Це тому, що операція “додавання члена” є двоетапним процесом, де користувач повинен спочатку застосувати команду “додавання члена”, а потім запустити процес нового вузла (див. Рисунок 7).
3. Неправильні конфігурації кластера
Ще гірший випадок, коли доданий член неправильно налаштований. Переналаштування членства є двоетапним процесом: “etcdctl member add” і запуск процесу сервера etcd з вказаною URL-адресою учасника. Тобто команда “додавання члена” застосовується незалежно від URL, навіть якщо значення URL є недійсним. Якщо перший крок застосовується з недійсними URL-адресами, другий крок не може навіть запустити новий etcd. Як тільки кластер втрачає кворум, немає способу скасувати зміну членства (див. Рисунок 8).
Те ж саме стосується багатовузлового кластера. Наприклад, кластер має два вузли, що не працюють (один несправний, інший неправильно налаштований) і два вузли, що працюють, але тепер потрібно щонайменше 3 голоси, щоб змінити членство кластера (див. Рисунок 9).
Як видно вище, проста неправильна конфігурація може призвести до того, що весь кластер стане непрацездатним. У такому випадку оператору потрібно вручну відновити кластер за допомогою прапорця etcd --force-new-cluster
. Оскільки etcd став критично важливою службою для Kubernetes, навіть найменший збій може мати значний вплив на користувачів. Що ми можемо зробити краще, щоб полегшити такі операції з etcd? Серед іншого, вибори лідера є найважливішими для доступності кластера: Чи можемо ми зробити переналаштування членства менш руйнівним, не змінюючи розмір кворуму? Чи може новий вузол бути бездіяльним, запитуючи лише мінімальні оновлення від лідера, поки не наздожене? Чи може неправильна конфігурація членства завжди бути зворотною і оброблятися більш безпечним способом (неправильна команда додавання члена не повинна ніколи призводити до збою кластера)? Чи повинен користувач турбуватися про топологію мережі при додаванні нового члена? Чи може API додавання члена працювати незалежно від розташування вузлів і поточних розділень мережі?
Raft Learner
Щоб помʼякшити такі прогалини в доступності, описані в попередньому розділі, Raft §4.2.1 вводить новий стан вузла “Learner” (“Учень”), який приєднується до кластера як член без права голосу, поки не наздожене журнали лідера.
Особливості у версії 3.4
Оператор повинен виконати мінімальну кількість роботи, щоб додати новий вузол-учень. Команда member add --learner
додає нового учня, який приєднується до кластера як член без права голосу, але все ще отримує всі дані від лідера (див. Рисунок 10).
Коли учень наздогнав прогрес лідера, його можна підвищити до члена з правом голосу за допомогою API member promote
, який тоді враховується у кворумі (див. Рисунок 11).
Сервер etcd перевіряє запит на підвищення, щоб забезпечити його операційну безпеку. Лише після того, як його журнал наздожене журнал лідера, учень може бути підвищений до члена з правом голосу (див. Рисунок 12).
Учень служить лише як резервний вузол до підвищення: Лідерство не може бути передано учню. Учень відхиляє читання і запис клієнтів (балансувальник клієнтів не повинен направляти запити до учня). Це означає, що учень не потребує видавати запити на індекс читання до лідера. Таке обмеження спрощує початкову реалізацію учня у версії 3.4 (див. Рисунок 13).
Крім того, etcd обмежує загальну кількість учнів, які може мати кластер, і уникає перевантаження лідера реплікацією журналу. Учень ніколи не підвищує себе. Хоча etcd надає інформацію про статус учня та перевірки безпеки, остаточне рішення про підвищення учня повинен приймати оператор кластера.
Запропоновані функції для майбутніх випусків
Зробити стан учня єдиним стандартним: Стандартне встановлення стану нового члена з на учня значно покращить безпеку переналаштування членства, оскільки учень не змінює розмір кворуму. Неправильна конфігурація завжди буде зворотною без втрати кворуму.
Зробити підвищення до члена з правом голосу повністю автоматичним: Як тільки учень наздожене журнали лідера, кластер може автоматично підвищити учня. etcd вимагає визначення певних порогів користувачем, і як тільки вимоги будуть виконані, учень підвищує себе до члена з правом голосу. З погляду користувача, команда “додавання члена” працюватиме так само, як і сьогодні, але з більшою безпекою, забезпеченою функцією учня.
Зробити учня резервним вузлом для аварійного відновлення: Учень приєднується як резервний вузол і автоматично підвищується, коли доступність кластера порушується.
Зробити учня лише для читання: Учень може служити як вузол лише для читання, який ніколи не підвищується. У режимі слабкої узгодженості учень отримує дані від лідера і ніколи не обробляє записи. Обслуговування читань локально без накладних витрат на консенсус значно зменшить навантаження на лідера, але може обслуговувати застарілі дані. У режимі сильної узгодженості учень запитує індекс читання у лідера, щоб обслуговувати останні дані, але все ще відхиляє записи.
Учень чи Mirror Maker
etcd реалізує “mirror maker” за допомогою API спостереження для безперервної передачі створення і оновлення ключів до окремого кластера. Дзеркалювання зазвичай має низьку затримку після завершення початкової синхронізації. Учень і дзеркалювання перекриваються в тому, що обидва можуть використовуватися для реплікації наявних даних для читання. Однак дзеркалювання не гарантує лінеаризованості. Під час розʼєднань мережі попередні значення ключів могли бути відкинуті, і клієнти повинні перевіряти відповіді спостереження для правильного порядку. Таким чином, у дзеркалі немає гарантії порядку. Використовуйте дзеркалювання для мінімальної затримки (наприклад, між центрами даних) шляхом узгодженості. Використовуйте учня для збереження всіх історичних даних і їх порядку.
Додаток: Реалізація учня у версії 3.4
Експонування типу вузла “Learner” для API “MemberAdd”.
Клієнт etcd додає прапорець до API “MemberAdd” для вузла-учня. І обробник сервера etcd застосовує запис про зміну членства з типом pb.ConfChangeAddLearnerNode
. Після того, як команда була застосована, сервер приєднується до кластера з прапорцем etcd --initial-cluster-state=existing
. Цей вузол-учень не може голосувати і не враховується в кворумі.
Сервер etcd не повинен передавати лідерство учню, оскільки він може все ще відставати і не враховується в кворумі. Сервер etcd обмежує кількість учнів, які може мати кластер, до одного: чим більше учнів ми маємо, тим більше даних лідер повинен поширювати. Клієнти можуть звертатися до вузла-учня, але учень відхиляє всі запити, крім серіалізованого читання і API статусу члена. Це для спрощення початкової реалізації. У майбутньому учень може бути розширений як сервер лише для читання, який безперервно дзеркалює дані кластера. Балансувальник клієнтів повинен надавати допоміжну функцію для виключення точки доступу вузла-учня. Інакше запит, надісланий до учня, може зазнати невдачі. Виклик синхронізації членів клієнта повинен враховувати тип вузла-учня. Так само повинні враховувати виклики оновлення точок доступу клієнта.
Відповіді MemberList
і MemberStatus
повинні вказувати, який вузол є учнем.
Додати API “MemberPromote”.
Внутрішньо в Raft другий виклик MemberAdd
до вузла-учня підвищує його до члена з правом голосу. Лідер контролює прогрес кожного послідовника і учня. Якщо учень не завершив своє повідомлення про знімок, відхилити запит на підвищення. Приймати запит на підвищення лише в тому випадку, якщо: Вузол-учень знаходиться в справному стані. Учень синхронізований з лідером або дельта знаходиться в межах порогу (наприклад, кількість записів для реплікації до учня менше 1/10 від кількості знімків, що означає, що навіть після підвищення лідеру не потрібно буде надсилати знімок учню). Вся ця логіка жорстко закодована в пакунку etcdserver
і не налаштовується.
Посилання
- Оригінальний тікет на github: etcd#9161
- Приклад використання: etcd#3715
- Приклад використання: etcd#8888
- Приклад використання: etcd#10114
Відгук
Чи це було корисним?
Раді чути! Будь ласка, повідомте нам, як ми можемо зробити краще.
Дуже шкода це чути. Будь ласка, повідомте нам, як ми можемо зробити краще.