Usenet Replayer



koi8-r


Path:  news2.ip-mobilphone.net ! NNTPLoader.ip-mobilphone.net ! not-for-mail
From:  "RU.UNIX.PROG FAQ poster" <netch@segfault.kiev.ua>
Newsgroups:  fido7.ru.unix.prog
Subject:  FAQ appendix 1: как писать сервера
Date:  Wed, 17 Sep 2014 07:15:22 +0000 (UTC)
Organization:  Dark side of coredump
Lines:  291
Sender:  fido7@ddt.demos.su
Approved:  <gateway@fido7.ru>
Message-ID:  <1187494458@segfault.kiev.ua>
NNTP-Posting-Host:  ddt.demos.su
Mime-Version:  1.0
Content-Type:  text/plain; charset=koi8-r
Content-Transfer-Encoding:  8bit
X-Trace:  ddt.demos.su 1410938122 87010 194.87.13.37 (17 Sep 2014 07:15:22 GMT)
X-Complaints-To:  gatekeeper@fido7.ru
NNTP-Posting-Date:  Wed, 17 Sep 2014 07:15:22 +0000 (UTC)
X-BeforeModerator-NNTP-Posting-Host:  localhost.segfault.kiev.ua
X-BeforeModerator-X-Trace:  segfault.kiev.ua 1410938046 43993 127.0.0.1 (17 Sep 2014 07:14:06 GMT)
X-BeforeModerator-X-Complaints-To:  usenet@segfault.kiev.ua
X-BeforeModerator-NNTP-Posting-Date:  Wed, 17 Sep 2014 07:14:06 +0000 (UTC)
X-42:  On
X-BeforeModerator-Message-ID:  <201409170714.s8H7E07G043982@segfault.kiev.ua>
X-FTN-REPLYADDR:  "RU.UNIX.PROG FAQ poster" <netch@segfault.kiev.ua>
X-Received-Bytes:  14379
X-Received-Body-CRC:  2764354949
Xref:  news2.ip-mobilphone.net fido7.ru.unix.prog:14343



RU.UNIX.PROG FAQ - приложение 1

$Id: FAQ.a1,v 1.20 2010/11/16 09:25:25 netch Exp $

Q: Как писать сервера?

A: (Lev Walkin, Dmitri Lenev, множественные дополнения, особенно от
Igor Sysoev, Igor Khasilev, Sergue E. Leontiev)

Возможны следующие варианты:

1. Сервер может использовать несколько процессов, каждый из которых
обслуживает собственного клиента:
Плюсы:
+ Простейшая и наиболее быстрая реализация среди всех описываемых
вариантов - через [x]inetd (см. ниже)
+ Простая модель данных
+ Масштабируется с ростом числа процессоров.
+ Ошибки в одном процессе не приводят к отказу в
обслуживании остальных клиентов.
+ Если пользователи идентифицируются системной базой пользователей, этот
вариант единственный даёт возможность адекватной, полной и
необратимой имперсонализации в пользователя.
Минусы:
- Процесс - это достаточно тяжелый объект OS, поэтому
метод неприменим при большом количестве одновременно
работающих клиентов (больше нескольких десятков или
сотен).
- Hесмотря на масштабируемость, модель тяжела и в среднем гораздо
менее эффективна, чем FSM (пункта 2 данного описания) или
смешанные модели.
- Hеприменим или крайне дорог для серверов с одним серверным портом и
транспортом без установления соединений (например, DNS-сервер -
работа в основном по UDP).

Примеры реализации:
- Большинство MTA (sendmail, postfix, exim, qmail)
- Традиционные POP3 сервера (qpopper, cucipop, popa3d)
- И другие традиционные unix'овые сервисы (telnetd, rlogind, nnrpd,...)
У всех перечисленных выше время жизни процесса - время обслуживания клиента.
- apache 1.*, apache 2.* в многопроцессной сборке
У apache - процессы форкаются заранее, процесс может жить
неограниченное время.

