Olej писал(а):В любом случае, имеем в итоге 7 принципиально разных схем для построения серверов массового обслуживания.
И результаты тестирования их латентности...
Сервера ретранслируют полученный запрос от клиента, после чего тут же закрывают соединение (так как поступает HTTP сервер).
Клиент фиксирует время задержки ответа.
Вот как это делает простой последовательный сервер:
Код: Выделить всё
[olej@notebook xservers]$ ./ech0
waiting on port 51000 ...
********************^C
[olej@notebook xservers]$ ./cli -p51000 -n20
TCP port = 51000, number of echoes = 20
time of reply - Cycles [usec.] :
318460[28661686] 213290[19196291] 201110[18100081] 233470[21012510] 244430[21998919]
201360[18122581] 243220[21890018] 326750[29407794] 215910[19432094] 287910[25912159]
211400[19026190] 359160[32324723] 233650[21028710] 198970[17907479] 206120[18550985]
218420[19657996] 293030[26372963] 221150[19903699] 198940[17904779] 206100[18549185]
А вот параллельный сервер блокированный на fork() (это классика - так работал Apache до версии 1.3 и работают все примеры для студентов):
Код: Выделить всё
[olej@notebook xservers]$ ./ech1
waiting on port 51001 ...
********************^C
[olej@notebook xservers]$ ./cli -p51001 -n20
TCP port = 51001, number of echoes = 20
time of reply - Cycles [usec.] :
595450[53591035] 629270[56634866] 715770[64419944] 679180[61126811] 653250[58793087]
643840[57946179] 632300[56907569] 280910[25282152] 576450[51881018] 653550[58820088]
620080[55807758] 696840[62716227] 696120[62651426] 656340[59071190] 662720[59645396]
660530[59448294] 1414580[127313473] 627310[56458464] 709540[63859238] 727710[65494554]
- задержка ответа вдвое больше чем у последовательного сервера, что естественно и понятно...
То же самое, но в работу fork() добавлен большой блок не инициализированных данных - показывает, что Copy On Write в Linux работает успешно:
Код: Выделить всё
[olej@notebook xservers]$ ./ech10
waiting on port 51002 ...
********************^C
[olej@notebook xservers]$ ./cli -p51002 -n20
TCP port = 51002, number of echoes = 20
time of reply - Cycles [usec.] :
265470[23892538] 644100[57969579] 626790[56411664] 1402360[126213662] 664800[59832598]
684810[61633516] 691680[62251822] 654220[58880388] 643030[57873278] 1349080[121418414]
594810[53533435] 625440[56290162] 609850[54887048] 536000[48240482] 306850[27616776]
699890[62990729] 607250[54653046] 611850[55067050] 591130[53202232] 638790[57491674]
Вот более редкая схема с pre-fork (fork() делается раньше, а блокирование потом производится на accept() - это нарушение правил, но это работает!)
Код: Выделить всё
[olej@notebook xservers]$ ./ech11
waiting on port 51003 ...
21021021021021021021^C
[olej@notebook xservers]$ ./cli -p51003 -n20
TCP port = 51003, number of echoes = 20
time of reply - Cycles [usec.] :
264890[23840338] 242110[21790117] 224740[20226802] 197670[17790477] 205860[18527585]
253670[22830528] 249320[22439024] 233310[20998109] 232180[20896408] 334040[30063900]
244620[22016020] 333940[30054900] 244620[22016020] 348460[31361713] 208530[18767887]
246230[22160921] 208680[18781387] 301630[27146971] 210000[18900189] 245390[22085320]
Реакция улучшена вдвое.
Вот ещё fork(), но косвенный: через суперсервер xinetd:
Код: Выделить всё
[olej@notebook xservers]$ ./cli -p51004 -n20
TCP port = 51004, number of echoes = 20
time of reply - Cycles [usec.] :
201372410[18123698136] 4631510[416840068] 6579840[592191521] 6685010[601656916] 6661510[599541895]
6611890[595076050] 6516470[586488164] 6669190[600233102] 6579970[592203222] 6344620[571021510]
6593150[593389433] 3761070[338499684] 6129520[551662316] 6586000[592745927] 6108540[549774097]
6098120[548836288] 6450080[580513005] 6042590[543838538] 6017040[541539015] 6184580[556617766]
Время хуже практически на порядок... Но не всем же нужна максимальная скорострельность? Зато какая простота кода!
Это параллельный сервер на потоках (нынешний Apache):
Код: Выделить всё
[olej@notebook xservers]$ ./ech2
waiting on port 51005 ...
********************^C
[olej@notebook xservers]$ ./cli -p51005 -n20
TCP port = 51005, number of echoes = 20
time of reply - Cycles [usec.] :
438550[39469894] 309340[27840878] 363090[32678426] 382170[34395643] 350030[31503015]
468220[42140221] 155430[13988839] 152060[13685536] 149410[13447034] 395890[35630456]
331570[29841598] 361000[32490324] 351430[31629016] 334230[30081000] 365590[32903429]
336360[30272702] 326130[29351993] 337690[30392403] 146510[13186031] 151240[13611736]
Время реакции вдвое лучше fork().
И предварительное создание потоков на манер pre-fork:
Код: Выделить всё
[olej@notebook xservers]$ ./ech22
waiting on port 51007 ...
30745137763066121072305772836830493356643040942960303255025630241575523015764848300737214429989794402990586736298219403229738013282965408624295701592029486232162940230512293183780829234451042915052400^C
[olej@notebook xservers]$ ./cli -p51007 -n20
TCP port = 51007, number of echoes = 20
time of reply - Cycles [usec.] :
248970[22407524] 283830[25544955] 299590[26963369] 401910[36172261] 219300[19737197]
229580[20662406] 326110[29350193] 147100[13239132] 249900[22491224] 143920[12952929]
233460[21011610] 147610[13285032] 147370[13263432] 325290[29276392] 331850[29866798]
154990[13949239] 154650[13918639] 322830[29054990] 321390[28925389] 369800[33282332]
Ещё лучше ... но чтобы зафиксировать это "лучше" сервера уже нужно запускать как приложения realtime-приоритета.