HAProxy как LoadBalanсer для RDP фермы. Надежное решение за 0$

    Совершенно случайно, в пассивном поиске альтернативы устаревшему 2X-LoadBalancer и тяжелому, непонятному Remote Connection Broker от MS наткнулся на HAProxy и его умению проксировать RDP трафик. В выдачах поисковиков практически не выдается haproxy в качестве прокси для RDP. Сейчас вдруг пачками стал выдавать. Вместе с тем, коммерческие продукты с таким же функционалом, такие как упоминались выше, стоят приличных денег.

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

    Как это работает, вкраце


    HAProxy умеет идентифицировать RDP, проксировать его и парсить rdp_cookie для выуживания из них нужной информации и последующего использования ее в механизме маршрутизации.

    Клиент подключается к прокси, тот вытаскивает логин из rdp_cookie, выбирает для него сервер, записывает значения «логин — сервер» в stick-table и подключает пользователя к серверу.
    Соотвественно, при следующем подключении этого же клиента(с этим логином) прокси находит запись в таблице и подключает его к тому серверу на котором у пользователя открытая сессия. Гениально и просто!

    stick-table — это таблица, хранящаяся в памяти процесса, где для каждой записи можно определить время жизни. Выставить 8 часов, и весь день клиент будет попадать на один и тот же сервер.

    Ниже стандартный конфиг:

    #/usr/local/etc/haproxy.conf
    global
    daemon
    stats socket /var/run/haproxy.sock mode 600 level admin
    stats timeout 2m
    
    defaults
    log     global
    mode tcp
    option tcplog
    option  dontlognull
    
    frontend fr_rdp
      mode tcp
      bind *:3389 name rdp
      log global
      option tcplog
      tcp-request inspect-delay 2s
      tcp-request content accept if RDP_COOKIE
      default_backend BK_RDP
    
    backend BK_RDP
      mode tcp
      balance leastconn
      timeout server 5s
      timeout connect 4s
      log global
      option tcplog
      stick-table type string len 32 size 10k expire 8h
      stick on rdp_cookie(mstshash),bytes(0,6)
    
      stick on rdp_cookie(mstshash)
      option tcp-check
      tcp-check connect port 3389
      default-server inter 3s rise 2 fall 3
      server TS01 172.16.50.11:3389 weight 10 check
      server TS02 172.16.50.12:3389 weight 20 check
      server TS03 172.16.50.13:3389 weight 10 check
      server TS04 172.16.50.14:3389 weight 20 check
      server TS05 172.16.50.15:3389 weight 10 check
      server TS06 172.16.50.16:3389 weight 10 check
      server TS07 172.16.50.17:3389 weight 20 check 
      server TS08 172.16.50.18:3389 weight 20 check
      
    listen stats 
     bind *:9000
     mode http
     stats enable
     #stats hide-version
     stats show-node
     stats realm Haproxy\ Statistics
     stats uri /
    

    Трудности


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

    #!/usr/bin/env python
    import sys
    import socket
    import re
    import subprocess
    
    haproxyConf = '/usr/local/etc/haproxy.conf'
    
    def restart():
    	backends = [] 	
    	with open(haproxyConf) as f:
    		for line in f:
    			lines = line.split(' ')
    			if lines[0] == 'backend':
    				backends.append(lines[1].strip('\n'))
    	for backend in backends:
    		getDataTables(backend)
    	rebootHa()
    	for backend in backends:
    		insertDataTables(backend)
    
    
    # Writes data from stik-tables to external files
    def getDataTables(table):
    	print table
    	tmp_f = open('/tmp/tmp.' + table,'w')
    	tableVal = {}
    	c = socket.socket( socket.AF_UNIX )
    	c.connect("/var/run/haproxy.sock")
    	c.send("prompt\r\n")
    	c.send("show table " + table + "\r\n")
    	d = c.recv(10240)
    	for line in d.split('\n'):
    		if re.search('^[a-zA-Z_0-9]',line):
    			line =  line.split(' ')
    			del line[0]
    			for item in line:
    				key = item.split('=')[0]
    				val = item.split('=')[1]
    				tableVal[key] = val
    			print tableVal['key']
    			print tableVal['server_id']
    			tmp_f.write(tableVal['key'] + ',' + tableVal['server_id'] + '\n')
    	tmp_f.close()
    
    
    def rebootHa():
    	subprocess.call("/usr/local/etc/rc.d/haproxy reload", shell=True)
     
    
    # Writes data from files to stik-tables
    def insertDataTables(table):
    	tmp_f = open('/tmp/tmp.' + table,'r')
    	c = socket.socket( socket.AF_UNIX )
    	c.connect("/var/run/haproxy.sock")
    	c.send("prompt\r\n")
    	for line in tmp_f:
    		line = line.split(',')
    		print "set table " + table + " key " + line[0] + " data.server_id " + line[1]
    		c.send("set table " + table + " key " + line[0] + " data.server_id " + line[1]  +"\r\n")
    		c.recv(10240)
    	c.close()
    
    restart()
    

    Что еще?


    Еще можно гибко управлять тем, на какие сервера проксировать тех или иных клиентов. Делать это можно на основании логина, ip адреса, сети, времени суток и т.п.
    Я же приведу пример как на основе групп из AD можно разбить сервера фермы по отделам, например:

    два сервера для Бухгалтерии
    два сервера для Маркетинга
    два сервера для Продажников
    два для всех остальных.

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

    HAProxy позволяет на основании определенных политик гибко определять к какому серверу подключать пользователя, имея одну точку входа для всех RDP подключений (что несомненно удобно).

    Для это необходимо немного модифицировать конфиг HAProxy и скрипт перезагрузки:

    #/usr/local/etc/haproxy.conf
    global
    daemon
    stats socket /var/run/haproxy.sock mode 600 level admin
    stats timeout 2m
    
    defaults
    log     global
    mode tcp
    option tcplog
    option  dontlognull
    
    frontend fr_rdp
      mode tcp
      bind *:3389 name rdp
     #timeout client 1h
      log global
      option tcplog
      tcp-request inspect-delay 2s
      tcp-request content accept if RDP_COOKIE
      acl Accounting_ACL rdp_cookie(mstshash),bytes(0,6) -m str -i -f /usr/local/etc/haproxy/Accounting
      acl Marketing_ACL rdp_cookie(mstshash),bytes(0,6) -m str -i -f /usr/local/etc/haproxy/Marketing
      acl Sales_ACL rdp_cookie(mstshash),bytes(0,6) -m str -i -f /usr/local/etc/haproxy/Sales 
      
      use_backend  Accounting_BK if Accounting_ACL
      use_backend  Marketing_BK if Marketing_ACL
      use_backend  Sales_BK if Sales_ACL  
     default_backend DF_RDP
    
    backend DF_RDP
      mode tcp
      balance leastconn
      log global
      option tcplog
      stick-table type string len 32 size 10k expire 8h
      stick on rdp_cookie(mstshash),bytes(0,6)
      option tcp-check
      tcp-check connect port 3389
      default-server inter 3s rise 2 fall 3
      server TS01 172.16.50.11:3389 weight 10 check
      server TS02 172.16.50.12:3389 weight 10 check
      
    backend Accounting_BK
      mode tcp
      balance leastconn
      log global
      stick-table type string len 32 size 10k expire 8h
      stick on rdp_cookie(mstshash),bytes(0,6)
      option tcplog
      tcp-check connect port 3389
      default-server inter 3s rise 2 fall 3
      server TS03 172.16.50.13:3389 weight 10 check
      server TS04 172.16.50.14:3389 weight 10 check
    
    backend Marketing_BK
      mode tcp
      balance leastconn
      log global
      stick-table type string len 32 size 10k expire 8h
      stick on rdp_cookie(mstshash),bytes(0,6)
      option tcplog
      tcp-check connect port 3389
      default-server inter 3s rise 2 fall 3
      server TS05 172.16.50.15:3389 weight 10 check
      server TS06 172.16.50.16:3389 weight 10 check
    
    backend Sales_BK
      mode tcp
      balance leastconn
      log global
      stick-table type string len 32 size 10k expire 8h
      stick on rdp_cookie(mstshash),bytes(0,6)
      option tcplog
      tcp-check connect port 3389
      default-server inter 3s rise 2 fall 3
      server TS07 172.16.50.17:3389 weight 10 check
      server TS08 172.16.50.18:3389 weight 10 check
    
    listen stats 
     bind *:9000
     mode http
     stats enable
     #stats hide-version
     stats show-node
     stats realm Haproxy\ Statistics
     stats uri /
    
    

    модифицированный скрипт перезагрузки:

    #!/usr/bin/env python
    import sys
    import ldap
    import socket
    import re
    import subprocess
    
    ldapDomain = ''
    ldapUser = ''
    ldapPass = ''
    ldapDN = '' # OU=GROUPS,DC=domain,DC=tld'
    haproxyConf = '/usr/local/etc/haproxy.conf'
    action = sys.argv[1]
    
    # Get users from Active Directory Groups and store it to files
    def getADGroups():
    	l = ldap.open(ldapDomain)
    	l.simple_bind_s(ldapUser,ldapPass)
    	f = open('/usr/local/etc/haproxy/' + groupName,'w')
    
    	results = l.search_s("cn=%s, %s" % (groupName, ldapDN), ldap.SCOPE_BASE)
    	for result in results:
    		result_dn = result[0]
    		result_attrs = result[1]
    	 	if "member" in result_attrs:
    			for member in result_attrs["member"]:
    				f.write(member.split(',')[0].split('=')[1] + '\n')
    	f.close()
    	restart()
    
    
    # Searching stik-tables to save it and to restore after reload
    def restart():
    	backends = [] 	
    	with open(haproxyConf) as f:
    		for line in f:
    			lines = line.split(' ')
    			if lines[0] == 'backend':
    				backends.append(lines[1].strip('\n'))
    	for backend in backends:
    		getDataTables(backend)
    	rebootHa()
    	for backend in backends:
    		insertDataTables(backend)
    
    
    # Writes data from stik-tables to external files
    def getDataTables(table):
    	print table
    	tmp_f = open('/tmp/tmp.' + table,'w')
    	tableVal = {}
    	c = socket.socket( socket.AF_UNIX )
    	c.connect("/var/run/haproxy.sock")
    	c.send("prompt\r\n")
    	c.send("show table " + table + "\r\n")
    	d = c.recv(10240)
    	for line in d.split('\n'):
    		if re.search('^[a-zA-Z_0-9]',line):
    			line =  line.split(' ')
    			del line[0]
    			for item in line:
    				key = item.split('=')[0]
    				val = item.split('=')[1]
    				tableVal[key] = val
    			print tableVal['key']
    			print tableVal['server_id']
    			tmp_f.write(tableVal['key'] + ',' + tableVal['server_id'] + '\n')
    	tmp_f.close()
    
    
    def rebootHa():
    	#pass
    	subprocess.call("/usr/local/etc/rc.d/haproxy reload", shell=True)
     
    
    # Writes data from files to stik-tables
    def insertDataTables(table):
    	#pass
    	tmp_f = open('/tmp/tmp.' + table,'r')
    	#tableVal = {}
    	c = socket.socket( socket.AF_UNIX )
    	c.connect("/var/run/haproxy.sock")
    	c.send("prompt\r\n")
    	for line in tmp_f:
    		line = line.split(',')
    		print "set table " + table + " key " + line[0] + " data.server_id " + line[1]
    		c.send("set table " + table + " key " + line[0] + " data.server_id " + line[1]  +"\r\n")
    		c.recv(10240)
    	c.close()
    
    
    if action == 'restart':
    	restart()
    if action == 'group':
    	groupName = sys.argv[2]
    	getADGroups()
    

    Как это работает:
    В AD создаются группы (и наверняка такие группы уже есть) Accounts, Marketing и Sales, в эти группы помещаются сотрудники. Скрипт подключается к AD и получает список сотрудников по выбранным группам. Список сотрудников сохраняется в файл с именем группы.

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

    Прокси проверяет, есть-ли логин в указанном файле. Если есть, отправляет на определенный для этой группы бакенд. Все очень просто!

    Параметры запуска скрипта:
    haproxy.py group group_name — перезагрузка группы, текущие сессии при этом не обрываются.
    haproxy.py restart — перезагрузка процесса (перечитать конфиг), при этом текущие сессии не обрываются.

    Отказоустойчивость


    Ее нет!

    В данном примере решение не обладает никакой отказоустойчивостью.

    Во первых, не зарезервирован haproxy.

    Во вторых, решение с записью значений «клиент-сервер» в stick-table не позволяет haproxy подключать пользователей к живым серверам, чьи записи уже есть в таблице, и сервер к которому они были подключены в данным момент недоступен. Он тупо будет пытаться отправить их на сервер из таблицы, несмотря на то, что он не в сети.

    Первое, резервирование haproxy можно сделать различными способами.

    Один из них — модифицированый скрипт перезагрузки. В него можно добавить копирование и загрузку сохраненных таблиц на другом haproxy, с запуском этого скрипта переодически по крону.
    Спасибо vasilevkirill, есть встроенное решение, которым он поделился в комментарии
    habrahabr.ru/post/335872/#comment_10369854

    Второе сложнее. Нужен механизм, который бы точно определял, что с сервером. Сервер может по каким то легальным и не очень причинам быть не доступен по сети некоторое время, скажем 1 минуту, к примеру. Но при этом иметь открытыми все RDP сессии. И если мы решим, что сервер больше не доступен, и нужно всех пользователей переключать на другие сервера, то можем получить несохраненные данные, клиенты могут потерять большой обьем работ и тп.

    Технически же, реализовать очистку stick-table не вызывает трудности. Для отслеживания состояния серверов можно использовать различные мониторинговые системы. В том же Zabbix, по событиям можно вызывать локальные скрипты.В нашем случае можно вызывать скрипт очистки stick-table.

    В заключении, с учетом тех недостатков, которые я указал выше, HAProxy работает очень стабильно и надежно.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 32
    • 0
      тяжелому, непонятному Remote Connection Broker от MS
      коммерческие продукты с таким же функционалом, такие как упоминались выше, стоят приличных денег.

      Хм… ничего не имею против HAProxy, но справедливости ради — брокер от MS штатно является частью винды (т.е. при уже имеющихся лицензиях на N серверов, на которых крутятся роли удаленных рабочих столов, попросту бесплатен), ставится по "Next-Next-Next, и работает", ресурсов практически не потребляет и не обладает рядом озвученных для HAProxy проблем.

      • +1
        Судя по всему имеет ровно те же проблемы. Штатно нет резервирования брокера, и соответсвенно нет резервирования активных сессий. Для резервирования брокера нужен выделенный MS SSQL сервер в редакции Standart.
        О проблемах невозможности подключиться к ферме, когда вышел из строя сервер на котором был пользователь, в сети тоже полно сообщений.

        Из минусов Remote Connection Broker от MS отмечу необходимость специально подготавливать rdp файлы и невозможность разделять сервера в ферме как в примере.

        Но в целом, я не называл бы проблемами отсутствие резервирования брокера, это недостатки. Основная функция брокера на мой взгляд — это горизонтальная масштабируемость.
        • 0
          Из минусов Remote Connection Broker от MS отмечу необходимость специально подготавливать rdp файлы и невозможность разделять сервера в ферме как в примере.

          Разве?
          Для каждой группы, далается своя RDP Collection, в которую включены необходимые для нее сервера.
          Про подготавливать rdp файлы — честно говоря не понял что под эти имеется ввиду.
          • 0
            В RDP файле необходимо явно указывать параметр loadbalanceinfo. Это не всегда удобно.
            • 0
              Если я правильно понимаю, о чем идет речь, то эта настройка балансировки меняется через GUI Server Manager'а, в RDP Session Collection, с возможностью выставить relative weigth и session limit для каждого из входящих в коллекцию серверов.
              • 0
                У меня есть ферма, которую я назвал farm.local. Если я зайду через mstsc на farm.local то попаду на брокер. Если открою специальный RDP файл, где есть строчка loadbalanceinfo — попаду на RDSH из фермы
                • 0
                  Если на ферме одна коллекция рабочих столов, то даже без loadbalanceinfo вас бросит на наименее нагруженный (по сеансам) RDSH.
                  Случаи с несколькими коллекциями не тестил, возможно там и работает так, как вы описали.
                  • 0
                    У меня одна коллекция и так не работает.
                    • 0
                      А какую версию RDS используете? Что то мне это сильно напоминает 2008/2008 R2 — там ярлычки нужно было генерить.

                      Начиная с 2012 с определенного патча или 2012 R2 все очень сильно поменялось. Правильный способ коннекта — через веб каталог. Ярлычки туда публикуются автоматом. Так же он отлично пристегуется к RemoteApp and Desktop в Win7-10. Без проблем работает как в корп сети, так и за ее пределами через Gateway при правильном сетапе. Балансирует нормально.
                      Сетап следующий:
                      2xRD Gateway (Windows NLB)
                      2xRD Web (Windows NLB)
                      2xConnection Broker (DNS Round Robin) + External SQL cluster
                      2xSOFS for user profile vhds
                      3 коллекции по 2 сервера для RDSH
                      2 коллекции по 2 сервера для RemoteApp

                      Gateway и Web прекрасно живут совместно, но были вопросы от IT Security, так что разнесли в разные сети DMZ.

                      Ну а брокер — он есть всегда. Даже при Single Server — без него это не рабоатет и не инсталлится.
                      • 0
                        У нас своя сборка тонких клиентов, через веб это работает излишне сложно для пользователя. Сервер 2012R2, два брокера.
                  • 0
                    Все верно.
                    Только стоит упомянуть, что автоматически сформированные RDP файлы, как для полноценных RDP сессий так и для RemoteApp, публикуются на RD Web Access и «ручками» ничего править не надо. ))
            • +1
              Штатно нет резервирования брокера, и соответсвенно нет резервирования активных сессий. Для резервирования брокера нужен выделенный MS SSQL сервер в редакции Standart.

              У нас, видимо, разные представления о том, что такое "штатно нет". У MS как раз "штатно есть" документированная Active-Active конфигурация, а вот у HAProxy вам придется колхозить скрипты вручную. И SQL Standard там не нужен, а просто рекомендован, на практике же для не слишком монструозных инсталляций ничто не мешает бесплатный использовать. Плюс брокер от MS штатно не страдает от проблемы "резетнули хост — потеряли базу сессий", поэтому требования к резервированию менее жесткие.


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

              У любого брокера будут подобные проблемы просто в силу самого принципа работы — если один из серверов лежит, это надо как-то обнаружить и принять меры, чтобы брокер об этом узнал. Для HAProxy вам надо опять вручную прикручивать некий мониторинг, а вот у MS определение живых серверов все-таки работает из коробки. Ситуаций, когда один из серверов в ферме по тем или иным причинам ложился, у меня за почти 10 лет работы с терминальными фермами от MS было достаточно, и я так сразу не вспомню связанных с этим проблем. Охотно верю, что у кого-то они были, но там уже надо разбираться в причинах.


              необходимость специально подготавливать rdp файлы

              Нет такой необходимости.


              невозможность разделять сервера в ферме как в примере

              Возможность есть, только реализована в другом компоненте — RD Gateway. А HAProxy в некотором роде сочетает возможности и того, и другого (в усеченном виде, хотя опять-таки кастомными скриптами можно много чего докрутить).

              • 0
                >Нет такой необходимости.

                А можете рассказать зачем тогда нужен параметр loadbalanceinfo в rdp файле. Я бы с радостью от него избавился, но незнаю как. Ниже уже писал что без него я попадаю на брокера а не на хост в ферме.
                • 0

                  Брокер, вообще говоря, не предназначен для того, чтобы точкой входа быть. Вариантов сходу три:


                  1. RD Gateway (хоть от MS, хоть еще какой)
                  2. Выделенный RDSH в drain mode (или пара с общим DNS именем для отказоустойчивости). Работает исключительно как точка входа, сам никакой нагрузки не несет.
                  3. Совсем просто и сердито — добавить для каждого сервера в ферме в DNS A запись вида terminal.domain.name и подключаться по этому адресу непосредственно на них.
                • 0
                  >У нас, видимо, разные представления о том, что такое «штатно нет». У MS как раз >«штатно есть» документированная Active-Active конфигурация, а вот у HAProxy вам >придется колхозить скрипты вручную.
                  Ниже в комментариях написали, что таки есть, штатное средство в HAproxy для горячего резервирования!, в отличии все таки, нештатного(не средствами сервиса) резервирования от MS(если придираться).

                  К тому же говоря о штатных средствах и «колхозных скриптах», хочется отметить что Unix Way — это использование стольких средств(сервисов, скрипитов, программ и тп), сколько необходимо для достижения цели. Корче для unix это нормально, и это доказано, и это работает, в этом мире, и хорошо :)
              • 0

                У него своих проблем хватает. К примеру штатно нельзя удалить из фермы выключенный сервер или закрыть на него логон. Или сессии сбросить, которые на нем зависли. Это все приходится делать через БД.


                А на сайте Microsoft написано:


                To safely remove the server from your RDS deployment, contact Microsoft Customer Support Services. For a complete list of Microsoft Customer Support Services telephone numbers and information about support costs, visit the following Microsoft website

                Important
                We do not recommend that you manually edit the database that is used by the RDS deployment.

                https://support.microsoft.com/en-us/help/2925854/cannot-remove-an-rd-host-from-an-rds-deployment

                • 0

                  По вашей ссылке описана ситуация, когда сервер аж из AD удалили, а про ферму позабыли. :) Выстрелить себе в ногу всегда можно, это бесспорно.

                  • 0
                    Вы немного передергиваете. Удалить выключенный сервер из фермы можно, само удаление проходит с предупреждениями, но доходит до конца.
                    В статье говорится про ситуацию, когда в ферме есть выключенный сервер и его учетка удалена в AD. Вы часто такое делаете?
                    • 0
                      Да, дезинформировал всех. Сервер действительно выходит удалить. Может еще сессии научите гасить на зависшем сервере?
                • +4

                  Маленькие уточнения


                  Так как клиент mstsc не передаёт в куки больше 9 символов, нет смысла делать длинну более девяти


                  stick-table type string len 9 size 10240k expire 48h peers loadbalancer_replication

                  причем будет происходить реплика между пирами stick-table


                  peers loadbalancer_replication
                  peer spb-ts-haproxy-11 10.101.255.11:7778
                  peer spb-ts-haproxy-12 10.101.255.12:7778
                  peer spb-ts-haproxy-13 10.101.255.13:7778
                  peer spb-ts-haproxy-14 10.101.255.14:7778

                  Для резервирования HAproxy используйте keepalived (aka VRRP) назначаете общий IP адрес (так как это VRRP между хостами должен бегать мультикаст)


                  Чекать сервера можно таким образом (в одну строку)


                  server spb-ts-des-102 10.101.251.102:3389 weight 1 check inter 2000 rise 2 fall 3 minconn 0 maxconn 0 on-marked-down shutdown-sessions verify none
                  • +1

                    Если коллекция одна то можно заюзать ключ реестра DefaultTsvUrl
                    а что делать если коллекций 2+ и нужно что б юзерыдля подключния использовали только RR DNS имени брокера ??

                    • 0
                      На совсем понимаю зачем костыли, если все работает «из коробки»? На чем экономить собираетесь? Если у вас мимнимум — 2 железяки — подымите на них виртуализацию и на каждом из них по шлюзу+броекру+вебу и вторым — сессионный хости либо приложения. Лицензия Windows Server Standard покрывает 2 виртуалки на хосте. Эконом-вариантов — море. Только на DC не навесьте много. Из RDS инфраструктуры на них вполне нормально работают Licensing server — проверено.
                      • 0

                        Есть N групп юзеров. На кажду группу по 6-10 хостов. Хочу в рамках 1го НА-брокера получить 1 (ну накрайняк N штук) адрес входа для юзеров который они будут вводить в RPD-клиенте. Как? Поднимать на каждую группу свою ферму?

                        • 0

                          повести разные ИП адреса на HAproxy и с помощью DNS разрулите

                          • 0
                            Публикация созданных для каждой из групп, RD Collection, состоящих из нужных хостов, на RD Web Access (1 адрес входа).
                            Штатные средства WS 2012R2.
                            • 0
                              прошу прощения, данная штукенция в 2012 сдюжит полторашку (1500) клиентов? А-то в 2012 без r2 web был узким местом, ещё и его приходилось балансировать.
                              • 0
                                Разумеется, Web Access, нужно будет балансировать через NLB, не только для разпределения нагрузки, но и, в первую очередь — для отказоустойчивости.
                              • 0

                                нет Remote App — есть полноценные сеансы на RDSH

                              • 0
                                ну или порт менять
                          • 0
                            в данном решении нет UDP и heathcheck, из-за этого я остановился на nginx.
                            • 0
                              расскажите подробнее?
                              • 0
                                а чё тут рассказывать, хотя бы тупой tcp heathcheck github.com/yaoweibin/nginx_upstream_check_module (некоторые заморачиваются с рдп клиентом), и stream помимо TCP 3389 ещё и на udp, прокатывает даже для NComputing vSpace, а уж HA на линуксах изобразить — проще простого.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.