информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Все любят медГде водятся OGRы
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Насчет 1000 потоков - небольшой ликбез 06.11.05 20:48  Число просмотров: 1651
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Каждый поток по дефолту отжирает мегабайт адресного пространства процесса под свой стек. Т.е. память не выделяется сразу, просто адреса резервируются (выделение памяти происходит по мере роста стека потока). А поскольку адресное пространство ограничено 2 Гб то при кол-ве потоков 2000 оно закнчится. В реальных условиях количество еще меньше так как адресное пространство используетя не только для стеков. Решения - либо в настройках линкера уменьшить размер стека, либо резервировать под стек меньше адресного пространства в CreateThread, но флаг STACK_SIZE_PARAM_IS_A_RESERVATION появился только в ХР. А лучше если потоков реально так много - менять архитектуру.
<programming>
Плохая архитектура 06.11.05 05:41  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Недавно обсуждал вопрос об архитектуре сервера реализующего кастом команд-ориентед протокол ...
Транспорт - TCP. Мне сказали, что архитектура, когда сервер делается в первичном потоке на блокирующем прослушивающем сокете (Беркли интерфейс), и когда каждый клиент обслуживается в отдельном потоке - сакс. Было сказано, что такой софт никто не будет покупать... Было заявлено, что всё на самом деле можно сделать в одном потоке. Было сказано также, что Winsock Microsoft вообще тянет как устарелую технологию только ради поддержки старых приложений. Типа сейчас так уже не пишут. :cry:
Вот я и думаю... Как я отстал от жизни. Как же сделать так, чтобы всё работало без отдельных потоков для клиентов.

Спасибо.
ПС. Интересно мнение не только тех кто проектирует под виндовз, но *никс тоже.
Неблокирующие сокеты 06.11.05 15:25  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Они были и в берклиевских и получили развитие в винсоке. Что там те про устаревание говорили - хз.
вариант 1: создаешь сокет переводишь его в неблокирующий режим через ioctlsocket и далее ждешь этих всех сокетов через select
вариант 2 и 3 - винсоковые расширения вышеописанного варианта - WSAAsyncSelect и WSAEventSelect
Спасибо за ответ. Попробую разобраться. Чтобы правильно... 06.11.05 19:23  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Спасибо за ответ. Попробую разобраться. Чтобы правильно задать вопрос - хочу попробовать вначале.
Но всё же есть навскидку несколько вопросов...

> вариант 1: создаешь сокет переводишь его в неблокирующий
> режим через ioctlsocket и далее ждешь этих всех сокетов
> через select

Положим селект сказал, что в сокет i содержит данные. Тогда мы можем переключиться на функцию работы с этим клиентом -> Там надо будет "вычитать" команду клиента заданного формата и размера в (размер в заголовке "пакета" прикладного протокола). Сделать ещё какую-то работу и отослать клиенту команду-ответ.

Вопрос: Что будет, если "одновременно" готовы клиентские сокеты с данными от других i+1, +2, +n клиентов. Будут ли они вынуждены ждать, пока для первого клиенты будет выполненавсяработа, требующая некоторого времени, например, получить данные из базы данных?

> вариант 2 и 3 - винсоковые расширения вышеописанного
> варианта - WSAAsyncSelect и WSAEventSelect

Буду смотреть. Спасибо.
Да, если требуется длительная обработка запросов - это... 06.11.05 19:32  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Да, если требуется длительная обработка запросов - это недостаток такого подхода. Впрочем вполне преодолимый путем запуска по необходимости дополнительных потоков которые асинхронно обрабатывают все и отправляют ответы в сокеты. Этакий гибридный подход. Потоков получится меньше чем сокетов, и все будет работать без задержек. Но сделать чтоб все это нормально работало задача очень нетривиальная.
Рабочие потоки или порты завершения ввода/вывода 07.11.05 12:13  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Да, если требуется длительная обработка запросов - это
> недостаток такого подхода. Впрочем вполне преодолимый путем
> запуска по необходимости дополнительных потоков которые
> асинхронно обрабатывают все и отправляют ответы в сокеты.
> Этакий гибридный подход. Потоков получится меньше чем
> сокетов, и все будет работать без задержек. Но сделать чтоб
> все это нормально работало задача очень нетривиальная.

Worker threads придется реализовывать самому. Создается пул потоков, очередь обработки (защищенная мьютексом). Все эти потоки становятся в ожидание одного синхронизирующего (с самосбросом) event-а. Когда необходимо выполнить некую работу, основной поток заполняет структуру, в которой есть все данные, необходимые для выполнения этой работы, вставляет ее в очередь и сигналит event. Первый из ожидающих потоков просыпается, блокирует мьютексом очередь обработки, забирает из очереди свое задание (с удалением его из очереди), разблокирует очередь и начинает спокойно выполнять задание.

