Управление кластерами в Orleans
Orleans обеспечивает управление кластерами через встроенный протокол членства, который мы иногда называем членством в кластерах. Цель этого протокола — для всех силосов (Orleans серверов) согласиться с набором живых силосов, обнаруживать сбои силосов и разрешать новым силосам присоединяться к кластеру.
Протокол использует внешнюю службу для предоставления абстракции IMembershipTable. IMembershipTable является плоской устойчивой таблицей, которую мы используем для двух целей. Во-первых, он используется в качестве точки свидания для силосов, чтобы найти друг друга и Orleans клиентов для поиска силосов. Во-вторых, он используется для хранения текущего представления членства (список живых силосов) и помогает координировать соглашение о представлении членства.
В настоящее время у нас есть 6 реализаций IMembershipTable: на основе хранилища таблиц Azure, Azure Cosmos DB, ADO.NET (PostgreSQL, MySQL/MariaDB, SQL Server, Oracle), Apache ZooKeeper, Consul IO, AWS DynamoDB, MongoDB, Redis, Apache Cassandraи реализацию в памяти для разработки.
В дополнение к IMembershipTable каждому сило участвует в полностью распределенном протоколе однорангового членства, который обнаруживает сбой силосов и достигает соглашения о наборе живых силосов. Мы описываем внутреннюю реализацию протокола членства Orleansниже.
Протокол членства
При запуске каждый сило добавляет запись для себя в общеизвестную общую таблицу, используя реализацию IMembershipTable. Сочетание идентификатора silo (
ip:port:epoch
) и идентификатора развертывания службы (идентификатор кластера) используется в качестве уникальных ключей в таблице. Эпоха — это просто время в галочки, когда этот разбился, и какip:port:epoch
таковой гарантированно будет уникальным в данном Orleans развертывании.Силосы отслеживают друг друга напрямую с помощью прикладных проб ("вы живы"
heartbeats
). пробы отправляются в виде прямых сообщений из одного узла в другой, через те же самые сокеты TCP, по которым обмениваются сообщениями узлы. Таким образом, пробы полностью коррелируют с фактическими проблемами сети и работоспособностью сервера. Каждый силос сканирует настраиваемый набор других силосов. Силос выбирает, кого проверять, вычисляя согласованные хэши на идентификаторах других силосов, формируя виртуальное кольцо всех идентификаторов и выбирая X следующих силосов на кольце (это хорошо известный распределенный метод, называемый согласованное хэширование и широко используется во многих распределенных хэш-таблицах, таких как Chord DHT).Если silo S не получает Y ответов от отслеживаемого сервера P, оно начинает его подозревать и заносит это подозрение с отметкой времени в строку P в IMembershipTable.
Если у P более Z подозрений в течение K секунд, то S записывает, что P умер, в строку P и отправляет моментальный снимок текущей таблицы участников во все остальные силосы. Силосы периодически обновляют таблицу, поэтому моментальный снимок служит оптимизацией для сокращения времени, необходимого всем силосам, чтобы узнать о новом представлении членства.
Дополнительные сведения:
Подозрение записывается IMembershipTableв специальный столбец в строке, соответствующей P. Когда S подозревает P он пишет: "во время TTT S подозреваемый P".
Одно подозрение недостаточно, чтобы объявить P мертвым. Вам нужны подозрения Z из разных силосов в настраиваемом окне времени T, как правило, 3 минуты, чтобы объявить P мертвым. Подозрение записывается с помощью контроля оптимистического параллелизма, предоставленного тем.IMembershipTable
Подозреваемый silo S считывает строку P.
Если
S
последний подозреваемый (там уже были подозреваемые Z-1 в течение периода T, как написано в столбце подозрений), S решает объявить P как мертвый. В этом случае S добавляет себя в список подозреваемых, а также записывает в столбец состояния P, который P является мертвым.В противном случае, если S не является последним подозреваемым, S просто добавляет себя в столбец подозреваемого.
В любом случае обратная запись использует номер версии или ETag, который был прочитан, поэтому обновления этой строки сериализуются. Если запись завершилась сбоем из-за несоответствия версии или ETag, повторных попыток S (повторная запись и попытка записи, если только P не помечен как мертвый).
На высоком уровне эта последовательность "чтение, локальное изменение, обратная запись" — это транзакция. Однако для этого не обязательно используются транзакции хранилища. Код "Транзакция" выполняется локально на сервере, и мы используем оптимистическое параллелизм, IMembershipTable предоставленное для обеспечения изоляции и атомарности.
Каждый silo периодически считывает всю таблицу членства для своего развертывания. Таким образом, силосы узнали о новых объединениях силосов и о других силосах, объявленных мертвыми.
трансляция снимков: чтобы уменьшить частоту обновления таблицы, каждый раз, когда силос записывает в таблицу (подозрение, новое соединение и т. д.), он отправляет снимок текущего состояния таблицы всем другим силосам. Так как таблица членства согласована и монотонно версиионна, каждое обновление создает уникально версиионованный моментальный снимок, которым можно безопасно делиться. Это позволяет мгновенно распространять изменения членства без ожидания периодического цикла чтения. Периодическое чтение по-прежнему сохраняется в качестве резервного механизма в случае сбоя распределения моментальных снимков.
Упорядоченные представления членства: Протокол членства гарантирует, что все конфигурации членства имеют глобальный и полный порядок. Это упорядочение обеспечивает два ключевых преимущества:
гарантированное подключение. Когда новый узел присоединяется к кластеру, он должен проверить двустороннее подключение к каждому другому активному узлу. Если ни один из существующих силосов не отвечает (что может указывать на проблему с сетевым подключением), новый силос не может присоединиться. Это обеспечивает полную связь между всеми силосами в кластере при запуске. См. примечание об IAmAlive ниже для исключения в случае аварийного восстановления.
обновления каталогов: протоколы более высокого уровня, такие как каталог распределенного зерна, полагаются на все силосы с согласованным монотонным представлением членства. Это обеспечивает более интеллектуальное разрешение повторяющихся активаций зерна. Для получения дополнительных сведений см. документацию каталога зерна .
Сведения о внедрении:
IMembershipTable требует атомарных обновлений, чтобы гарантировать глобальный общий порядок изменений:
- Реализации должны атомарно обновлять как записи таблицы (список силосов), так и номер версии.
- Это можно сделать с помощью транзакций базы данных (как в SQL Server) или атомарных операций сравнения и замены с помощью ETags (как в хранилище таблиц Azure)
- Конкретный механизм зависит от возможностей базовой системы хранения
Специальная строка версии членства в таблице отслеживает изменения:
- Каждая вставка в таблицу (подозрения, объявления о смерти, присоединения) увеличивает этот номер версии.
- Все записи сериализуются по этой строке с помощью атомарных обновлений
- Монотонно увеличивающаяся версия обеспечивает общее упорядочение всех изменений членства.
Когда silo S обновляет состояние silo P:
- Впервые S считывает последнее состояние таблицы
- В рамках одной атомарной операции обновляется строка данных P и увеличивается номер версии.
- Если атомарное обновление завершается ошибкой (например, из-за одновременных изменений), операция повторяется с экспоненциальной задержкой.
рекомендации по масштабируемости:
Сериализация всех операций записи через версионную строку может повлиять на масштабируемость из-за возросшего конфликтов. Протокол был проверен в производстве с числом силосов до двухсот, но может столкнуться с проблемами, если их количество превысит тысячу. Для очень крупных развертываний другие части Orleans (обмен сообщениями, каталог grain, хостинг) остаются масштабируемыми, даже если обновления членства становятся узким местом.
Конфигурация по умолчанию: Конфигурация по умолчанию была настроена вручную во время использования в производственной среде в Azure. По умолчанию: каждый силос отслеживается тремя другими силосами, два подозрения достаточно, чтобы объявить сило мертвым, подозрения только за последние три минуты (в противном случае они устарели). Зонды отправляются каждые десять секунд, и нужно пропустить три зонда, чтобы заподозрить сбой соединения.
самостоятельного мониторинга : детектор сбоев включает идеи из исследованияLifeguard Lifeguard (бумаги ,говорить ,блоге ) для повышения стабильности кластера во время катастрофических событий, где большая часть кластера испытывает частичный сбой. КомпонентLocalSiloHealthMonitor
оценивает работоспособность каждого силоса с помощью нескольких эвристик.- Активное состояние в таблице членства
- Никаких подозрений от других силосов
- Последние успешные ответы запросов
- Последние полученные исследовательские запросы
- Скорость отклика пула потоков (рабочие элементы, выполняемые в течение 1 секунды)
- Точность таймера (запуск в течение 3 секунд по расписанию)
Оценка работоспособности силоса влияет на время ожидания пробы: неработоспособные силосы (оценка 1-8) увеличили время ожидания по сравнению со здоровыми силосами (оценка 0). Это имеет два преимущества:
- Предоставляет больше времени для успешного выполнения запросов, когда сеть или система находится под нагрузкой.
- Становится более вероятным, что неработоспособные силосы будут признаны недействительными, прежде чем смогут неправильно голосовать против здоровых силосов.
Это особенно важно во время таких сценариев, как голодание пула потоков, где медленные узлы могут неправильно подозревать здоровые узлы просто потому, что они не могут обрабатывать ответы достаточно быстро.
косвенные пробы: другой Lifeguard-вдохновленный компонент, который повышает точность обнаружения сбоев, уменьшая вероятность того, что неработоспособная или секционированная сило будет неправильно объявлять здоровый сило мертвый. Когда в аналитическом блоке остаётся две попытки проверки для целевого силоса до подачи голоса об объявлении его мёртвым, используется косвенное зондирование.
- Хранилище мониторинга случайным образом выбирает другое хранилище в качестве посредника и просит его провести проверку цели.
- Посредник пытается связаться с целевым silo
- Если целевой объект не может реагировать в течение периода ожидания, посредник отправляет отрицательное подтверждение
- Если хранилище мониторинга получило отрицательное подтверждение от посредника, и посредник объявляет себя здоровым (через самоконтроль, описанный выше), хранилище мониторинга голосует, чтобы объявить цель мёртвой.
- При настройке по умолчанию двух обязательных голосов отрицательное подтверждение от косвенного зонда учитывается как оба голоса, что позволяет ускорить объявление мертвых силосов при подтверждении сбоя несколькими перспективами.
Применение идеального обнаружения сбоев: После объявления силоса мёртвым в таблице, он считается мёртвым для всех, даже если он не мёртв (просто временно разделён или сообщения о сердцебиении были потеряны). Все перестают взаимодействовать с ним, и как только он узнает, что он мертв (считывая его новое состояние из таблицы), он зафиксирует самоубийство и завершает свой процесс. В результате на месте должна быть инфраструктура, чтобы перезапустить в качестве нового процесса (при запуске создается новый номер эпохи). При размещении в Azure это происходит автоматически. Если это не так, требуется другая инфраструктура, например служба Windows, настроенная для автоматического перезапуска при сбое или развертывании Kubernetes.
Что происходит, если таблица недоступна в течение некоторого времени:
Если служба хранилища отключена, недоступна или возникают проблемы с взаимодействием, Orleans протокол НЕ объявляет силосы как мертвые по ошибке. Операционные силосы будут работать без каких-либо проблем. Тем не менее, Orleans не сможет объявить силос мертвым (если он обнаружит, что некоторые из силосов перестали работать из-за пропущенных зондов, он не сможет записать этот факт в таблицу), а также не сможет позволить новым силосам присоединиться. Таким образом, полнота будет страдать, но точность не пострадает - разделение таблицы никогда не приведет к тому, что Orleans ошибочно объявит silo мертвым. Кроме того, в случае частичной сетевой секции (если некоторые силосы могут получить доступ к таблице и некоторые нет), это может произойти, что Orleans будет объявлять мертвый сило как мертвый, но потребуется некоторое время, пока все остальные силосы не знают об этом. Таким образом, обнаружение может быть отложено, но Orleans никогда не будет неправильно убить сило из-за недоступности таблицы.
IAmAlive пишет для диагностики и аварийного восстановления:
В дополнение к сигналам "пульс", которые отправляются между силосами, каждый силос периодически обновляет метку времени "Я жив" в своей строке таблицы. Это служит двумя целями:
- Для диагностики система предоставляет системным администраторам простой способ проверки активности кластера и определения, когда силос был активен в последний раз. Метка времени обычно обновляется каждые 5 минут.
- Для аварийного восстановления, если силос не обновил метку времени в течение нескольких периодов (настроено с помощью
NumMissedTableIAmAliveLimit
), новые силосы будут игнорировать его при проверках подключения при запуске, что позволяет кластеру восстановиться из сценариев, когда силосы выходят из строя, не завершившись корректно.
Таблица членства
Как уже упоминалось, IMembershipTable используется в качестве точки встречи для силосов, чтобы найти друг друга и Orleans клиентов для поиска силосов, а также помогает координировать соглашение о представлении членства. Основной репозиторий Orleans содержит реализации для многих систем, таких как хранилище таблиц Azure, Azure Cosmos DB, PostgreSQL, MySQL/MariaDB, SQL Server, Apache ZooKeeper, Consul IO, Apache Cassandra, MongoDB, Redis, AWS DynamoDB и реализация в памяти для разработки.
Хранилище таблиц Azure. В этой реализации мы используем идентификатор развертывания Azure в качестве ключа секции и идентификатора silo (
ip:port:epoch
) в качестве ключа строки. Вместе они гарантируют уникальный ключ для каждого сило. Для управления параллелизмом мы используем элемент управления оптимистичным параллелизмом на основе ETags таблицы Azure. Каждый раз, когда мы читаем из таблицы, мы сохраняем ETag для каждой строки чтения и используем этот ETag при попытке обратной записи. ETag автоматически назначаются и проверяются службой таблиц Azure на каждой записи. Для транзакций с несколькими строками мы используем поддержку пакетных транзакций, предоставляемых таблицей Azure, которая гарантирует сериализуемые транзакции по строкам с одним ключом секции.SQL Server — в этой реализации настроенный идентификатор развертывания используется для различения развертываний и компонентов, принадлежащих развертываниям. Идентификатор silo определяется как сочетание
deploymentID, ip, port, epoch
в соответствующих таблицах и столбцах. Реляционная серверная часть использует управление оптимистическим параллелизмом и транзакции, аналогичные процедуре использования ETags в реализации таблицы Azure. Реляционная реализация ожидает, что ядро СУБД создаст используемый ETag. В случае с SQL Server в SQL Server 2000 созданный ETag является одним из полученных из вызоваNEWID()
. В SQL Server 2005 и более поздних версиях ROWVERSION используется. Orleans считывает и записывает реляционные ETags в виде непрозрачныхVARBINARY(16)
тегов и сохраняет их в памяти в виде строк в кодировке Base64 . Orleans поддерживает вставку нескольких строк с помощьюUNION ALL
(для Oracle, включая DUAL), которая в настоящее время используется для вставки статистических данных. Точную реализацию и обоснование SQL Server можно увидеть на CreateOrleansTables_SqlServer.sql.Apache ZooKeeper — в этой реализации мы используем настроенный идентификатор развертывания в качестве корневого узла и идентификатора silo (
ip:port@epoch
) в качестве дочернего узла. Вместе они гарантируют уникальный путь для каждого сило. Для управления параллелизмом мы используем элемент управления оптимистичным параллелизмом на основе версии узла. Каждый раз, когда мы считываем из корневого узла развертывания, мы сохраняем версию для каждого дочернего узла silo и используем эту версию при попытке обратной записи. Каждый раз при изменении данных узла номер версии увеличивается атомарно службой ZooKeeper. Для транзакций с несколькими строками мы используем многоуровневый метод, который гарантирует сериализуемые транзакции по узлам silo с одинаковым родительским узлом идентификатора развертывания.Consul IO — мы использовали хранилище ключей и значений Consul для реализации таблицы членства. Дополнительные сведения см. в статье Consul-Deployment .
AWS DynamoDB . В этой реализации мы используем идентификатор развертывания кластера в качестве ключа секции и идентификатора Silo (
ip-port-generation
) в качестве RangeKey, делающего запись unity. Оптимистическая параллелизм выполняется атрибутомETag
путем создания условных операций записи в DynamoDB. Логика реализации довольно похожа на службу хранилища таблиц Azure.Apacha Cassandra. В этой реализации мы используем составной ключ, состоящий из идентификатора службы и идентификатора кластера, в качестве ключа раздела, а идентификатор хранилища (
ip:port:epoch
) - в качестве ключа строки. Вместе они гарантируют уникальную запись на каждый силос. Для контроля параллелизма мы используем оптимистичный контроль параллелизма на основе версии статического столбца с помощью легковесной транзакции. Этот столбец версии используется для всех строк в секции или кластере, обеспечивая тем самым последовательное увеличение номера версии для таблицы членства каждого кластера. В этой реализации нет транзакций с несколькими строками.Эмуляция в памяти для настройки разработки. Мы используем специальное системное зерно для этой реализации. Это зерно живет на выделенном первичном сило, который используется только для установки разработки. В любой реальной рабочей среде основной silo не требуется.
Обоснование проектирования
Естественный вопрос, который можно задать, заключается в том, почему не полностью полагаться на Apache ZooKeeper или etcd для реализации членства в кластере, используя, например, встроенную поддержку ZooKeeper для членства в группе с временными узлами? Почему мы беспокоили реализацию протокола членства? Были в первую очередь три причины:
Развертывание и размещение в облаке:
Zookeeper не является размещенной службой. Это означает, что в облачной среде Orleans клиентам придется развертывать и запускать и управлять экземпляром кластера ZK. Это просто еще один ненужный бремя, что мы не хотели заставить наших клиентов. Используя таблицу Azure, мы используем размещенную управляемую службу, которая упрощает жизнь клиента. В основном в облаке используйте облако как платформу, а не инфраструктуру. С другой стороны, при запуске локальной среды и управлении серверами, использование ZK в качестве реализации IMembershipTable является жизнеспособным вариантом.
Прямое обнаружение сбоев:
При использовании членства в группе ZK с временными узлами обнаружение сбоев выполняется между Orleans серверами (клиентами ZK) и серверами ZK. Это может не обязательно коррелировать с фактическими проблемами сети между Orleans серверами. Наше желание было в том, что обнаружение сбоев точно отражает состояние взаимодействия внутри кластера. В частности, в нашем дизайне, если Orleans сило не может взаимодействовать с IMembershipTable ним, он не считается мертвым и может продолжать работать. В отличие от этого, мы использовали членство в группах ZK с временными узлами отключение от сервера ZK может привести Orleans к тому, что клиент Silo (ZK) будет объявлен мертвым, в то время как он может быть жив и полностью функциональным.
Переносимость и гибкость:
В рамках Orleansфилософии мы не хотим принудительно принудить сильную зависимость от любой конкретной технологии, но вместо того чтобы иметь гибкий дизайн, где различные компоненты можно легко переключать с различными реализациями. Это именно цель, IMembershipTable которая служит абстракции.
Свойства протокола членства
Может обрабатывать любое количество сбоев:
Наш алгоритм может обрабатывать любое количество сбоев (то есть f<=n), включая полный перезапуск кластера. Это в отличие от "традиционных" решений на основе Paxos , которые требуют кворума, который обычно является большинством. Мы видели в производственных ситуациях, когда более половины силосов были вниз. Наша система остается функциональной, в то время как членство на основе Paxos не сможет добиться прогресса.
Трафик к таблице очень легкий:
Реальные запросы проходят непосредственно между серверами, а не к таблице. Это приведет к созданию большого трафика плюс будет менее точным с точки зрения обнаружения сбоев - если сило не удалось достичь таблицы, он пропустил бы писать свой живой пульс, и другие убьет его.
Неустранимая точность и полнота:
Хотя вы не можете достичь идеального и точного обнаружения сбоев, один обычно хочет возможность компромисса точности (не хочу объявлять сило, который жив как мертвый) с полнотой (хотите объявить мертвый сило, который действительно мертв как можно скорее). Настраиваемые голоса для объявления мертвых и пропущенных проб позволяют торговать этими двумя. Дополнительные сведения см. в университете Йель: детекторы сбоев компьютеров.
Scale (Масштаб):
Протокол может обрабатывать тысячи и, вероятно, даже десятки тысяч серверов. Это отличается от традиционных решений на основе Paxos, таких как протоколы групповой связи, которые, как известно, не масштабируются за десятки.
Диагностика:
Таблица также очень удобна для диагностика и устранения неполадок. Системные администраторы могут мгновенно найти в таблице текущий список живых силосов, а также просмотреть историю всех убитых силосов и подозрений. Это особенно полезно при диагностике проблем.
Почему нам нужен надежный постоянный хранилище для реализации IMembershipTable:
Мы используем постоянное хранилище для IMembershipTable в двух целях. Во-первых, он используется в качестве точки свидания для силосов, чтобы найти друг друга и Orleans клиентов для поиска силосов. Во-вторых, мы используем надежное хранилище, чтобы помочь нам координировать соглашение о представлении членства. Хотя мы выполняем обнаружение сбоев непосредственно в одноранговом режиме между оси, мы сохраняем представление членства в надежном хранилище и используем механизм управления параллелизмом, предоставляемый этим хранилищем, чтобы достичь соглашения о том, кто жив и кто мертв. Таким образом, в смысле, наш протокол аутсорсинг трудной проблемы распределенного консенсуса в облаке. В этом случае мы полностью используем возможности базовой облачной платформы, используя ее действительно как платформу как услуга (PaaS).
Прямые записи IAmAlive в таблицу только для диагностика:
Помимо пульса, которые отправляются между силосами, каждый сило также периодически обновляет столбец "Я Жив" в строке таблицы. Этот столбец "Я жив" используется только для устранения неполадок вручную и диагностика и не используется самим протоколом членства. Обычно он записывается на гораздо более низкой частоте (каждые 5 минут) и служит очень полезным инструментом для системных администраторов, чтобы проверить динамическую активность кластера или легко узнать, когда сило было последней жизнью.
Благодарности
Мы хотели бы признать вклад Алекса Когана в проектирование и реализацию первой версии этого протокола. Эта работа была выполнена в рамках летней стажировки в Microsoft Research в лето 2011 года.
Реализация IMembershipTable на основе ZooKeeper была выполнена Shay Hazor, реализация SQL IMembershipTable была выполнена Veikko Eeva, реализация AWS DynamoDB IMembershipTable была выполнена Gutemberg Ribeiro, и реализация Consul на основе IMembershipTable была выполнена Пол Норт, и, наконец, реализация Apache Cassandra IMembershipTable была адаптирована с OrleansCassandraUtils
Arshia001.