Как сделать активные сервисы максимально доступными? - PullRequest
8 голосов
/ 17 апреля 2010

Я знаю, что с Network Load Balancing и Failover Clustering мы можем сделать пассивные услуги высокодоступными. Но как насчет активных приложений ?

Пример. Одно из моих приложений извлекает некоторый контент из внешнего ресурса через фиксированный интервал. Я представил следующие сценарии:

  1. Запустите его на одной машине. Проблема: если этот экземпляр падает, содержимое не будет извлечено
  2. Запустите его на каждой машине кластера. Проблема: содержимое будет извлечено несколько раз
  3. Имейте это в каждой машине кластера, но запустите это только в одной из них. Каждый экземпляр должен будет проверять какой-то общий ресурс, чтобы решить, выполнять свою задачу или нет.

Когда я размышлял над решением № 3, я задавался вопросом, каким должен быть общий ресурс. Я думал о создании таблицы в базе данных, где мы могли бы использовать ее для получения глобальной блокировки.

Это лучшее решение? Как люди обычно делают это?

Кстати, это приложение CF .NET WCF, работающее на Windows Server 2008

Ответы [ 6 ]

4 голосов
/ 20 апреля 2010

Для таких проблем они изобрели очереди сообщений. Представьте себе случай, когда все ваши кластерные приложения прослушивают очередь сообщений (сама кластеризованная :-)). В какой-то момент один экземпляр получает вашу начальную команду для загрузки вашего внешнего ресурса. В случае успеха ваш экземпляр сбрасывает сообщение и вместо этого отправляет другое для более позднего времени выполнения, равного «времени выполнения» + «интервал». Но если экземпляр умирает во время обработки, это не проблема. Сообщение откатывается в очередь (после истечения времени ожидания), и некоторые другие экземпляры могут забрать его. Немного транзакций, немного очередей сообщений

Я нахожусь на стороне Java EE, поэтому могу помочь вам с подробностями кодирования

1 голос
/ 26 апреля 2010

Есть некоторые требования, которые вы, вероятно, знаете, но не были описаны в вопросе, которые затрудняют предоставление информированного ответа. Вот некоторые из этих вопросов:

  • Должна ли задача успешно завершиться?
  • Если задание выполнено / не выполнено успешно, «кому» нужно знать и какой тип действий необходимо выполнить?
  • Каково поведение, если задача еще не завершена, когда придет время снова запустить задачу? Это должно бежать или нет?
  • Насколько важно, чтобы задания выполнялись с заданным интервалом? Если интервал составляет каждые 5 минут, должен ли он быть каждые 5 минут или задача может выполняться через 5 минут и 10 секунд?

Первый шаг - ответить, как будет запланировано выполнение периодического задания. Одним из вариантов является запланированное задание Windows, но оно не является высоко доступным по своей природе, но может быть возможным обойти это. Если вы используете SQL Server, другой альтернативой может быть использование агента SQL Server в качестве планировщика, поскольку он будет переключаться при сбое как часть SQL Server.

Следующим шагом для определения является способ вызова приложения WCF. Самый простой вариант - запустить задание для вызова службы WCF через IP-адрес NLB. Это можно считать «нет-нет», если сервер базы данных (или другой сервер в этой зоне) обращается к зоне приложения (конечно, всегда есть исключения, такие как MSDTC).

Другим вариантом будет использование модели очереди. Это было бы наиболее надежным в большинстве ситуаций. например Агент SQL Server может выполнить хранимую процедуру для ввода записи в таблицу очередей. Затем на каждом сервере приложений служба может опрашивать в поисках записи в очереди для обработки. Доступ к записи в очереди будет сериализован базой данных, так что первый сервер будет выполнять задание (и это задание будет выполняться только один раз).

В зависимости от ответов на вводные вопросы в этом ответе вам, возможно, придется добавить еще несколько способов обработки ошибок. Если извлечение внешнего ресурса обычно довольно короткое, вы можете просто сохранить запись очереди заблокированной с помощью select for update, а по завершении задачи обновить состояние (или удалить запись, если хотите). Это заблокирует другие экземпляры службы от обработки записи, пока она обрабатывается на другом сервере, и если во время обработки происходит сбой, транзакцию следует откатить, и другая служба в кластере может получить запись. (Хотя вы можете увеличить тайм-аут транзакции так долго, как считаете нужным.)

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

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

