В общи линии, Апача е по-мощен откъм функционалност и гъвкавост за настройка, следователно е по-добър и подходящ за general purposes. Но по-лош за голям и едновременен “напън” при неподходяща настройка.
Nginx-а е по-дървен, но по-бърз и подходящ за статичен контент, по-добре разпределя задачите си при голямо натоварване.
Апача е “швейцарско ножче”, Nginx e кирка, лопата или мотика.
“Швейцарско ножче” обаче, към което може много по-лесно да добавиш например лупа, огледалце, трионче… отколкото от кирката или мотиката да направиш… миксер.
Напълно могат да се заместват и допълват един друг, но вече въпросът е във взаимното допълване на предимствата и недостатъците на двата – за да се получи “добре изпилена и смазана система”.
Така че, няма отговор на въпроса: “кой е по-добър”.
По-добър, за какво?
Истината е в допълването, в заедността.
Погледнато от историческа гледна точка, Апача (1995) е по-стар от Nginx-a, (2002). Какво е бил Интернет в 1995, в сравнение с 2002 г.? Реторичен въпрос, нали? Или какво е сега, в сравнение с 2002г.?
Апача генерално не е правен за голям “напън”, не че не държи на голям напън при правилна настройка, просто Nginx-a е правен първо с тази идея, и поне за това е по-добър. Подчертавам на ПОНЕ.
Nginx е създаден за да реши т.н. “C10k problem”, което може да се представи нагледно със следната ситуация:
Лелка на гише, например в банка или в някаква институция.
Изсипват и се едновремнно N на брой клиенти, тя се шашва и казва: “О не, не мога да ви оправя всички наведнъж, я се наредете един след друг, така наведнъж не мога да ви обслужа.” Подчертавам на “ЕДИН СЛЕД ДРУГ”.
Connection Handling Architecture
MPM, демек Multi Processing Module – демек, текущо зареденият модул на Апача, който отговяря за разпределянето на задачите (that dictate how client requests are handled).
Биват три: mpm_prefork, mpm_worker и mpm_event
За да разберем разликите между тях, трябва първо и задължително, да разберем разликите межд process и thread.
Представям си го нагледно и практично така:
Процесът е по-общото, тредът е процес, разделен на части.
Все едно процесът е фирма с шеф, който събира служителите и им казва “Трябва да се свърши едикакво си”. Иване – ти поеми това, Петре – ти свърши онова, Мария – ти ще отговаряш за това… Имате фирмените ресурси, които ви трябват – баничарката, принтера и ксерокса, някой лев за командировъчни…”
Това са т.н. “споделени ресурси”. Тредовете-служители могат да ги ползват, стига да не си пречат и застъпват, защото те (ресурсите) са на ниво – процес-фирма.
Вътре в процеса-фирма, всички ресурси са споделени между ресурсите-тредове. Нали шефът е един все пак. Но между отделните процеси-фирми – не.
Не може “Дезинфекционна станция Трепем гад всякаква” ООД и неговете служители-тредове, да ползват баничарката или ксерокса на “Топли мекици” ООД.
mpm_prefork – един рекуест – един процес – един тред.
Рекуестът нека е клиент на фирма. Процесът нека е шефът на фирмата. Тредът нека е служителят (служителите). А над шефовете (процесите) и техните тредове (служители) бди неотклонно core-то (ядрото) на Апача.
Идва рекуест (демек клиент) при Коре-то и иска да му се свърши някаква работа. Коре-то му създава фирма (демек шеф), която да му свърши работата, и тази фирма (шеф) ще има ЕДИН тред (служител), който реално ще свърши работата. Демек – един рекуест – един процес – един тред.
Един клиент – една фирма(шеф) – с един служител.
Който служител ще има всички ресурси на фирмата, няма да се чака и занимава с колеги-идиоти, няма “дай баничарката, че ми трябва”, няма “Мише, кога ще ми издадеш едикойси документ”… Това, че е сам служител на шефа си, не значи, че не може да ползва всички ресурси на фирмата, без да се съобразява с колегите си. И не значи, че няма да свърши работата даже по-бързо от ако бяха много колеги (тредове) и работата не беше разпределна между тях.
Лошото е ,че не се оплътняват ресурсите много добре. Демек, шефът дава целите ресурси на фирмата на единственият си служител-тред, което не значи, че този служител-тред ще скатава или краде от бензина на баничарката. Идеята е ,че фирмата-процесът като си има запазени ресурси, те остават блокирани само за тази фирма, и са недостъпни за останалите фирми, дори и да са свободни. Демек, фирмената баничарка, фирмената секретарка… са си само за дадената фирма. Ако друга фирма и трябва баничарка или секретарка – да си купи (запази в паметта) своя.
Обаче когато рекуестите станат повече от процесите, производителнността спада рязко. Не знам защо, явно просто няма процес, който да обработи новопостъпилият рекуест? И к’о прай’м? Сядаме и чекаме? Демек, Коре-то казва на клиента “Нема свободна фирма да Ви свърши работата, е па че почекате”.
Затова mpm_prefork е сигурен откъм споделени ресурси (колегите-тредове) няма да се чакат и бъркат един друг за ресурси, но пък е неефективен при “напън” от рекуести-клиенти.
Докато има процеси (шефове) колкото за всеки рекуест (клиенти) – всичко е ОК. И понеже имаме “един процес – един тред” – значи това е модулът, подходящ за “non thread safe” PHP – понеже процесите си имат запазена, своя памет, няма как да се оплетат тредовете. Нали е един тред само в процеса.
mpm_worker – Тук пак като дойде клиент-рекуест, core-то вместо да създава отделна фирма с един служител, както при mpm_prefork (и по този начин да гарантира, че отделните служители-тредове няма да се чакат и пречат), създава един процес-фирма с много тредове-служители, на които се дава даден рекуест-клиент, и той (служител-треда) си го движи. Колко фирми-процеса и всяка с по колко треда-служителя във всяка ще има – не знам.
Но тук със сигурност има доста по-голямо уплътняване на общият ресурс.
Нека осъзнаем, че както и в живота, процесите-фирми само управляват тредовете-служители, работата се върши от тредовете-служители. Демек, колкото повече процеси-фирми – толкова “повече вожд, малко индианец”. Е да, разделението и сигурността откъм оплитане на ресурси е по-голяма, вярно.
mpm_event – този модул е същият като mpm_worker но се различава по начина, по който обработва keep-alive рекеуест-клиентите. Тоест: mpm_worker ще държи тред-служителя, докато keep-alive е в сила, дори и работата да е свършена. mpm_event отделя служител-тредовете за активните клиент-рекуести отделно от тези за keep-alive. The event MPM handles keep alive connections by setting aside dedicated threads for handling keep alive connections and passing active requests off to other threads. Идеята е явно, да не се задръсти сървъра с “Чакай да се наканя…” клиенти.
Както се вижда, Апача е доста по-гъвкав откъм това, какъв начин на обслужване на заявките генерално ще изберете.
Distributed vs Centralized Configuration
Nginx does not interpret .htaccess files, nor does it provide any mechanism for evaluating per-directory configuration outside of the main configuration file. This may be less flexible than the Apache model, but it does have its own advantages.
Apache има възможност за настройки на ниво директория (per directory basis) с помощта на .htaccess
Nginx – не.
Nginx печели производителност, защото не трябва да отваря, чете, обработва и т.н… този .htaccess файл за всеки рекуест, както Apache, но пък губи гъвкавост. Също имай предвид, че Apache прави това “отваряне, четене, обработване…” става по целия път от корена – до даденият ресурс (файл), и застъпващите се директиви се override-ват… и изобщо…
При Nginx като стартираш с дадени настройки – това е, каквото си настроил – настроил, газ на педалите.
Е да, в Апача може да изключиш .htaccess и би трябвало горните грижи и тревоги да отпаднат, не знам, предполагам…
Modules
При Апача, имаш ядро и модули, и можеш динамично, само с един рестарт да ги активираш/деактивираш.
При Nginx пак имаш разни модули, но трябва да компилираш. In Nginx, modules are not dynamically loadable, so they must be selected and compiled into the core software.
File vs URI-Based Interpretation
Или с други думи, като как двата сърва интерпретират заявените URI ресурси и ги мапват към съответните ресурси (най-често – филета).
По подразбиране, и двата сърва приемат заявените ресурси като ресурси на файловата система. Вземат домейна, заметват го с document root-a, и от там нататък – следва пътя до ресурса.
Апача може и по двата начина – демек, може да интерпретира заявените ресурси и буквално като филета или директории,
или като “псевдоними” на реални филета и директории.
Има разни механизми, дали ще е с RewriteRules или с директиви в htconfig – a…
Nginx-a може само по един начин – като интерпретира URI-то като път до ресурса на файловата система.
Static vs Dynamic Content
Апача обработва ПХП като
- или ПХП-то му е инсталирано като модул (т.н. “dynamically loadable modules”), да си припомним все пак, че Апача по принцип е набор, или по-грубо казано – “купчина” от модули, обединени от ярдо.
- или като вика външен интерпретатор (интерпретатора на ПХП).
Това като цяло явно е с идеята да може като интерпретатор да се ползва не само ПХП но и други езици. Да е по-модулно.
Nginx-a няма подобен механизъм за “външно обработване” на скриптове. Там трябва да се настрои комуникация между Nginx-а и скрипта, като се използва някакъв протокол (http, FastCGI, SCGI, uWSGI, memcache).
И тук идва допълнителното усложнение – излиза, че всеки рекуест за ПХП страница води до допълнителен “вътрешен” рекуест от Nginx-a – към ПХП-то.
Конфигурацията изглежда горе – долу така:
location / {
fastcgi_pass localhost:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
}
Е да, вярно, този сценарий ще се случи само за динамичен контент. Освен ако под горните редове, ще добавим и тези:
location ~ \.(gif|jpg|png)$ {
root /data/images;
}
с които ще кажем на Nginx-a да минава през ПХП-то за всичко, без gif, jpg и png