HighLoad++ 2017
Зал «Сингапур», 8 ноября, 11:00
Тезисы:
http://www.highload.ru/2017/abstracts/3080.html
Мы расскажем от том, как мы написали отказоустойчивый, распределенный и консистентный сервис на сто тысяч проводок в секунду. Почему согласно CAP-теореме такой сервис не будет работать. Как мы сумели работать с этим ограничением. Про test-driven development распределенной системы или как численными методами строго доказать, что сервис будет работать нужным для нас образом. Опишем возможности применения используемых технологий при разработке криптовалют.
2. Как сделать приложение:
• Горизонтально масштабируемое
• C большим числом операций на объект
• Гарантией выполнения операции один и только один раз
• Отказоустойчивое
• Устойчивое к человеческому фактору
• Дешёвая эксплуатация
24. Итог
• Отказоустойчивость связана с доступностью
• Система отказоустойчива если может терять ноды
• CAP параметры могут быть не дискретны
• С CAP теоремой можно жить.
• Вероятностная работа системы
45. Требования к алгоритму консенсуса
• Идеальная согласованность
• Атомарная операция с несколькими шардами
• Работа при потере одного дата центра
В терминах CAP-теоремы
• С = 1
• A ≈ 1/3
• P ≈ 1/3
46. Не изобретать велосипед
• Paxos
• Vertical paxos and primary-backup replication / Pages 312
• Raft
• Не устойчив
47. Свой алгоритм консенсуса
• Много лидеров одновременно
• Лидер совмещен с акцептором (последователем)
Недостатки
• Лишний трафик
50. Алгоритм консенсуса
Любая нода
сохранила блок
Сохранить блок в
персистентное
хранилище Большинство
нод сохранили
один блок
Большинство нод
выбрали
одинаковый блок
Выбрать блок с
наименьшим хэшем
51. Алгоритм консенсуса
Любая нода
сохранила блок
Сохранить блок в
персистентное
хранилище Большинство
нод сохранили
один блок
Ждем
Большинство нод
выбрали
одинаковый блок
Выбрать блок с
наименьшим хэшем
52. Алгоритм консенсуса
Любая нода
сохранила блок
Сохранить блок в
персистентное
хранилище Большинство
нод сохранили
один блок
Ждем
Большинство нод
выбрали
одинаковый блок
Выбрать блок с
наименьшим хэшем
Любая нода
сохранила блок
53. Алгоритм консенсуса
Любая нода
сохранила блок
Сохранить блок в
персистентное
хранилище Большинство
нод сохранили
один блок
Ждем
Подтверждаем
блок
Алгоритм
завершёнБольшинство нод
выбрали
одинаковый блок
Выбрать блок с
наименьшим хэшем
Любая нода
сохранила блок
54. Алгоритм консенсуса
Любая нода
сохранила блок
Сохранить блок в
персистентное
хранилище Большинство
нод сохранили
один блок
Ждем
Подтверждаем
блок
Алгоритм
завершёнБольшинство нод
выбрали
одинаковый блок
Выбрать блок с
наименьшим хэшем
Любая нода
сохранила блок
55. Алгоритм консенсуса полностью
Номер
текущего
блока
Запросить
все новые
блоки
Сказать ноде
что она
устарела
Номер блока, порядковый номер блока, все время растет
Кворум это (n+1)/2 нод
Больше текущего
Меньше текущего
Текущее
состояние
Инициализировать
алгоритм либо
новым блоком
либо пришедшим
Кворум нод выбрал
один блок
Ждать/повторить
отправку
сообщений
Подтвердить блок
Завершить
алгоритм.
Записать блок в
неподтверждённо
м состоянии.
Отправить всем
сообщение
Кворум нод выбрал
один блок
Выбрать блок с
меньшим хэшем
среди всех
полученных
Не инициализировано
Нача-
льный
Блок сохранен без подтверждена
Да
Нет
Да
Нет
56. Итог
• Шардинг наше все
• Пакетная репликация
• Есть готовые алгоритмы Raft и Paxos
• Сделать свой алгоритм консенсуса просто
• Специализированное решение лучше общего
65. Тестируем конченый автомат
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Дошло сообщение
от других нодФаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Нода 1 Нода 2
Новый Новый
0x4CA7 0x4CA7
Фаза: Новый
Блок: 0xEF12
Сохр: null
66. Тестируем конченый автомат
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
Нода 1 Нода 2
Новый Новый
0x4CA7 0x4CA7
67. Тестируем конченый автомат
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
Нода 1 Нода 2
Новый Новый
0x4CA7 0x4CA7
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Не дошло
сообщение от
других нод
Падение ноды
77. CAP теорема
• Только для дискретных величин
• Для любого A < 1 возможно A = 0
• Есть циклически переходы
• Для paxos и raft тоже
• Только если нарушается кворум
78. Цепь Маркова
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
79. Цепь Маркова
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
30%100%
30%
100% 50%
80. Цепь Маркова
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
30%100%
50%
30%
100%
100%
81. Цепь Маркова
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
30%100%*30%
50%100%
130%
30%
100%
82. Цепь Маркова
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
30%
50%100%
15%
130%
30%
50%100%
100%*30%
50%*30%
83. Цепь Маркова
Фаза: Коммит
Блок: 0x4CA7
Сохр: 0x4CA7
инициализация
Падение ноды
Падение ноды
Фаза: Новый
Блок: 0x4CA7
Сохр: null
Фаза: null
Блок: null
Сохр: null
инициализация
Фаза: Новый
Блок: 0xEF12
Сохр: null
Фаза: null
Блок: null
Сохр: 0x4CA7
Дошло сообщение
от других нод
30%
50%100%
19.5%
130%
30%
50%+15%100%
100%*30%
30%*50%
+15%*30%
50%*30%
84. Цепь Маркова
• Есть граф
• Есть все переходы
• Присваиваем вероятности
• Суммируем возвратные состояния
Для нашей системы менее одного платежа в год.
89. Итог
• Алгоритм в виде конечного автомата
• Результат работы известен
• Поиск в ширину узлов графа
• Возможны возвратные состояния
90. Использование в криптовалюте
• Алгоритм
• Одноранговый
• Децентрализованный
• Блокчейн
• Уже есть
• Генерация центрального
91. Заключение
• Можно жить CAP теоремой
• Сделать свой консенсус не трудно
• Пакетная репликация
• Пишите алгоритм в виде конечного автомата
• Не забудьте протестировать на циклы
Здравствуйте! Я Алексей Булылов. Пять лет работаю в киви.
Я расскажу как вы сможете написать сервис-мечту! Горизонтально масштабирующуюся по числу серверов базу данных, гарантирующее выполнение любой операци один и только один раз. Позволяющую делать атомарные операции между шардами, и при этом обеспечивающее такую отказоустойчивость, что даже падении целого дата-центра не приведёт к простоям.
Как проверить что мы написали методом разработки черезе тесирование
А также, как обеспечить работоспособность этого сервиса, когда придет злобный админ!
На самом деле админ не злобный. Он просто воплощение закона мерфи, который гласит: «если какая-нибудь неприятность может произойти - она обязательно произойдёт».
Полагаю что типичное ваше нагруженное приложение выглядит примерно так. Несколько state-less серверов которые обслуживают клиентов подключенных через облако
Злобный админ может ронять перезагружать сервисы по отдельности. Это не как не повлияет на пользователей.
Кончено реальная система должна где-то хранить свои данные – по ваше приложение выглядит примерно так.
С точки зрения злобного админа она выглядит так. Этому система в целом работает хорошо. Современны базы данных обеспечивают достаточно высокую доступность до 3-4 девяток, по.
Проблемы возникают если поставить много SQL баз данных и сделать между ними шардинг. Это приводит к резкому падению доступности
Предположим что доступность одиночной базы три девятки.
При росте числа шард доступность начинает быстро падает, и для 12 нод достигает одной девятки. Одним из самых эффективных способов повысить отказоустойчивость, сделать сервис работоспособным при потере одной базы данных.
Например для нашего сервиса из 12 нод доступность возрастет c одной девятки до четырех. Общая доступность даже больше чем доступность отдельной ноды!
Вообще возможность останавливать ноды без простоев очень удобна. Она позволяет обновлять систему без остановки. Добавлять и удалять ноды на лету. Злобному админу не так то просто ее сломать. В общем не система а мечта. В чем же проблема?
Кратенько, для тех кто подзабыл о чем она.
Partition tolerance (устойчивость к разделению) : Система способна работать при разрыве соединения между узлами, или падении узлов. При отказе от устойчивости к разделению, связь между узлами должна гарантированно отрабатывать за определённое время. Таким свойствами обладают различные аппаратные шины. Замен процессорных модулей в некоторых MainFrame, или жёстких дисков в NAS работает благодаря тому что они CA.
CAP теорема говорит что возможны два свойства из трех.
В целом очень просто. Если между узлами нашей системы нет связи – то они либо будут возвращать разные данные, либо перестанут обрабатывать часть запросов. Связи может не быть в следствии того что или часть узлов упала, или между ними пропала сеть.
Consistency (согласованность): все клиенты видят одинаковые данные. От согласованности отказываются большинство отказоустойчивых решений, таких как NoSQL базы данных или Akka-cluster. В противовес говорят о eventual consistency то есть согласованости через некоторое, весьма неопределенное время, согласованность восстановится. Например на слайде согалсованности нет. По понятным причинам для финансовых сервисов C обязательна.
Availability (доступность): означает что система может обработать любой запрос. В качестве интересного примера можно привести кластер SQL баз данных с координатором распределённых транзакций. Если координатор не отвечает, то вы не можете писать.
Partition tolerance (устойчивость к разделению) : Система способна работать при разрыве соединения между узлами, или падении узлов. При отказе от устойчивости к разделению, связь между узлами должна гарантированно отрабатывать за определённое время. Таким свойствами обладают различные аппаратные шины. Замен процессорных модулей в некоторых MainFrame, или жёстких дисков в NAS работает благодаря тому что они CA.
CAP теорема говорит что возможны два свойства из трех.
И так. Вопрос к залу. Как вы думаете работает ли CAP теорема?
Варианты
Мало голосов) Не слышу громче!
Да) Большинство говорит да. Сейчас попробую показать пример который почти покажет что она не работает
Нет) Нет. Прекрасно! У меня есть пример который это почти подтверждает.
В суровом математическом мире, cap теорема работает. Во первых есть доказательство, во вторых многократные попытки ее опровергнуть не удачны. Теоретически ее можно обойти получив идеальные часы, которые везде показывают одинаковое время. К сожалению в теории относительности, вообще нет понятия одинаковое время.
Фактически даже два пункта из трех в реальной системе получить очень трудно. Неужели не чего нельзя сделать?
Рассмотрим такой пример. Каждый клиент работает со своей собственной шардой.
Если мы теряем 2/3 шард мы остаемся доступны для 1/3 клиентов. При этом все клиенты видят строго согласованные данные. Конечно реальность значительно хуже, и всегда будут клиенты – работающие с несколькими шардами или переходящие с одной шарды на другую. Но как я уже говорил получить сумму равную двум практически не возможно.
В самой как теореме параметры являются дискретными. То есть согласованность либо есть либо ее нет. Но вернемся из математических высей на грешную землю.
Дискретны ли параметры в практических применениях? На предыдущем примере видно что нет. С не дискретными параметрами уже можно жить!
В целом CAP теорема работает. Например: злобный админ ломает великий китайский фаервол изолируя китайский сегмент интернета. При этом возникнет два форка блокчейн. Появится возможность двойного проведения. То-есть клиент в китае и европе могут списать все деньги с одного счета (выхода), в пользу разных магазинов. Как вы помните согласованность это когда все клиенты видя одни и теже данные. Были случаи когда благодаря этому эффекту крали деньги.
Если злобный админ сломает глобальную таблицу маршутеризации и отправит трафик Новой Зеландии в Канаду, то перевод внутри в Новой Зеландии будет занимать месяцы, так как там не очень много майнеров. Я не могу назвать это доступностью.
В целом Bitcoin обладает всеми тремя параметрами на уровне вполне устраивающем конечного потребителя. Биткоин показывает что можно получить гораздо более интересную систему – которая будет обладать всеми тремя свойствами кап теоремы пока соблюдаются некоторые условия. Например можно получить строго согласованную систему которая будет работать пока не потеряет до половины нод.
Недостатком такого подходя, явлется то что при дробных значениях параметров работа системы приобретает вероятностную природу, например форки блокчейна появляются с некой вероятностью. Прооценку этоих вероятностей я поговорю позже.
Сейчас я раскажу
Поскольку нам требовался сервис для финансоввых транзакций то требовалось строгая согласованность. Под изначальную задачу требовались атомарные переводы между счетами. Пока удалось обойтись без них. Обязательной была работа при потере одного датацентра, поскольку злобный админ любит ломать дата центр целиком.
И так согласно нашей недискретной модели, не могу называть ее CAP теоремой, мы можем оставаться доступными при потере одного датацентра из трех. Совсем не плохо.
Ключевой проблемой paxos и raft является наличие единой точки отказа. Лидера. Если он падает то клиенты вынуждены ждать таймаута. Еще хуже, если он начинает глючить или вести себя неадекватно, например приближается OOM. Алгоритм может не сойтись ни когда. Эта проблема решается элементарно – делаем два лидера! А лучше три! На каждой шарде свой. Тогда отпадает необходимость выбирать лидера а потом искать его, всех лидеров однозначно определяется алгоритмом шардирования. К сожалению три лидера дают в три-четрые раза больше трафика чем один. Теоретически этом можно забороть, но нам было не нужно.