Ну а в IoCompletion объектах (в win32 Completion Ports) это все уже реализовано (только в NT, но не думаю, что кто-то станет писать высокопроизводительный сервер с прицелом на 9x).

http://msdn.microsoft.com/library/en-us/fileio/base/i_o_completion_ports.asp

Ну и несколько полезных ссылок (с примерами)

http://msdn.microsoft.com/library/en-us/dndllpro/html/msdn_servrapp.asp
http://msdn.microsoft.com/library/en-us/dndllpro/html/msdn_scalabil.asp
http://msdn.microsoft.com/msdnmag/issues/1000/winsock/default.aspx
Спасибо за мнение и ссылки. IOCP - именно это сейчас хочу... 08.11.05 19:04  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Спасибо за мнение и ссылки. IOCP - именно это сейчас хочу посмотреть.

> Worker threads придется реализовывать самому. Создается пул
> потоков, очередь обработки (защищенная мьютексом).

Почему именно мьютексом?


> Все эти потоки становятся в ожидание одного синхронизирующего (с
> самосбросом) event-а.

кто устанавливает event? В лупе первичного потока проверкой select наличие данных в буфере данных сокета одного из клиентов?

Когда необходимо выполнить некую
> Когда необходимо выполнить некую работу, основной поток заполняет структуру, в которой есть
> все данные, необходимые для выполнения этой работы,
> вставляет ее в очередь и сигналит event. Первый из
> ожидающих потоков просыпается, блокирует мьютексом очередь
> обработки, забирает из очереди свое задание (с удалением
> его из очереди), разблокирует очередь и начинает спокойно
> выполнять задание.

Впростейшем случае, если используется STL контейнеры - критической секцией нельзя защищтить очередь?

> http://msdn.microsoft.com/library/en-us/fileio/base/i_o_com
> pletion_ports.asp
>
> Ну и несколько полезных ссылок (с примерами)
>
> http://msdn.microsoft.com/library/en-us/dndllpro/html/msdn_
> servrapp.asp
> http://msdn.microsoft.com/library/en-us/dndllpro/html/msdn_
> scalabil.asp
> http://msdn.microsoft.com/msdnmag/issues/1000/winsock/defau
> lt.aspx

Ещё раз спасибо.
Я сам свои ссылки перечитал. В общем я несколько неправильно... 09.11.05 11:26  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Спасибо за мнение и ссылки. IOCP - именно это сейчас хочу посмотреть.

Я сам свои ссылки перечитал. В общем я несколько неправильно понимал принцип действия iocp, но все равно - это самый эффективный метод реализации масштабируемых серверов на NT-платформе. На самом деле в эту очередь добавляются хендлы с запрошенным асинхронным вводом/выводом. И этот порт можно ждать при помощи WaitForSingleObject. Когда любая из операций завершается - порт становится в signalled state. И из него можно вычитать данные о завершившейся операции. Рабочие потоки все равно придется создавать самому, правда раздача заданий несколько упрощается. В общем смотри примеры.

> > Worker threads придется реализовывать самому.
> Создается пул
> > потоков, очередь обработки (защищенная мьютексом).
>
> Почему именно мьютексом?

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

> > Все эти потоки становятся в ожидание одного
> синхронизирующего (с
> > самосбросом) event-а.
>
> кто устанавливает event? В лупе первичного потока проверкой
> select наличие данных в буфере данных сокета одного из
> клиентов?

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

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

Можно чем угодно. Лишь бы не было race-а и не побились сами списки.

ЗЫ: Да, эту концепцию можно несколько расширить. Если по завершению операций необходимо выполнить еще какую то работу (в зависимости от того, как она была завершена, например за операций СЧИТЫВАНИЯ команды из сокета следует операция ВЫПОЛНЕНИЯ этой команды), то можно создать еще один список, но уже завершенных операций. А еще лучше в каждом задании на обработку завести поля для callback-а, который будет вызываться по завершению. В любом случае поллить (переопрашивать) статус (как тут было предложено) - не самый лучший выбор в многозадачных системах.
Это главное, что теперь мне ясно. Ясно, что надо обязательно... 06.11.05 19:54  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
>Потоков получится меньше чем
> сокетов, и все будет работать без задержек.
Это главное, что теперь мне ясно. Ясно, что надо обязательно разобраться с этим хотя бы в первом приближении.

