Celé HTTP2 mi trochu připadá jako přesouvání problému z jednoho místa na jiné.
Začínáme s: TCP - flow control, congestion control, multiple streams. Máme podporu v OS pro všechny tyto věci, takže cílová aplikace (web server) se tím vůbec nemusí zabývat - může být napsána nějakým způsobem multi-threadovaně a vešekeré tyhle věci pak zařizuje OS.
Bohužel to má některé nevýhody - při použití TLS trochu vyšší latence při otevření spojení (+hlavičky, které se nevejdou do jednoho TCP paketu, takže ta latence je pak ještě o trochu vyšší zvláště na mobilních sítích). Takže to řešíme tím, že celý multiplexing přesuneme do user-space a implementujeme ho znova včetně flow-control. Web server v podstatě znova implementuje celou multiplexing logiku z OS včetně flow-control, celé se to příšerně zesložití... připadá mi to takové trochu zbytečné...
Tenhle přesun věcí z kernelu do userspace se děje i jinde. Třeba vlákna. Kernelové jsou obecnější, ale když se rozumně omezená funkcionalita implementuje i v userlandu, tak je najednou přepnutí vlákna nesrovnatelně levnější záležitost. Nebo třeba databáze si ve vlastní režii dělají spoustu záležitostí kolem diskové cache, protože takhle to jde vytunit přesně pro jejich způsob využití.
To, že něco podobného dělá systém je pěkné. Ale pro přenos více souborů není třeba navazovat více tcp spojení, vyjednávat pro každé šifrovací klíč atd. HTTP dělá něco jako systém, ale v daleko omezenější míře, díky čemu to taky dokáže dělat zatraceně efektivněji.
Myslím, že thready nejsou dobrý příklad, protože user-space thready jsou obecně pro aplikaci nerozlišitelné od native threadů.
Ano, databáze si řeší někdy diskové cache samy - ale nějak si nejsem jistý, jestli je tohle krok správným směrem. Připadá mi, že problém není obecně navázání TCP spojení, problém je spíše to TLS, kterému trvá asi o 2 pakety déle, než se to s existujícími session keys dohodne. Tady mě právě trochu překvapuje snaha překopat protokol ve světě, kde se rychlost linek obecně zvyšuje, takže bude hrát menší a menší roli. Připadá mi to, jako kdyby databáze komplet implementovala cachování disku v situaci, kdy by zrychlení bylo na úrovni 5%.
To zrychlení sice závisí na aplikaci, ale 5% je hodně pesimistický odhad. Co takhle 6x tolik uživatelů na server? http://www.neotys.com/blog/performance-of-spdy-enabled-web-servers/
Rychlost linek se sice zvyšuje, ale latence zůstává +- furt na jedno brdo. A to je ta hlavní brzda ve starém HTTP.
Vypadá to tak, ale problém je spíš s terminologií, která je podobná, ale znamená jiné kroky. Flow control v TCP/IP je velmi složité, musí řešit velikosti paketů, více cest, nezaručené pořadí ap. Flow control v HTTP/2 už má všechny výhody flow control z TCP/IP (aplikace je pořád může používat), takže je velmi primitivní (má jen okno; smyslem je třeba i to, aby server nepřecpal spojení daty streamu, který se klient snaží uzavřít). Multiplexing v TCP/IP slouží pro komunikaci s více počítači, což musí složitě řešit a řídit, opět s tím, že není zaručené téměř nic, tohle ale HTTP/2 opět už využívá a tak na jeho úrovni je to zase velmi primitivní (jen ID streamu). Ten rozdíl v rychlosti vytváření streamů v HTTP/2 a v TCP/IP je právě v tom, že TCP/IP musí znovu řešit spoustu věcí, které jsou ale pro spojení se stejným klientem (tedy při znovupoužití existujícího TCP spojení) už vyřešené.
může být napsána nějakým způsobem multi-threadovaně a vešekeré tyhle věci pak zařizuje OS
Takhle jednoduše to ale moc nefunguje, webový server má nějaké zdroje, které různé požadavky nějak sdílí, a k tomu potřebuje řídit přístup, aby předcházel starvation nebo třeba backlog overflow při přílišné serializaci (oboje lze použít i pro DoS útok). Ale pokud vám to tak jednoduché stačilo, tak v HTTP/2 to můžete mít úplně stejně, nijak nenutí server vyřizovat požadavky out-of-order, jen to umožňuje.
Flow control v TCP protokolu je prakticky identické flow control v HTTP 2.0 (nic víc než okno tam není). Congestion control už samozřejmě funguje jinak... a ten smysl je spíš v tom, že pokud by na jedné straně "thread" požírající určitý stream fungoval pomalu, tak by to zablokovalo komplet celou komunikaci.
Web server pro HTTP 1.1 se dá v jazycích, které podporují "levné" thready napsat velmi elegantně. HTTP/2.0 znamená v podstatě reimplementovat celý poll() interface znovu nebo to nějak simulovat přes nějaké fronty, což asi nebude zrovna efektivní. Nebo si udělat HTTP2 -- HTTP/1.1 gateway.... a nebo to skutečně vyřizovat in-order, ale to by byl krok zpět, protože web klienti to dneska posílají paralelně ve více TCP spojeních.
Připadá mi, že web servery obecně žádné řízení prostředků nad rámec "maximum najednou vyřizovaných požadavků" nečiní, protože by musely vědět, jak dlouho se který požadavek bude vyřizovat... pletu se?
Připadá mi to celé trošku jako nástavba, která se docela snadno implementuje na klientu, docela nepříjemně špatně na serveru (obzvláště v in-process web serverech) a výsledný efekt se projeví na pár špatně připojených zařízeních přes pomalé mobilní připojení.
Flow control v TCP protokolu je prakticky identické flow control v HTTP 2.0 (nic víc než okno tam není). Congestion control už samozřejmě funguje jinak...
Nemyslel jsem přímo flow control TCP, myslel jsem obecně celý systém řízení toku, které dělá TCP/IP. Kromě congestion control v TCP je to třeba MTU discovery nebo přesměrování mobilního spojení.
Web server pro HTTP 1.1 se dá v jazycích, které podporují "levné" thready napsat velmi elegantně. HTTP/2.0 znamená v podstatě reimplementovat celý poll() interface znovu nebo to nějak simulovat přes nějaké fronty, což asi nebude zrovna efektivní. Nebo si udělat HTTP2 -- HTTP/1.1 gateway.... a nebo to skutečně vyřizovat in-order, ale to by byl krok zpět, protože web klienti to dneska posílají paralelně ve více TCP spojeních.
Není pro tyhle jazyky spíš vhodnější (Fast)CGI? Webový server napsaný v takovém jazyku pravděpodobně nebude na frontendu a interně používat HTTP (libovolnou verzi) není zrovna rychlé.
Mimochodem napsat HTTP/1.1 server tak, aby se opravdu choval podle RFC (včetně všech dost šílených případů), rozhodně není nic elegantního.
Připadá mi, že web servery obecně žádné řízení prostředků nad rámec "maximum najednou vyřizovaných požadavků" nečiní, protože by musely vědět, jak dlouho se který požadavek bude vyřizovat... pletu se?
Tohle se řeší spíš frontou, kde se požadavky od jednoho klienta prokládají požadavky od jiných klientů.
No, je to pro "velké" servery. A ty moderní (nginx, lighttpd, ...) mají jen tolik threadů, kolik je jader. Takže jim většinou postačí přejít do režimu kdy jedno http/2 spojení (tedy jeden multiplex k uživateli) bude obsluhovat nejvýše jeden thread. Ona dobře napsaná eventová smyčka je u "překydávání obsahu" z paměti(*)/backendu směrem ke klientovi rychlejší (a hlavně méně hw náročná), než multithreading.
*) V ideálním světě i z disku, ale na to je potřeba asynchronní I/O, které funguje stejně jako pipes/sockets (neblokuje). Jinak si musíme pomáhat I/O thready.
U "malých" serverů často http/2 nepotřebujete, nebo můžete zařadit http/2 gateway (ostatně podobně se používá třeba SSL gateway) - v obou případech se hodí mít tam něco jako hloupé http/1.0. (bez Connection: keep-alive, a podobných výmyslů).
A teď si představte, že Google se rozhodl jít ještě dál a obešel nedostatky TCP spojení pomocí experimentálního protokolu QUIC, což je trochu upravené SPDY běžící po udp/443. Tam se zahodila rovnou celá transportní vrstva a veškerá logika se řeší v userspace. Uvidíme, co se z toho vyvine :)