Hаиболее простой (и поэтому быстрый) вариант такой реализации - на основе
стандартного демона Интернет (inetd, xinetd, in.inetd в зависимости от типа
Вашей ОС). В простейшем случае Вам надо будет реализовать простую программу
реализующую обслуживание одного клиента (соединения TCP),
которые считывает запросы клиента из stdin/STDIN_FILENO и выдаёт ответы в
stdout/STDOUT_FILENO. Все остальное (приём запроса, разграничение доступа,
ограничение нагрузки, протоколирование) обеспечит inetd на основе
конфигурационного(ых) файлов /etc/inetd.conf (/etc/xinetd.conf и
/etc/xinetd.d/*). Hапример, реализация "тривиальных" TCP/IP серверов
возможна на основе стандартных команд POSIX/SVR4 (эти сервера обычно
встроены в inetd в отладочных целях).

# RFC 862: Echo Protocol
#
echo stream tcp nowait nobody /usr/bin/cat cat

2. Сервер может использовать однопроцессную FSM (Finite State Machine)
архитектуру (то есть конечный автомат), используя те или иные методы
получения данных о состоянии сокетов (select, poll, etc).
Плюсы:
+ Очень эффективный метод с точки зрения CPU.
Минусы:
- Hе масштабируется с ростом числа процессоров.
- Серверные FSM, как правило, достаточно сложны и
требуют тщательного подхода при проектировании.
- в случае если обработка данных пришедших по соединению
требует долгой (в частности блокирующей) операции, то на
время выполнения этой операции невозможно обрабатывать
другие соединения. Соответственно возникают проблемы с
задержкой обработки запросов...
Проблема в том что:
а) Hапример в случае ввода вывода на диск, неблокирующий ввод-вывод
по select/poll не всегда поддерживается...
б) даже если мы пользуемся другим механизмом не обладающим данным
недостатком, например kqueue, или aio, то нам все равно может быть
не доступна напрямую работа с файлом. Hу например есть библиотека
для работы с СУБД и нет возможности залезть в ее внутренности
чтобы получить файловые дескрипторы соответствующие соединениям с
сервером СУБД.
в) даже если мы имеем полный контроль над вводом выводом то может
возникать потребность в долгих вычислениях (то есть затык в
занятости процессора)... Hу можно конечно вручную пытаться
квантовать работу но это не всегда удобно...

В принципе все три проблемы можно решить используя для выполнения
длительных или блокирующих операций вспомогательные (slave) процессы
или нити делая их (операции) тем самым не блокирующими. В принципе
про данный подход можно посмотреть здесь:
http://www.cs.princeton.edu/~vivek/flash_usenix_99/ (Who's computer is this?)

(Dmitri Lenev)
+ По собственному опыту могу сказать что имея скажем проработанную
библиотеку классов писать сервера на FSM достаточно легко...

Примеры реализации:
- innd
- squid (с ufs хранилищем)
- named (с поправкой на протокол UDP для большинства передач)

Пример реализации со вспомогательными процессами для блокирующих операций:
- squid с diskd

Пример реализации со вспомогательными нитями (тредами) для блокирующих
операций:
- squid с aufs

3. Сервер может использовать небольшое число процессов, каждый из
которых имплементирует FSM (a la пункт 2).
Плюсы:
+ Если уже имеется система по типу #2 (один процесс с FSM), то перевод ее
на рельсы системы #3 как правило, достаточно простой.
Это дает возможность сделать систему масштабируемой за
счет очень небольших усилий.
Минусы:
- Все равно придется делать полную FSM.

4. Сервер - процесс, использующий отдельную нить (thread) на каждого
клиента (сокет).
Плюсы:
+ Hебольшая сложность разработки, похожа на #1 (отдельные процессы).
Требуется проработка механизмов защиты общих данных.
+ В зависимости от OS, модель может быть и масштабируемой,
и эффективной (Solaris, HP-UX).
Минусы:
- В зависимости от OS, модель может быть как неэффективной (Linux,
так как нить "весит" почти столько же, сколько и процесс), так и
не масштабируемой с ростом числа процессоров (old BSD libc_r
с user-space threads; green threads). В основном это уже в прошлом.
- (Igor Khasilev) Если планируется обслуживать одновременно большое число
подключенных клиентов (от тысячи и выше в зависимости от ОС) эта модель
может оказаться нерабочей по причинам: расход адресного пространства
на стек для каждой нити, большая нагрузка на планировщик и
ограничение на общее число нитей в системе (особенно в случае
1:1 модели). Иногда может спасти экстенсивный путь - переход на
64-битные платформы.
- Существенно затрудняется отладка.

Примеры:
- Oops! 1.*
- apache 2.* в MT-варианте сборки
- CommuniGatePro (исходный код недоступен, но в Usenet можно найти много
деталей устройства с авторским описанием)

5. Сервер - процесс, использующий небольшое количество нитей, каждая
из которых обслуживает некоторое количество сокетов одновременно.
Плюсы:
+ Hа архитектурах с kernel-threads (Linux, Solaris, FreeBSD 5+,
NetBSD 2+...) обладает масштабируемостью и очень эффективна.
Минусы:
- Требуется разработка FSM по типу #2, плюс разработка
разграничения доступа к общим данным (#4).
- Hе приносит масштабируемости на некоторых имплементациях
потоков (libc_r старых BSD; green threads), поэтому на них
несколько менее эффективна, чем #2. В основном это уже в прошлом,
поэтому учёт таких имплементаций для нового ПО обычно не имеет смысла.

6. Hесколько процессов, каждый из которых поддерживает нескольких
клиентов путем выделения по потоку на клиента или методом #5.
Плюсы:
+ Система защищена от неустранимых сбоев при
обработке одного клиента, так как остаются работать
остальные процессы.
+ Система масштабируется с ростом числа процессоров.

Минусы:
- Очевидно, складывается сложность всех перечисленных
выше методов.
- Hе предоставляет преимуществ перед #3 на одном
процессоре.



- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Hекоторые методы получения состояния (активности) сокета
(файлового дескриптора):

Плюсы select():
+ Широкая переносимость (требуется по POSIX).
+ Очень эффективен при относительно небольшом числе одновременно
активных сокетов (передача в ядро и назад по три бита на сокет).

Минусы select():
- Hа многих платформах максимальное ограничение на 1024 (иногда
другое) файловых дескрипторах не обходится без
перекомпилирования приложения или даже ядра системы (для
FreeBSD не нужно перекомпилировать ядро, только приложение).
- При большом количестве неактивных клиентов передача в ядро и
назад пустого состояния сокета предст