Спасибо. Буду читать, побарывая свою дремучесть ;))
Самое главное — не держать клиента на сокете при обработке. 07.11.05 08:17  
Автор: HandleX <Александр М.> Статус: The Elderman
Отредактировано 07.11.05 08:34  Количество правок: 1
<"чистая" ссылка> <обсуждение закрыто>
Можно обойтись вообще всего 2-мя потоками. Или больше, к примеру 4-процовый сервер - 1 поток командный, остальные 3 исполнительные.
Клиент ставит запрос на исполнение. Сервер ставит его в исполнительную очередь.
Клиент получает или сразу ответ, или, если запрос не завершится за приемлемое время, получает код ошибки, типа "Подойдите попозже" -)

Клиент цепляется к сокету и шлёт туда типа "как там мой запрос". Сервер отвечает или данными, или кодом ошибки, может быть даже снова "Подойдите попозже". Закрывает сокет. В результате имеем и клиентов удовлетворёнными, и сетевой стек не в напряге.
Как сказать 07.11.05 18:37  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Клиент цепляется к сокету и шлёт туда типа "как там мой
> запрос". Сервер отвечает или данными, или кодом ошибки,
> может быть даже снова "Подойдите попозже". Закрывает
> сокет. В результате имеем и клиентов удовлетворёнными, и
> сетевой стек не в напряге.
Закрывать сокет наверно все таки не стоит. Потому что закрытие/открытие соединений самая ресурсоемкая процедура как для сервер, так и для клиента и всех маршрутизаторов между ними. Мало того файрволлы могут расценить это как атаку. Так что разрывать соединение стоит на действительно долгие сроки - например если запрос точно не выполниться в течении минуты.
Как сказать - это верно 08.11.05 18:34  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Закрывать сокет наверно все таки не стоит. Потому что
> закрытие/открытие соединений самая ресурсоемкая процедура

Сокет закрывать наверное не стоит, хотя будет зависеть от прикладного протокола.

> как для сервер, так и для клиента и всех маршрутизаторов
> между ними.

Вряд ли. Промежуточные маршрутиризаторы _почти_всегда_не_фильтруют трафик (что может относится к сокетам). Маршрутиризатоы работают с IP, но не транспортом.

> Мало того файрволлы могут расценить это как атаку.

Вряд ли. Только при большой частоте запросов, или в случае, когда сокет закрывается неверно, так что клиент продолжает пытаться послать данные на несуществующий на серверной стороне сокет (даже одного такоего пакета клиента будет достаточно, чтобы IDS запаниковал, или в лог пакетного фильтра было записано deny ,,, , если в access list было использовано - established ).
Режим клиент-ждет-в-офлайне следует предусмотреть для... 08.11.05 19:57  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Сокет закрывать наверное не стоит, хотя будет зависеть от
> прикладного протокола.
Режим клиент-ждет-в-офлайне следует предусмотреть для критичных ситуаций, когда сервер видит что клиентов - туча и еще прут.

> > как для сервер, так и для клиента и всех
> маршрутизаторов
> > между ними.
>
> Вряд ли. Промежуточные маршрутиризаторы
> _почти_всегда_не_фильтруют трафик (что может относится к
> сокетам). Маршрутиризатоы работают с IP, но не транспортом.
Не забывай про возможность наличия в промежутке всяких NAT, и прочей фигни типа соксов и хттп туннелей через которые может конектится юзер.
Инетересно, реализация TCP под виндами имеет ограничения на количество одновременно подключаемых клиентов? 08.11.05 07:09  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
> Закрывать сокет наверно все таки не стоит. Потому что
> закрытие/открытие соединений самая ресурсоемкая процедура
> как для сервер, так и для клиента и всех маршрутизаторов
> между ними.
Subj, и если да, то вот он — потолок для нашего сервера :-))

> Мало того файрволлы могут расценить это как атаку.
Какие чуствительные файры...

> Так что разрывать соединение стоит на действительно
> долгие сроки - например если запрос точно не выполниться в
> течении минуты.
Ну, я говорил выше, что закрывать стоит при невозможности выполнить запрос «за приемлемое время».

