Je to škoda. Myslím si, že se tomu dalo málo času, aby se to usadilo – byla to úplně nová technologie, kterou není tak snadné implementovat. Aby to dávalo smysl, musejí se informace z buildu a případně z redakčního systému protlačit až do webového serveru. Je pochopitelné, že něco takového se nebude hned všude používat, vždyť ani samotné HTTP/2 ještě není zdaleka všude.
Není tak docela pravda, že to nebralo v úvahu klientovu cache. Server soubor nabídl a hned jej mohl začít posílat, nicméně klient měl možnost posílání souboru kdykoli odmítnout. Což přesně odpovídá realitě – server ví, co může klient potřebovat a co mu může poslat, klient k tomu může maximálně doplnit informaci „tohle nepotřebuju, to už mám“.
Google se tohle rozhodování pořád snaží tlačit do prohlížeče, že prohlížeč ví nejlépe, co bude potřebovat. Jenže za jednak to prohlížeč neví, jenom to hádá, případně s nápovědou od serveru. A hlavně prohlížeč neví, co má server k dispozici – dává smysl začít posílat třeba obrázek, který má nižší prioritu, ale server už ho má, než čekat na skript, který má pro prohlížeč vyšší prioritu, ale server ho třeba ještě nemá k dispozici, protože se teprve generuje.
krátce, push prostě nikdy dobře nefungoval, rel="preload" a multiplexing ho nahrazují daleko lépe a prohlížeč pak opravdu ví, co chce lépe než server.
Není pravda, že server soubor nenabízí, jen oznámí jeho poslání přes PUSH_PROMISE a poté začne v dalším framu data posílat. Prohlížeč data příjme a drží si je v odděleném uložišti než rozhodne co s nimi. Tak funguje aktuální implementace v třeba Chromu. Problém je, že soubor se neposílá se všemi hlavičkami, takže ty různé varianty if-modified hlaviček nemusí správně sepnout a cache se přemaže. Data se ale pošlou bez ohledu na cache v prohlížeči.
Kromě zmíněných problémů je třeba ještě problém se SPA a offline aplikacemi, kdy server při posílání obsahu neví, jakou verzi aplikace má klient a může dojít k nekonzistenci aplikace.
Další problém je, že server neví, na jak rychlé lince je prohlížeč a při posílání velkých dat (nebo posílání malých dat ale hodně klientům na stejné lince) dochází k zahlcení linky na straně prohlížeče. Za normálních okolností si tohle prohlížeč řídí sám, tady je ale jako rukojmí. Implementovali jsme to u jednoho z našich mobilních operátorů, takže testovací vzorek byl značný.
Na straně serverů a hlavně load balancerů je pak problém s throttlingem nebo rate limitem, v podstatě žádný velký vendor (AWS, cloudflare, Azure, F5 atd.) neposkytuje plně funkční load balancer pro Push, jsme rádi, když jakžtakž to funguje pro samotné HTTP/2. Potenciál k DoS útokům je pak obrovský.
Ale při použití HTTP PUSH má klient také možnost to nechtít. Klient má kdykoli možnost pomocí RST_STREAM kterýkoli stream odmítnout. Takže přinejhorším, když se ta komunikace úplně nepodaří, pošle rychlý server navíc pár paketů, než se klientovi podaří ten stream odmítnout.
Samozřejmě pokud je to v prohlížeči implementované špatně a prohlížeč neodmítá streamy, které nechce, nebude to fungovat dobře. Pak by ale dávalo smysl implementaci opravit, ne to úplně zaříznout.
Těch pár bajtů někomu vadí? Pokud by to vadilo, nebyl by problém serveru signalizovat, jak dlouho má čekat, než po nabídnutí souborů začne data opravdu posílat. Kdyby tedy někdo opravdu potřeboval zařídit, aby nepřišel ani bajt nazmar.
To je hezká teorie, že má vždy prohlížeč rozhodovat, co se má stahovat. Problém je, že prohlížeč neví, která data má server k dispozici.
Situace, kdy je serverem nabídnuto stažení dalších kusů stránky, mi přijde mnohem lepší.
Tak to ovšem fungovalo s HTTP PUSH, což je technologie, která se ruší. Místo toho se zavádí nová technologie, že server nic nenabízí, jenom pošle klientovi seznam všeho, co by možná mohl potřebovat. Klient si něco z toho vybere a pošle serveru požadavek třeba na pět souborů. A co čert nechtěl, server ty soubory zrovna nebude mít k dispozici, tak na ně bude čekat. A prohlížeč také bude čekat. Server by mezi tím mohl posílat něco jiného, ale to klient nechce. Takže se bude čekat, a až soubory konečně budou k dispozici, server je pošle – a pak si klient konečně požádá o ty soubory, které mu server mohl poslat už dávno.
Nebo-li kritické soubory dostane prohlížeč ve stejném okamžiku, jako by je dostal se server PUSH, ale zbytek souborů dostane později o to, co se čekalo na ty kritické soubory. Takže k vykreslení kompletní stránky dojde později. A to se vyplatí.
> Těch pár bajtů někomu vadí?
Nejsem si jist, jak to dopadne na špatném připojení, když se ztrácí zpráva od prohlížeče, že k ten soubor nestojí.
> Pokud by to vadilo, nebyl by problém serveru signalizovat, jak dlouho má čekat, než po nabídnutí souborů začne data opravdu posílat.
Pak ale nevidím moc výhody oproti Prefetch.
> Problém je, že prohlížeč neví, která data má server k dispozici.
Nerozumím. Když prohlížeč dostane Prefetch, může důvodně předpokládat, že ten soubor je j dispozici a zároveň se bude hodit.
> A co čert nechtěl, server ty soubory zrovna nebude mít k dispozici, tak na ně bude čekat. A prohlížeč také bude čekat. Server by mezi tím mohl posílat něco jiného, ale to klient nechce. Takže se bude čekat, a až soubory konečně budou k dispozici, server je pošle – a pak si klient konečně požádá o ty soubory, které mu server mohl poslat už dávno.
Jak se za běžných okolností stane, se tyto soubory nebudou k dispozici? Proč by to mělo blokovat klienta, když HTTP/2 umí multiplexing?
Nejsem si jist, jak to dopadne na špatném připojení, když se ztrácí zpráva od prohlížeče, že k ten soubor nestojí.
Pořád se to děje nad spojením, které garantuje doručení zprávy – HTTP/2 na TCP, HTTP/3 na QUIC.
Pak ale nevidím moc výhody oproti Prefetch.
Na rychlém spojení prohlížeč může signalizovat, ať server začne posílat hned. Ta signalizace by byla součástí hlaviček prvotního dotazu, takže by tam nebyla žádná latence. A výhoda oproti Prefetch? Pořád stejná – server na rozdíl od klienta může vědět, která data má k dispozici a co tudíž může začít posílat.
Nerozumím. Když prohlížeč dostane Prefetch, může důvodně předpokládat, že ten soubor je j dispozici a zároveň se bude hodit.
To je ale chybný předpoklad. Ten soubor k dispozici být nemusí. Jenže server nemá možnost, jak dát prohlížeči vědět, že už k dispozici je. Tu možnost měl s HTTP PUSH.
Jak se za běžných okolností stane, se tyto soubory nebudou k dispozici? Proč by to mělo blokovat klienta, když HTTP/2 umí multiplexing?
Představte si redakční systém, třeba jako je tady na Rootu. Myslím, že je to docela častý případ webu.
Prohlížeč pošle požadavek na titulní stránku na server, na což server zareaguje tím, že pošle dotaz do databáze, jaké jsou aktuálně články na titulní stránce, zprávičky, počty komentářů atd. Vyřízení těch dotazů v DB nějakou dobu trvá. Mezi tím může prohlížeči posílat styly, skripty, designové obrázky – protože to všechno jsou statické soubory a server na ně nemusí čekat. Může mu dokonce začít posílat ilustrační obrázky k článkům, protože ví, že dneska jsou na titulní stránce zobrazené tyhle obrázky. To všechno jsou soubory, které mají nižší prioritu, než HTML – ale když se nedá posílat HTML, dává smysl posílat tyhle soubory.
Můžete namítnout, že když prohlížeč čeká na HTML, o další soubory, které dostal v hlavičkách Prefetche, si řekne. No, jednak záleží na implementaci – když prohlížeč nevěděl při HTTP PUSH, jestli ten soubor chce nebo ne, stejně tak to nemusí vědět i při použití Prefetch. Ale hlavně, ten soubor, který se generuje a na který se čeká, nemusí být HTML. Může to být JavaScript – třeba u SSG, které teď (znovu) získává na popularitě.
Klienta to bude blokovat proto, protože klient nepošle požadavky na všechny soubory najednou. Klient se bude snažit prioritizovat ty soubory, které považuje za důležitější. proto se přece ta logika do klienta přenáší, aby si to mohl řídit sám. Kdyby prohlížeč na Prefetch reagoval tím, že odpálí salvu požadavků na všechny soubory v Prefetchi a nechal na serveru, ať mu je posílá v pořadí, jaké vyhovuje serveru, bylo by to přece úplně stejné, jako HTTP PUSH (co se pošle určuje server), akorát by tam byl přidaný jeden roundtrip (a ušetří se roundtrip na odmítnutí nepotřebného souboru).
Mimochodem, i to, že server posílá prohlížeči přes HTTP PUSH soubory, které klient nepotřebuje, protože je má nakešované, se dá řešit hned, tj. bez toho odmítnutí prohlížečem. Prohlížeč totiž posílá podmiňující hlavičky hned s prvním požadavkem, takže server umí rozlišit, jestli prohlížeč na tu stránku přichází poprvé a nejspíš nemá nakešováno nic, nebo jestli se vrací a tudíž už nejspíš má něco nakešované. Dokonce by podle těch hlaviček uměl určit i to, kdy stránku viděl naposledy a tedy které soubory může použít z cache a které mu má rovnou začít tlačit.
> Pořád se to děje nad spojením, které garantuje doručení zprávy – HTTP/2 na TCP, HTTP/3 na QUIC.
Ano. On se ten požadavek na zrušení k serveru někdy dostane. Mezitím ale může server naposílat hromadu paketů klientovi. Nemám to rozmyšlené do detailu a nevím, jak moc je takový scénář na špatném spojení pravděpodobný.
> Na rychlém spojení prohlížeč může signalizovat, ať server začne posílat hned.
+ neměřeném, ať neplýtváme FUP.
> Ten soubor k dispozici být nemusí. Jenže server nemá možnost, jak dát prohlížeči vědět, že už k dispozici je.
No, pokud tím myslíte, že naservírování toho souboru je spojeno s vyšší latencí (třeba kvůli DB), tak v tom nevidím problém. Klient pošle požadavek a bude čekat, aniž by to blokovalo spojení.
> Prohlížeč pošle požadavek na titulní stránku na server, na což server zareaguje tím, že pošle dotaz do databáze, jaké jsou aktuálně články na titulní stránce, zprávičky, počty komentářů atd.
Nevím, jestli titulní stránka je ideální příklad. Když řešíme optimalizace, tak titulní stránka bude nacacheovaná. Ale v principu ano, podobný scénář by mohl nastat, když by někdo dostal odkaz na článek na serveru, který ještě nenavštívil. Tam nemusí být tak agresivní cacheování, zvlášť jde-li o starší článek. Takže ano, v některých případech to bude relevantní.
> Můžete namítnout, že když prohlížeč čeká na HTML, o další soubory, které dostal v hlavičkách Prefetche, si řekne.
To by bylo problematické. Typicky v této chvíli server ještě neví ani stavový kód (možná čtení z DB failne a server hodí 500). A možná ani neví všechny hlavičky. Na HTTP/1.1 by šlo poslat částečnou odpověď, když bychom se vykašlali na 500 a optimisticky poslali 200 (ano, není ideální), na HTTP/2 nevím.
> když prohlížeč nevěděl při HTTP PUSH, jestli ten soubor chce nebo ne, stejně tak to nemusí vědět i při použití Prefetch.
V obou případech se může rozhodnout celkem jednoduše – nemá-li v cache, pošle požadavek. Ano, nikde není záruka, že ten soubor bude využit (ostatně pokud failne přístup do DB a server hodí 500, je docela šance, že některé soubory prohlížeč načte zbytečně), ale když už se s tím někdo optimalizuje, lze IMHO předpokládat, že ví, co dělá.
> Ale hlavně, ten soubor, který se generuje a na který se čeká, nemusí být HTML. Může to být JavaScript – třeba u SSG, které teď (znovu) získává na popularitě.
IIRC tu byla nějaká možnost prefetche i přes HTTP hlavičku.
> Kdyby prohlížeč na Prefetch reagoval tím, že odpálí salvu požadavků na všechny soubory v Prefetchi a nechal na serveru, ať mu je posílá v pořadí, jaké vyhovuje serveru, bylo by to přece úplně stejné, jako HTTP PUSH (co se pošle určuje server), akorát by tam byl přidaný jeden roundtrip (a ušetří se roundtrip na odmítnutí nepotřebného souboru).
Před chvílí jste navhroval přidat na serveru latenci v době jednoho round-tripu, aby se neposílala zbytečná data. Potom by HTTP PUSH round-trip neušetřilo, ledaže by klient požádal o nulovou latenci.
> Prohlížeč totiž posílá podmiňující hlavičky hned s prvním požadavkem, takže server umí rozlišit, jestli prohlížeč na tu stránku přichází poprvé a nejspíš nemá nakešováno nic, nebo jestli se vrací a tudíž už nejspíš má něco nakešované. Dokonce by podle těch hlaviček uměl určit i to, kdy stránku viděl naposledy a tedy které soubory může použít z cache a které mu má rovnou začít tlačit.
OK, fair point.
On se ten požadavek na zrušení k serveru někdy dostane. Mezitím ale může server naposílat hromadu paketů klientovi.
Objem dat zaslaných navíc je omezen oknem TCP spojení. Klient musí potvrzovat serveru přijaté požadavky, a protože klient asi nebude mít nic důležitějšího, co by posílal serveru, dostane se požadavek klienta na přerušení streamu na server nejpozději s dalším potvrzovacím paketem.
No, pokud tím myslíte, že naservírování toho souboru je spojeno s vyšší latencí (třeba kvůli DB), tak v tom nevidím problém. Klient pošle požadavek a bude čekat, aniž by to blokovalo spojení.
Takhle by to fungovalo jedině v případě, kdy by se klient nepokoušel řídit, které soubory chce prioritně. Jenže klient se to řídit pokouší (přestože k tomu má méně informací, než server). Takže klient nepošle požadavky na všechny soubory, o kterých ví, že je bude potřebovat. Klient má frontu souborů, které stahuje najednou, a do té fronty cpe soubory od nejprioritnějšího po nejméně prioritní. Takže spojení se blokuje tím, že klient čeká na soubory, které mu v danou chvíli server nemůže poslat, a to čekání nevyužívá k tomu, aby stahoval jiné soubory - protože ty čekají, až se stáhnou ty prioritnější soubory.
Nevím, jestli titulní stránka je ideální příklad. Když řešíme optimalizace, tak titulní stránka bude nacacheovaná. Titulní stránka tady na Rootu obsahuje výpis diskuí, obsahuje počet komentářů a počet nepřečtených komentářů ke každému článku a zprávičce. Nemůže být na klientovi nakešovaná.
To by bylo problematické. Typicky v této chvíli server ještě neví ani stavový kód
Na tom není nic problematického. Pokud klient nakonec dostane nějakou 4xx nebo 5xx chybu, stejně neuvidí, to co vidět chtěl - takže je jedno, že k té stránce nebude mít v cache zdroje a její zobrazení bude trvat déle. Navíc chybové stránky obvykle nemívají moc závislostí. A že se do cache dostaly soubory, které pro tu zobrazenou chybovou stránku nejsou potřeba? Nevadí, použijí se, až se chyba opraví a uživateli se zobrazí ta správná stránka.
IIRC tu byla nějaká možnost prefetche i přes HTTP hlavičku.
Ano, ale o to nejde. Jde o to, že prohlížeče implementují strategii "čekám na HTML, tak můžu stahovat něco jiného", ale už nemají podobnou strategii pro jiné typy souborů. Když bude prohlížeč čekat na stažení CSS nebo JS, nezvětší počet stahovaných souborů, aby mezi tím mohl stahovat nějaký obrázek.
Před chvílí jste navhroval přidat na serveru latenci v době jednoho round-tripu, aby se neposílala zbytečná data. Potom by HTTP PUSH round-trip neušetřilo, ledaže by klient požádal o nulovou latenci.
Ano, klient by mohl podle připojení požádat o takovou latenci, která mu vyhovuje. Na rychlém připojení by si vyžádal nulovou latenci, na pomalém by si dal nějakou rezervu na odmítnutí.
Pořád platí to, že klient se rozhoduje na základě: 1. informací od serveru, co bude potřebovat, 2. algoritmu, co je důležitější, 3. stavu cache, 4. podmínek prostředí (media queries apod.) Informaci 1 server má, vždyť to prohlížeči posílá on. Algoritmus 2 může server implementovat stejně, jako klient, ale navíc může mít server reálné informace o dané webové stránce, jaké jsou tam reálné priority - takže tady má server mnohem lepší informace, než klient. 3 server neví jistě, co má klient v cache, ale může to docela dobře odhadovat podle prvního požadavku. 4 to je jediná věc, na kterou server snadno nedosáhne. Částečně je to řešitelné hlavičkami požadavku (třeba podporované typy médií), řešit takhle responzivní obrázky by bylo příliš komplikované. Ale responzivní obrázky jsou jenom jeden z mnoha zdrojů, navíc obvykle nejsou tou nejkritičtější částí stránky. A pak je tu 5, o čem klient vůbec netuší, a to které zdroje už má server k dispozici a může je posílat a které ještě nemá.
push prostě nikdy dobře nefungoval
Myslím si, že se tomu dalo málo času, aby se to usadilo – byla to úplně nová technologie, kterou není tak snadné implementovat.
prohlížeč pak opravdu ví, co chce lépe než server.
Neví to lépe než server, protože je závislý na informacích, které mu server pošle. Prohlížeč ví lépe než server co nechce. Což řeší odmítnutí streamu.
Server ale ví, co může prohlížeči poslat – a o tom prohlížeč neví vůbec nic. Takže vznikají situace, kdy prohlížeč něco chce, ale server mu to nemůže poskytnout, tak se čeká – přitom by server mezi tím mohl posílat data, která klient bude chtít za chvíli.
Není pravda, že server soubor nenabízí, jen oznámí jeho poslání přes PUSH_PROMISE a poté začne v dalším framu data posílat.
Je to přesně jak jsem psal – server soubor nabídne a začne ho posílat. Prohlížeč má kdykoli šanci ho odmítnout.
Prohlížeč data příjme a drží si je v odděleném uložišti než rozhodne co s nimi. Tak funguje aktuální implementace v třeba Chromu.
To, že je to blbě implementované v jednom prohlížeči, není důvod, proč zabít celou technologii. Užitečnější by bylo to opravit než to celé zaříznout.
Problém je, že soubor se neposílá se všemi hlavičkami
To není pravda, hlavičky se tam posílají úplně stejně, jako při client-pull. Rozdíl je jenom v tom, odkud se ten stream iniciuje.
Kromě zmíněných problémů je třeba ještě problém se SPA a offline aplikacemi, kdy server při posílání obsahu neví, jakou verzi aplikace má klient a může dojít k nekonzistenci aplikace.
Nikdy nebylo povinné používat server PUSH. Když to server neví, nic posílat nemusí.
Další problém je, že server neví, na jak rychlé lince je prohlížeč a při posílání velkých dat (nebo posílání malých dat ale hodně klientům na stejné lince) dochází k zahlcení linky na straně prohlížeče. Za normálních okolností si tohle prohlížeč řídí sám, tady je ale jako rukojmí.
Ne, neřídí si to prohlížeč sám. Řídí si to síťové vrstvy operačních systémů ne obou stranách. Protože řízení toku v TCP/IP není úplně ideální, vznikl QUIC, nad kterým je postavené HTTP/3.
Na straně serverů a hlavně load balancerů je pak problém s throttlingem nebo rate limitem, v podstatě žádný velký vendor (AWS, cloudflare, Azure, F5 atd.) neposkytuje plně funkční load balancer pro Push, jsme rádi, když jakžtakž to funguje pro samotné HTTP/2.
Myslím si, že se tomu dalo málo času, aby se to usadilo – byla to úplně nová technologie, kterou není tak snadné implementovat.
Je to přesně jak jsem psal – server soubor nabídne a začne ho posílat
Aha, já myslel, že pokud něco nabídnu, čekám na odpověď. I v dokumentaci se mluví o oznámení, přislíbení a následném poslání.
Server neví, jestli prohlížeč (přesněji teda klient) bude potřebovat css, font, obrázky. A prohlížeč zase neví, co přesně mu server posílá (path a content-type nemusí být dostatečný zejména třeba u responzivních stránek), aby to mohlo odmítnout.
Už jen důsledek, že klient musí něco aktivně odmítat vede k přílišné komplexnosti. Pokud sám tvrdíš, že to není snadná technologie, není to právě ten správný důvod ke zrušení?
Aha, já myslel, že pokud něco nabídnu, čekám na odpověď. I v dokumentaci se mluví o oznámení, přislíbení a následném poslání.
Tváříte se, jako by to byl obrovský problém, že to server začne hned posílat. Za prvé, protokol nikde neříká, že to musí začít posílat okamžitě - kdyby o to někdo stál, může dát prohlížeči čas k odmítnutí. Dokonce by byla i možnost, aby si prohlížeč hlavičkou v prvním požadavku řekl, jak dlouho má server čekat (ve standardu to není, ale kdyby na to byl požadavek z praxe, nebyl by problém to doplnit).
Server neví, jestli prohlížeč (přesněji teda klient) bude potřebovat css, font, obrázky.
Ale ví. Server ví, zda už prohlížeč na webu byl a kdy. A pořád platí, že pokud klient ten soubor nepotřebuje, protože ho už má v cache, může soubor snadno odmítnout.
A prohlížeč zase neví, co přesně mu server posílá (path a content-type nemusí být dostatečný zejména třeba u responzivních stránek), aby to mohlo odmítnout.
Ano, responzivní obrázky jsou jediný příklad, kdy toho server v tuhle chvíli neví dost. Tak prostě ten soubor nemusí nabízet a počká si, až si o něj prohlížeč řekne.
Už jen důsledek, že klient musí něco aktivně odmítat vede k přílišné komplexnosti.
Já na odmítání nevidím nic složitějšího, než když prohlížeč dostane seznam toho, co by si měl stáhnout, a z toho si musí vybrat, co opravdu bude chtít. Naopak s Prefetch je komplexita v prohlížeči větší, protože tu logiku, kdy co požadovat, řídí prohlížeč místo serveru.
Pokud sám tvrdíš, že to není snadná technologie, není to právě ten správný důvod ke zrušení?
Ne, není. Prefetch je na straně prohlížeče komplikovanější, ale má méně možností. Jsou dvě věci, které umí navíc - řešit výběr responzivního obrázku nabídnout zdroje z jiné domény. PUSH má naopak tu výhodu, že dokáže využít i "hluchá" místa ve spojení, tj. okamžiky, kdy by jinak neměl co posílat. Což je podle mne klíčová věc při zrychlování načítání stránek. Zmenšovat data na úrovni protokolu už moc víc nejde, celý prefetch je snaha o to, aby se zbytečně nečekalo. HTTP PUSH byla možnost to posunout dál a okamžiky, kdy se stejně musí čekat, využít k posílání něčeho užitečného.