1 голос
/ 23 апреля 2010

С точки зрения простоты, самый быстрый / простой способ выполнить то, что вы ищете, - это «циклически перебирать» ваш кластер, чтобы для каждого запроса выбиралась машина (службой управления кластером или некоторые такие) для обработки запроса. Фактические запросы клиентов не отправляются непосредственно на компьютер, который их обрабатывает; вместо этого они указывают на одну конечную точку, которая действует как прокси-сервер для распределения входящих запросов на компьютеры в зависимости от доступности и нагрузки. Чтобы процитировать ссылку ниже,

Балансировка сетевой нагрузки - это способ настроить пул машин, чтобы они по очереди отвечали на запросы. Чаще всего это реализуется в фермах серверов: одинаково настроенные машины, распределяющие нагрузку на веб-сайт, или, возможно, ферма терминальных серверов. Вы также можете использовать его для фермы брандмауэров (ISA), точек доступа vpn, действительно, всякий раз, когда у вас есть трафик TCP / IP, который стал слишком загруженным для одной машины, но вы все равно хотите, чтобы он отображался как одна машина для цели доступа.

Что касается того, что ваше приложение является "активным", это требование не учитывается в этом уравнении, так как приложение "активное" или "пассивное" по-прежнему выполняет запрос к вашим серверам.

Существуют коммерческие балансировщики нагрузки для обслуживания запросов в стиле HTTP, поэтому, возможно, стоит взглянуть на них, но с функциями балансировки нагрузки в W2k8 вам лучше всего воспользоваться этими возможностями.

Для получения дополнительной информации о том, как настроить это в Win2k8, см. эту статью.

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

см. Здесь для другого подробного обзора настройки и конфигурации NLB.

Если это не удастся, вы будете хорошо обслуживаться поиском / публикацией на ServerFault, поскольку код вашего приложения не (и не должен) точно знать, что NLB даже существует.

РЕДАКТИРОВАТЬ: добавил еще одну ссылку.

РЕДАКТИРОВАТЬ (2-е): ОП исправил мой ошибочный вывод в концепции «активный» или «пассивный». Мой ответ на него очень похож на мой первоначальный ответ, за исключением того, что «активная» служба (которая, поскольку вы используете WCF, легко может быть службой Windows) может быть разделена на две части: фактическую часть обработки и часть управления. Управляющая часть будет работать на одном сервере и действовать как циклический балансировщик нагрузки для других серверов, выполняющих фактическую обработку. Это немного сложнее, чем оригинальный сценарий, но я считаю, что он обеспечит большую гибкость, а также обеспечит четкое разделение между вашей обработкой и логикой управления.

1 голос
/ 23 апреля 2010

Я однажды реализовал нечто подобное, используя ваше решение № 3.

Создайте таблицу с именем, например, resource_lock, со столбцом (например, locking_key), который будет содержать ключ блокировки.

Тогда на каждом интервале все экземпляры вашего приложения будут:

  1. Запустите запрос вроде 'update resource_lock set resource_key = 1 where resource_key is null'. (конечно, вы также можете вставить идентификатор сервера, метку времени и т. д.)
  2. Если обновлено 0 строк: ничего не делать - другой экземпляр приложения уже извлекает ресурс.
  3. Если обновлена ​​1 строка: извлечь ресурс и установить locking_key обратно на null.

Есть два преимущества:

  • Если один из ваших серверов выйдет из строя, ресурс по-прежнему будет выбираться серверами, которые все еще работают.
  • Вы оставляете блокировку для базы данных, это избавляет вас от ее реализации самостоятельно.
0 голосов
/ 30 июля 2013

Zookeeper хорошо использует распределенные блокировки.У Zookeeper есть z-узлы, которые похожи на каталог с данными.

Даже у куратора netflix уже есть множество рецептов, готовых и используемых.Нравится: выборы лидера, распределенная блокировка и многое другое.

Я думаю, что у нас есть клиент zookeeper для C #.Вы должны обязательно попробовать этот вариант.# Вариант3

0 голосов
/ 22 апреля 2010

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

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

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

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

...