Склоняюсь к мысли, что Custom Hi-Performance Application Protocol надо ваять вообще на UDP ;)
В XP SP2 на одно приложение - меньше полтинника. Сделано для борьбы со злобными вирусами :) 08.11.05 08:15  
Автор: Fighter <Vladimir> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Это на исходящие, IMHO. На входящие, скорее всего, нету. Ну, т.е. сколько положено по стандарту -)) 08.11.05 13:32  
Автор: HandleX <Александр М.> Статус: The Elderman
<"чистая" ссылка> <обсуждение закрыто>
Где-то встречал, что макс колво соединений всёже рихтуется в... 08.11.05 18:38  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Где-то встречал, что макс колво соединений всёже рихтуется в реестре для TCP. Не помню. Но что-то такое точно есть. Могу сильно ошибаться. Если знаешь ты, писни в форум.
Спасибо.
Исходящих 08.11.05 19:53  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Рихтуется пул портов выделяемых для исходящих подключений. По дефолту их 4096. Учитывая что каждый клиентский сокет в нормальной ситуации еще 3 мин (тоже настраиваемо) держит порт в состоянии CLOSE WAIT это существенно. Но на входящие это вроде не распространяется.
Точно, на исходящие. На входящие - не помню, надо почитать умные книжки :) 08.11.05 17:33  
Автор: Fighter <Vladimir> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Кстати хорошая идея 07.11.05 18:17  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка> <обсуждение закрыто>
Ты прав. Я не допёр, что можно было запрашивать команду и её результат в два действия последовательно ;) Хорошая идея вне зависимости от особенностей архитектуры сервера, если сервер должен некоторое время готовить данные.
Спасибо.

> Можно обойтись вообще всего 2-мя потоками. Или больше, к
> примеру 4-процовый сервер - 1 поток командный, остальные 3
> исполнительные.
> Клиент ставит запрос на исполнение. Сервер ставит его в
> исполнительную очередь.
> Клиент получает или сразу ответ, или, если запрос не
> завершится за приемлемое время, получает код ошибки, типа
> "Подойдите попозже" -)
>
> Клиент цепляется к сокету и шлёт туда типа "как там мой
> запрос". Сервер отвечает или данными, или кодом ошибки,
> может быть даже снова "Подойдите попозже". Закрывает
> сокет. В результате имеем и клиентов удовлетворёнными, и
> сетевой стек не в напряге.
Сэмулируй многозадачность! :-)) 06.11.05 12:08  
Автор: HandleX <Александр М.> Статус: The Elderman
Отредактировано 06.11.05 12:56  Количество правок: 2
<"чистая" ссылка> <обсуждение закрыто>
> Транспорт - TCP. Мне сказали, что архитектура, когда сервер
> делается в первичном потоке на блокирующем прослушивающем
> сокете (Беркли интерфейс), и когда каждый клиент
> обслуживается в отдельном потоке - сакс. Было сказано, что
> такой софт никто не будет покупать... Было заявлено, что
> всё на самом деле можно сделать в одном потоке.
Сделать-то можно... Но зачем? -))
Ну да ладно. IMHO самое разумное, что можно предложить, дык это слушать всё-таки во столько потоков, сколько есть реальных исполнительных устройств для потоков, т.е. если сервер -- 2-х процовый Xeon with HT, юзать четыре потока, ну и так далее...

Вновь подключающемуся клиенту создавать контекст (сеанс), давать ему идентификатор сеанса, и вперёд — старыми добрыми средствами.

> Было сказано также, что Winsock Microsoft вообще тянет как
> устарелую технологию только ради поддержки старых
> приложений. Типа сейчас так уже не пишут. :cry:
Интересно, а как СЕЙЧАС пишут? Напрямую работают со стеком (TDI), что ли? -))

> Вот я и думаю... Как я отстал от жизни. Как же сделать так,
> чтобы всё работало без отдельных потоков для клиентов.
Ну... Тут бы я вообще не стал ни с кем спорить. Сделай два варианта сервера — один многопоточный, другой не очень -) Потести на производительность. Кто победит — тот и Д'Артаньян.

Мне самому больше нравится многозадачная модель. Если обслуживание клиента на блокирующем сокете затянется, то остальные со своими запросами будут становится в очередь сетевого стека, когда она заполнится, могут получить отлуп. Таймауты или ещё какая-нить хрень, завязанная на реализацию TCP/IP именно под виндами. При многопоточной модели реализация более "резиновая", но и более ресурcоёмкая. IMHO.

P.S.: Кстати, M$ SQL Server, яркий пример многопоточной службы, имеет два режима работы: на обычных потоках, и на т.н. "fibers", менее ресурсоёмких, чем "threads". Прикол в том, что приложение само заботится о переключении из нити в нить, виндовозный шедулер отдыхает. Можешь написать сервис с одним потоком - шедулером, но с такми кол-вом fibers, сколько тебе надо. Чисто китайский подход всех удивить :-)))
1  |  2 >>  »  




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 1 s   Design: Vadim Derkach