Управление кластерами в Orleans

Orleans предоставляет управление кластерами с помощью встроенного протокола членства, который иногда называется членством В Silo. Цель этого протокола — для всех силосов (Orleans серверов) согласиться с набором живых силосов, обнаруживать сбои силосов и разрешать новым силосам присоединяться к кластеру.

Протокол использует внешнюю службу для предоставления абстракции IMembershipTable. IMembershipTable — это плоская устойчивая таблица No-SQL, используемая для двух целей. Во-первых, он используется в качестве точки свидания для силосов, чтобы найти друг друга и Orleans клиентов для поиска силосов. Во-вторых, он используется для хранения текущего представления членства (список живых силосов) и помогает координировать соглашение о представлении членства. В настоящее время у нас есть 6 реализацийIMembershipTable: на основе таблиц Azure служба хранилища, SQL Server, Apache ZooKeeper, Consul IO, AWS DynamoDB и эмуляции в памяти для разработки.

В дополнение к IMembershipTable каждому сило участвует в полностью распределенном протоколе однорангового членства, который обнаруживает сбой силосов и достигает соглашения о наборе живых силосов. Сначала мы описываем внутреннюю реализацию Orleansпротокола членства ниже и более поздних версий IMembershipTable.

Базовый протокол членства

  1. При запуске каждый сило добавляет запись для себя в общеизвестную общую таблицу, используя реализацию IMembershipTable. Сочетание идентификатора silo (ip:port:epoch) и идентификатора развертывания службы используется в качестве уникальных ключей в таблице. Эпоха — это просто время в галочки, когда этот разбился, и как ip:port:epoch таковой гарантированно будет уникальным в данном Orleans развертывании.

  2. Силосы отслеживают друг друга напрямую с помощью pings приложения ("вы живы". heartbeats Связи отправляются как прямые сообщения из silo в silo в silo, по тем же сокетам TCP, которые обмениваются данными. Таким образом, проверка связи полностью коррелирует с фактическими проблемами сети и работоспособностью сервера. Каждый сило выполняет настройку настраиваемого набора других силосов. Silo выбирает, кому следует пинг, вычисляя согласованные хэши на удостоверение других силосов, формируя виртуальное кольцо всех удостоверений, и выбирает X преемник силосов на кольце (это хорошо известный распределенный метод называется согласованным хэшированием и широко используется во многих распределенных хэш-таблицах, таких как Хорд DHT).

  3. Если silo S не получает ответы Y ping от отслеживаемых серверов P, он подозревает его, написав метку времени в строку P в строке IMembershipTableP.

  4. Если P имеет больше, чем Z подозрения в течение нескольких секунд, то S записывает, что P мертв в строке P, и передает запрос на повторное чтение таблицы членства (которые они будут делать в любом случае периодически).

  5. Дополнительные сведения:

    1. Подозрение записывается IMembershipTableв специальный столбец в строке, соответствующей P. Когда S подозревает P он пишет: "во время TTT S подозреваемый P".

    2. Одно подозрение недостаточно, чтобы объявить P мертвым. Вам нужны подозрения Z из разных силосов в настраиваемом окне времени T, как правило, 3 минуты, чтобы объявить P мертвым. Подозрение записывается с помощью контроля оптимистического параллелизма, предоставленного тем.IMembershipTable

    3. Подозреваемый silo S считывает строку P.

    4. Если S последний подозреваемый (там уже были подозреваемые Z-1 в течение периода T, как написано в столбце подозрений), S решает объявить P как мертвый. В этом случае S добавляет себя в список подозреваемых, а также записывает в столбец состояния P, который P является мертвым.

    5. В противном случае, если S не является последним подозреваемым, S просто добавляет себя в столбец подозреваемого.

    6. В любом случае обратная запись использует номер версии или ETag, который был прочитан, поэтому обновления этой строки сериализуются. Если запись завершилась сбоем из-за несоответствия версии или ETag, повторных попыток S (повторная запись и попытка записи, если только P не помечен как мертвый).

    7. На высоком уровне эта последовательность "чтение, локальное изменение, обратная запись" — это транзакция. Однако для этого мы не используем транзакции хранилища. Код "Транзакция" выполняется локально на сервере, и мы используем оптимистическое параллелизм, IMembershipTable предоставленное для обеспечения изоляции и атомарности.

  6. Каждый silo периодически считывает всю таблицу членства для своего развертывания. Таким образом, силосы узнали о новых объединениях силосов и о других силосах, объявленных мертвыми.

  7. Конфигурация: мы предоставляем конфигурацию по умолчанию, которая была настроена вручную во время использования рабочей среды в Azure. В настоящее время по умолчанию: каждый сило отслеживается тремя другими силосами, два подозрения достаточно, чтобы объявить сило мертвым, подозрения только за последние три минуты (в противном случае они устарели). Pings отправляются каждые десять секунд, и вам потребуется пропустить три пинга, чтобы подозревать сило.

  8. Применение идеального обнаружения сбоев — теоретически возможно, что сило будет объявлено мертвым, если он потерял связь с другими силосами, в то время как сам процесс сило все еще работает. Чтобы решить эту проблему, как только силос объявлен мертвым в таблице, он считается мертвым всем, даже если он не мертв (просто секционирован временно или сердечные сообщения потеряны). Все перестают взаимодействовать с ним, и как только он узнает, что он мертв (считывая его новое состояние из таблицы), он зафиксирует самоубийство и завершает свой процесс. В результате на месте должна быть инфраструктура, чтобы перезапустить в качестве нового процесса (при запуске создается новый номер эпохи). При размещении в Azure это происходит автоматически. Если это не так, требуется другая инфраструктура. Например, служба Windows, настроенная для автоматического перезапуска при сбое или развертывании Kubernetes.

  9. Оптимизация для уменьшения частоты операций чтения и ускорения всех силосов о новых объединениях силосов и мертвых силосов. Каждый раз, когда любой сило пишет что-нибудь успешно в таблицу (подозрение, новое соединение и т. д.), он также вещает всем другим силосам - "идти и перечитать таблицу сейчас". Silo не сообщает другим, что он написал в таблице (так как эта информация уже может быть устаревшей или неправильной), она просто сообщает им повторно читать таблицу. Таким образом, мы очень быстро узнаем об изменениях членства без необходимости ждать полного периодического цикла чтения. Мы все еще нуждаемся в периодическом чтении, если сообщение "повторно прочитать таблицу" теряется.

Свойства базового протокола членства

  1. Может обрабатывать любое количество сбоев:

    Наш алгоритм может обрабатывать любое количество сбоев (то есть f<=n), включая полный перезапуск кластера. Это в отличие от "традиционных" решений на основе Paxos , которые требуют кворума, который обычно является большинством. Мы видели в производственных ситуациях, когда более половины силосов были вниз. Наша система остается функциональной, в то время как членство на основе Paxos не сможет добиться прогресса.

  2. Трафик к таблице очень легкий:

    Фактические проверки связи проходят непосредственно между серверами, а не в таблицу. Это приведет к созданию большого трафика плюс будет менее точным с точки зрения обнаружения сбоев - если сило не удалось достичь таблицы, он пропустил бы писать свой живой пульс, и другие убьет его.

  3. Неустранимая точность и полнота:

    Хотя вы не можете достичь идеального и точного обнаружения сбоев, один обычно хочет возможность компромисса точности (не хочу объявлять сило, который жив как мертвый) с полнотой (хотите объявить мертвый сило, который действительно мертв как можно скорее). Настраиваемые голоса для объявления мертвых и пропущенных оповечений позволяют торговать этими двумя. Дополнительные сведения см. в университете Йель: детекторы сбоев компьютеров.

  4. Scale (Масштаб):

    Базовый протокол может обрабатывать тысячи и, вероятно, даже десятки тысяч серверов. Это отличается от традиционных решений на основе Paxos, таких как протоколы групповой связи, которые, как известно, не масштабируются за десятки.

  5. Диагностика:

    Таблица также очень удобна для диагностика и устранения неполадок. Системные администраторы могут мгновенно найти в таблице текущий список живых силосов, а также просмотреть историю всех убитых силосов и подозрений. Это особенно полезно при диагностике проблем.

  6. Почему нам нужен надежный постоянный хранилище для реализации IMembershipTable:

    Для двух целей мы используем постоянное хранилище (таблица Azure, SQL Server, AWS DynamoDB, Apache ZooKeeper или Consul IO KV).IMembershipTable Во-первых, он используется в качестве точки свидания для силосов, чтобы найти друг друга и Orleans клиентов для поиска силосов. Во-вторых, мы используем надежное хранилище, чтобы помочь нам координировать соглашение о представлении членства. Хотя мы выполняем обнаружение сбоев непосредственно в одноранговом режиме между оси, мы сохраняем представление членства в надежном хранилище и используем механизм управления параллелизмом, предоставляемый этим хранилищем, чтобы достичь соглашения о том, кто жив и кто мертв. Таким образом, в смысле, наш протокол аутсорсинг трудной проблемы распределенного консенсуса в облаке. В этом случае мы полностью используем возможности базовой облачной платформы, используя ее действительно как платформу как услуга (PaaS).

  7. Что происходит, если таблица недоступна в течение некоторого времени:

    Если служба хранилища отключена, недоступна или возникают проблемы с взаимодействием, Orleans протокол НЕ объявляет силосы как мертвые по ошибке. Операционные силосы будут работать без каких-либо проблем. Тем не менее, Orleans не сможет объявить сильо мертвым (если он обнаруживает, что некоторые силос мертвы через пропущенные пинги, он не сможет написать этот факт в таблицу), а также не сможет позволить новым силосам присоединиться. Поэтому полнота будет страдать, но точность не будет - секционирование из таблицы никогда не приведет Orleans к объявлению сило как мертвым по ошибке. Кроме того, в случае частичной сетевой секции (если некоторые силосы могут получить доступ к таблице и некоторые нет), это может произойти, что Orleans будет объявлять мертвый сило как мертвый, но потребуется некоторое время, пока все остальные силосы не знают об этом. Таким образом, обнаружение может быть отложено, но Orleans никогда не будет неправильно убить сило из-за недоступности таблицы.

  8. Прямые записи IAmAlive в таблицу только для диагностика:

    Помимо пульса, которые отправляются между силосами, каждый сило также периодически обновляет столбец "Я Жив" в строке таблицы. Этот столбец "Я жив" используется только для устранения неполадок вручную и диагностика и не используется самим протоколом членства. Обычно он записывается на гораздо более низкой частоте (каждые 5 минут) и служит очень полезным инструментом для системных администраторов, чтобы проверка живость кластера или легко узнать, когда silo был последний живый.

Расширение для заказа представлений членства

Описанный выше базовый протокол членства был расширен для поддержки упорядоченных представлений членства. Кратко описаны причины этого расширения и его реализации. Расширение не изменяет ничего в приведенном выше дизайне, просто добавляет свойство, которое все конфигурации членства глобально упорядочены полностью.

Почему полезно упорядочить представления членства?

  • Это позволяет сериализовать присоединение новых силосов к кластеру. Таким образом, когда новый silo присоединяется к кластеру, он может проверить двустороннее подключение к каждому другому слоу, который уже запущен. Если некоторые из них уже присоединенные силосы не отвечают на него (потенциально указывая на проблему сетевого подключения с новым сило), новый сило не может присоединиться. Это гарантирует, что по крайней мере при запуске silo есть полное подключение между всеми оси в кластере (это реализовано).

  • Протоколы более высокого уровня в silo, такие как распределенный каталог зерна, могут использовать тот факт, что представления членства упорядочены и используют эту информацию для выполнения более интеллектуального разрешения повторяющихся активаций. В частности, когда каталог обнаруживает, что 2 активации были созданы при входе в поток, может решить отключить старую активацию, созданную на основе устаревших сведений о членстве.

Расширенный протокол членства:

  1. Для реализации этой функции мы используем поддержку транзакций по нескольким строкам, предоставляемым этим MembershipTableкомпонентом.

  2. Мы добавим строку версии членства в таблицу, которая отслеживает изменения таблицы.

  3. Когда silo S хочет написать подозрение или объявление о смерти для silo P:

    1. S считывает последнее содержимое таблицы. Если P уже мертв, ничего не делать. Иначе
    2. В той же транзакции запишите изменения в строку P, а также добавите номер версии и запишите его обратно в таблицу.
    3. Обе записи обусловлены ETags.
    4. Если транзакция прерывается из-за несоответствия ETag в строке P или строке версии, повторите попытку.
  4. Все записи в таблицу изменяют и увеличивают строку версии. Таким образом все операции записи в таблицу сериализуются (путем сериализации обновлений строки версии) и так как индексы только увеличивают номер версии, записи также полностью упорядочены в растущем порядке.

Масштабируемость расширенного протокола членства:

В расширенной версии протокола все записи сериализуются по одной строке. Это может повредить масштабируемость протокола управления кластерами, так как он повышает риск конфликтов между параллельными записью таблиц. Чтобы частично устранить эту проблему, выполните повторную попытку всех записей в таблицу с помощью экспоненциальной обратной передачи. Мы наблюдали расширенные протоколы для плавной работы в рабочей среде в Azure с до 200 силосов. Тем не менее, мы считаем, что протокол может иметь проблемы с масштабированием за пределами тысячи силосов. В таких больших настройках обновления строки версии могут быть легко отключены, по существу сохраняя остальную часть протокола управления кластерами и отказываясь от общего свойства упорядочивания. Обратите внимание также, что мы ссылаемся на масштабируемость протокола управления кластерами, а не остальной Orleansчасти. Мы считаем, что другие части Orleans среды выполнения (обмен сообщениями, распределенный каталог, размещение зерна, подключение клиента к шлюзу) являются масштабируемым способом за пределами сотен силосов.

Таблица членства

Как уже упоминание, IMembershipTable используется в качестве точки свидания для силосов, чтобы найти друг друга и Orleans клиентов для поиска силосов, а также помогает координировать соглашение о представлении членства. В настоящее время у нас есть шесть реализаций IMembershipTable: на основе таблицы Azure, SQL Server, Apache ZooKeeper, Consul IO, AWS DynamoDB и эмуляции в памяти для разработки.

  1. Таблица Azure служба хранилища. В этой реализации мы используем идентификатор развертывания Azure в качестве ключа секции и идентификатора сило (ip:port:epoch) в качестве ключа строки. Вместе они гарантируют уникальный ключ для каждого сило. Для управления параллелизмом мы используем элемент управления оптимистичным параллелизмом на основе ETags таблицы Azure. Каждый раз, когда мы читаем из таблицы, мы сохраняем ETag для каждой строки чтения и используем этот ETag при попытке обратной записи. ETag автоматически назначается и проверка служба таблиц Azure для каждой записи. Для транзакций с несколькими строками мы используем поддержку пакетных транзакций, предоставляемых таблицей Azure, которая гарантирует сериализуемые транзакции по строкам с одним ключом секции.

  2. 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.

  3. Apache ZooKeeper — в этой реализации мы используем настроенный идентификатор развертывания в качестве корневого узла и идентификатора silo (ip:port@epoch) в качестве дочернего узла. Вместе они гарантируют уникальный путь для каждого сило. Для управления параллелизмом мы используем элемент управления оптимистичным параллелизмом на основе версии узла. Каждый раз, когда мы считываем из корневого узла развертывания, мы сохраняем версию для каждого дочернего узла silo и используем эту версию при попытке обратной записи. Каждый раз при изменении данных узла номер версии увеличивается атомарно службой ZooKeeper. Для транзакций с несколькими строками мы используем многоуровневый метод, который гарантирует сериализуемые транзакции по узлам silo с одинаковым родительским узлом идентификатора развертывания.

  4. Consul IO — мы использовали хранилище ключей и значений Consul для реализации таблицы членства. Дополнительные сведения см. в статье Consul-Deployment .

  5. AWS DynamoDB . В этой реализации мы используем идентификатор развертывания кластера в качестве ключа секции и идентификатора Silo (ip-port-generation) в качестве RangeKey, делающего запись unity. Оптимистическая параллелизм выполняется атрибутом ETag путем создания условных операций записи в DynamoDB. Логика реализации довольно похожа на служба хранилища таблиц Azure.

  6. Эмуляция в памяти для настройки разработки. Мы используем специальное системное зерно, называемое MembershipTableGrainдля этой реализации. Это зерно живет на выделенном первичном сило, который используется только для установки разработки. В любой реальной рабочей среде основной silo не требуется.

Настройка

Протокол членства настраивается с помощью Liveness элемента в Globals разделе в Orleansфайле Configuration.xml . Значения по умолчанию были настроены в течение многих лет использования рабочей среды в Azure, и мы считаем, что они представляют хорошие параметры по умолчанию. Вообще изменить их не нужно.

Пример элемента конфигурации:

<Liveness ProbeTimeout="5s"
    TableRefreshTimeout="10s"
    DeathVoteExpirationTimeout="80s"
    NumMissedProbesLimit="3"
    NumProbedSilos="3"
    NumVotesForDeathDeclaration="2" />

Реализовано 4 типа активности. Тип протокола liveness настраивается с помощью SystemStoreType атрибута SystemStore элемента в разделе в GlobalsOrleansфайле Configuration.xml .

  1. MembershipTableGrain: таблица членства хранится в зерне на первичном сило. Это только настройка разработки.
  2. AzureTable: таблица членства хранится в таблице Azure.
  3. SqlServer: таблица членства хранится в реляционной базе данных.
  4. ZooKeeper: таблица членства хранится в ансамбле ZooKeeper.
  5. Consul: настроено как пользовательское системное хранилище с MembershipTableAssembly = "OrleansConsulUtils"помощью . Дополнительные сведения см. в статье Consul-Deployment .
  6. DynamoDB: настроено в качестве пользовательского системного хранилища с MembershipTableAssembly = "OrleansAWSUtils"помощью .

Для всех типов активности общие переменные конфигурации определяются в Globals.Liveness элементе:

  1. ProbeTimeout: Количество секунд, чтобы прощупать другие силосы для их активности или для silo, чтобы отправить "я жив" сердечных сообщений о себе. Значение по умолчанию — 10 секунд.
  2. TableRefreshTimeout: количество секунд для получения обновлений из таблицы членства. По умолчанию значение 60 секунд.
  3. DeathVoteExpirationTimeout: время окончания срока действия в секундах для голосования за смерть в таблице членства. Значение по умолчанию — 120 секунд
  4. NumMissedProbesLimit: Количество пропущенных "я жив" сердечных сообщений из сило или количества неответливых зондов, которые приводят к подозрению в этом сило как мертвые. Значение по умолчанию — 3.
  5. NumProbedSilos: количество силосов для каждой пробы сило для активности. Значение по умолчанию — 3.
  6. NumVotesForDeathDeclaration: число неисчисленных голосов, необходимых для объявления некоторых сило как мертвых (должно быть не более NumMissedProbesLimit). По умолчанию используется значение 2.
  7. UseLivenessGossip: следует ли использовать оптимизацию сплетни для ускорения распространения информации о жизни. Значение по умолчанию — "истина".
  8. IAmAliveTablePublishTimeout: количество секунд для периодической записи в таблице членства, в которую находится этот сайлос. Используется только для диагностика. Значение по умолчанию — 5 минут.
  9. NumMissedTableIAmAliveLimit: количество пропущенных обновлений "Я жив" в таблице из сайлона, что приводит к регистрации предупреждения. Не влияет на протокол liveness. По умолчанию используется значение 2.
  10. MaxJoinAttemptTime: количество секунд, чтобы попытаться присоединиться к кластеру силосов, прежде чем отказаться. Значение по умолчанию — 5 минут.
  11. ExpectedClusterSize: ожидаемый размер кластера. Не нужно быть очень точным, может быть чрезмерной. Используется для настройки экспоненциального алгоритма обратной передачи повторных попыток для записи в таблицу Azure. Значение по умолчанию — 20.

Обоснование проектирования

Естественный вопрос, который может быть задан, почему бы не полностью полагаться на Apache ZooKeeper для реализации членства в кластере, потенциально используя поддержку членства в группах с временными узлами? Почему мы беспокоили реализацию протокола членства? Были в первую очередь три причины:

  1. Развертывание и размещение в облаке:

    Zookeeper не является размещенной службой (по крайней мере на момент написания этой статьи 2015 года и определенно, когда мы впервые реализовали этот протокол летом 2011 года, не было версии Zookeeper, работающей как размещенная служба любым крупным поставщиком облачных услуг). Это означает, что в облачной среде Orleans клиентам придется развертывать и запускать и управлять экземпляром кластера ZK. Это просто еще один ненужный бремя, что мы не хотели заставить наших клиентов. Используя таблицу Azure, мы используем размещенную управляемую службу, которая упрощает жизнь клиента. В основном в облаке используйте облако как платформу, а не инфраструктуру. С другой стороны, при запуске локальной среды и управлении серверами, использование ZK в качестве реализации IMembershipTable является жизнеспособным вариантом.

  2. Прямое обнаружение сбоев:

    При использовании членства в группе ZK с временными узлами обнаружение сбоев выполняется между Orleans серверами (клиентами ZK) и серверами ZK. Это может не обязательно коррелировать с фактическими проблемами сети между Orleans серверами. Наше желание было в том, что обнаружение сбоев точно отражает состояние взаимодействия внутри кластера. В частности, в нашем дизайне, если Orleans сило не может взаимодействовать с IMembershipTable ним, он не считается мертвым и может продолжать работать. В отличие от этого, мы использовали членство в группах ZK с временными узлами отключение от сервера ZK может привести Orleans к тому, что клиент Silo (ZK) будет объявлен мертвым, в то время как он может быть жив и полностью функциональным.

  3. Переносимость и гибкость:

    В рамках Orleansфилософии мы не хотим принудительно принудить сильную зависимость от любой конкретной технологии, но вместо того чтобы иметь гибкий дизайн, где различные компоненты можно легко переключать с различными реализациями. Это именно цель, IMembershipTable которая служит абстракции.

Благодарности

Мы хотели бы признать вклад Алекса Когана в проектирование и реализацию первой версии этого протокола. Эта работа была выполнена в рамках летней стажировки в Microsoft Research в лето 2011 года. Реализация ZooKeeper была IMembershipTable выполнена Shay Hazor, реализация SQL IMembershipTable была выполнена Veikko Eeva, реализация AWS DynamoDB IMembershipTable была выполнена Gutemberg Ribeiro , а реализация Consul была IMembershipTable выполнена Полом Нортом.