Общие проблемы при разработке кластерных программных приложений, не связанных с веб-сайтами

Мне нужно переместить многопоточное приложение на основе Windows (которое использует глобальные переменные, а также RDBMS для хранения) в кластер NLB (например, сетевой балансировщик). Общие архитектурные проблемы, которые сразу приходят на ум, - это

  • Глобальные переменные (которые читаются и записываются) должны быть перемещены в общую память. Каковы лучшие практики здесь? Есть ли в Windows Clustering API что-нибудь доступное для управления такими вещами?

  • В моем приложении используются сокеты, а постоянные соединения - норма в области, в котором я работаю. Я считаю, что постоянные соединения не могут быть сбалансированы по нагрузке. Опять же, какие архитектурные рекомендации в этом отношении?

3 ответа

Сначала я отвечу на вопрос о постоянной связи вопроса, так как это проще. Все хорошие решения по балансировке сетевой нагрузки (включая службу Microsoft NLB, встроенную в Windows Server, но также включающую устройства балансировки нагрузки, такие как F5 BigIP) имеют возможность "прикреплять" отдельные соединения от клиентов к конкретным узлам кластера на время соединения. В Microsoft NLB это называется " Single Affinity", в то время как другие балансировки нагрузки называют это "Sticky Sessions". Иногда есть оговорки (например, Microsoft NLB будет разорвать соединения, если новый член добавляется в кластер, хотя одно соединение никогда не перемещается с одного узла на другой).

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

Большинство кластеризованных приложений, которые я видел, будут хранить разделяемое состояние (даже общее, изменчивое состояние, такое как глобальные переменные) в СУБД. Это в основном из-за удобства. Вы также можете использовать базу данных в памяти для максимальной производительности. Но простота использования RDBMS для всех разделяемых состояний (переходных и долговечных), а также использование существующих инструментов базы данных для обеспечения высокой доступности, имеет тенденцию работать для многих служб. Perf RDBMS, конечно, на несколько порядков медленнее глобальных переменных в памяти, но если общее состояние невелико, вы все равно будете считывать кеш-память RDBMS, и если вы делаете сетевой скачок для чтения/записи данных разница относительно меньше. Вы также можете внести большой вклад, оптимизируя схему базы данных для быстрого чтения/записи, например, удалив ненужные индексы и используя NOLOCK для всех запросов на чтение, где точна точность до миллисекунды не требуется.

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

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

Для более сложных случаев приложения могут переключаться с Pessimistic Concurrency (проверяя, что ресурс доступен заранее) до Оптимистичный Concurrency ( предположив его доступным, а затем позже отложите работу, если вы закончите, например, продаете один и тот же товар двум другим клиентам!).

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

Я бы не стал использовать MSCS (Microsoft Cluster Service) в вашем сценарии. MSCS - это решение для отказоустойчивости, что означает, что он отлично поддерживает односерверное приложение, даже если один из узлов кластера идет вниз, но вы не получите масштабируемости и простоты, которые вы получите от истинной балансировки нагрузки. Я подозреваю, что у MSCS есть способы совместного использования состояния (на общем диске), но им необходимо настроить кластер MSCS, который включает настройку отказоустойчивости, использование общего диска и другую сложность, которая не подходит для большинства приложений с балансировкой нагрузки. Вам лучше использовать базу данных или специализированное решение в памяти для хранения вашего общего состояния.


Что касается постоянного соединения, посмотрите в правила порта потому что правила порта определяют, какой порт tcpip обрабатывается и как.

MSDN:

Когда правило порта использует несколько хостов балансировка нагрузки, один из трех клиентов выбираются режимы сродства. Когда нет выбран режим близости клиента, Балансировка нагрузки балансировки нагрузки клиентский трафик с одного IP-адреса и разные порты источника на хосты с несколькими кластерами. Это максимизирует гранулярность балансировки нагрузки и минимизирует время отклика для клиентов. к помощь в управлении сеансами клиентов, единство по умолчанию для одного клиента режим нагрузки - балансирует весь сетевой трафик с данного IP-адреса клиента на однокластерный хост. Класс C режим привязки дополнительно ограничивает это для балансировки всего клиентского трафика из одного адресного пространства класса C.

В приложении asp.net то, что позволяет состояние сеанса быть постоянным, - это когда параметр параметров affinity клиента включен; NLB направляет все TCP-соединения с одного IP-адреса клиента на один и тот же узел кластера. Это позволяет поддерживать состояние сеанса в памяти хоста;

Параметр affinity клиента гарантирует, что соединение всегда будет маршрутизироваться на сервере, на котором он был первоначально выгружен; тем самым поддерживая состояние приложения.

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


  • Concurrency (Проверьте Apache Cassandra, и др.)
  • Скорость света (при переходе по пересеченной местности или в международном масштабе вам будет необходимо использовать транзакции)
  • Резервные копии и дедупликация (такие компании, как FalconStor, или EMC может помочь здесь в распределенной системе. Я бы не стал недооценивать необходимость консультации здесь)

licensed under cc by-sa 3.0 with attribution.