Arkkitehtuuri
Servo on projekti uuden verkkoselaimen moottorin kehittämiseksi. Tavoitteemme on luoda arkkitehtuuri, joka hyödyntää rinnakkaisuutta monilla tasoilla samalla kun eliminoimme yleisiä virheiden ja tietoturva-aukkojen lähteitä, jotka liittyvät virheelliseen muistinhallintaan ja datakilpailuihin.
Koska C++ sopii huonosti näiden ongelmien estämiseen, Servo on kirjoitettu Rustilla, modernilla kielellä, joka on suunniteltu erityisesti Servon vaatimusten huomioon ottaen. Rust tarjoaa tehtäväpohjaisen rinnakkaisuusinfrastruktuurin ja vahvan tyyppijärjestelmän, joka pakottaa muistiturvallisuuden ja datan kilpailuttamattomuuden.
flowchart TB
subgraph Web-sisällön prosessi
ScriptA[Script-säie]-->PipelineA[Pipeline A]
PipelineA
PipelineA-->ImageA[Kuvavälimuisti]
PipelineA-->FontA[Fonttivälimuisti]
PipelineA-->LayoutA[Layout]
LayoutA-->ImageA
LayoutA-->FontA
ScriptA[Script-säie]-->PipelineB[Pipeline B]
PipelineB
PipelineB-->ImageB[Kuvavälimuisti]
PipelineB-->FontB[Fonttivälimuisti]
PipelineB-->LayoutB[Layout]
LayoutB-->ImageB
LayoutB-->FontB
end
subgraph Upotusprosessi
direction TB
Embedder-->Constellation[Constellation-säie]
Embedder<-->Renderer[Renderer]
Constellation<-->Renderer
Renderer-->WebRender
Constellation-->SystemFont[Järjestelmäfonttivälimuisti]
Constellation-->Resource[Resurssienhallinta]
end
Constellation<-->ScriptA
FontA-->SystemFont
PipelineA-->Renderer
FontB-->SystemFont
PipelineB-->Renderer
Tämä kaavio näyttää moniprosessisen Servon arkkitehtuurin, kun se ajetaan yhdellä web-sisällön prosessilla. Kun moniprosessitila on käytössä, jokainen script-säie ajaa omassa web-sisällön prosessissaan. Kun moniprosessitila on pois päältä, kaikki script-säieet ajavat upotusprosessissa. Jokaisella script-säieellä on joukko viestintäkanavia constellationin ja upotusprosessin upotus-API-osien kanssa. Yhtenäiset viivat osoittavat viestintäkanavia tai API-kutsuja.
Constellation, script-säieet ja pipeline:t
Jokaisella Servo-instanssilla on yksi constellation, joka hallinnoi web-sisällön prosesseja kaikille kehyksille kaikissa WebView-instansseissa.
Web-sisällön prosessin script-säie voi hallita useita pipelineja, yhden jokaiselle <iframe>-elementille tai WebView-instanssin pääkehykselle.
Script-säieen pipeline vastaa syötteen vastaanottamisesta, JavaScriptin suorittamisesta DOM:ia vasten, layoutin suorittamisesta, display listien rakentamisesta ja display listien lähettämisestä rendererille.
Servo-instanssilla on yksi renderer koko instanssille, ja se hallinnoi useita WebRender-instansseja, jotka renderöivät erilaisiin RenderingContext-instansseihin (käytännössä OpenGL-konteksteihin alustan pinnoilla).
Pipeline koostuu kolmesta pääosasta:
- Script: Scriptin ensisijainen tehtävä on luoda ja omistaa DOM ja suorittaa JavaScript-moottoria. Se vastaanottaa tapahtumia useista lähteistä, mukaan lukien navigointitapahtumat, ja reitittää ne tarpeen mukaan.
- Layout: Layout käynnistyy aluksi samalla säieellä kuin Script, mutta se voi käyttää worker-säieitä sivun layoutin rinnakkaiseen suorittamiseen. Se laskee tyylit ja rakentaa kaksi päälayout-tietorakennetta, box tree ja fragment tree. Fragment treeä käytetään solmujen muuntamattomien sijaintien määrittämiseen ja siitä rakennetaan display list, joka lähetetään rendererille.
- Renderer: Renderer (tunnetaan myös compositorina) välittää display listit WebRenderille, joka on sisällön rasterointi- ja näyttömoottori, jota sekä Servo että Firefox käyttävät. Se käyttää GPU:ta sivun lopullisen kuvan renderöintiin. Upottajan käyttöliittymäsäieellä ajettava renderer vastaanottaa myös ensimmäisenä syöte-tapahtumat, jotka yleensä lähetetään heti constellationille ja sitten script-säieelle käsittelyä varten. Jotkin tapahtumat, kuten scroll- ja kosketustapahtumat, voidaan käsitellä aluksi rendererissä responsiivisuuden vuoksi.
Rinnakkaisuus ja rinnakkaisuus (concurrency vs parallelism)
Rinnakkaisuus (concurrency) on tehtävien erottelua vuorottelevan suorituksen tarjoamiseksi. Rinnakkaisuus (parallelism) on useiden työpalojen samanaikaista suorittamista nopeuden lisäämiseksi. Näin hyödynnämme molempia:
- Tehtäväpohjainen arkkitehtuuri: Järjestelmän pääkomponentit tulisi jakaa näyttelijöiksi (actors) eristetyillä keoilla, selkeillä raja-arvoilla virheille ja palautumiselle. Tämä kannustaa myös löyhään kytkentään koko järjestelmässä, mikä mahdollistaa komponenttien vaihtamisen kokeilu- ja tutkimustarkoituksiin.
- Rinnakkainen renderöinti: Renderöinti on erillinen säie, joka on irrotettu layoutista responsiivisuuden ylläpitämiseksi. Renderer-säie hallitsee muistiaan manuaalisesti välttääkseen roskienkeruun (garbage collection) tauot.
- Selektorien täsmäytys: Tämä on helposti rinnakkaistettava ongelma. Kuten Gecko, Servo tekee selektorien täsmäytyksen erillisessä läpäisyssä flow tree -rakentamisen sijaan, jotta se on helpompi rinnakkaistaa.
- Rinnakkainen layout: Rakennamme flow tree:n rinnakkaisella DOM-käynnillä, joka kunnioittaa elementtien, kuten floatien, luomia peräkkäisiä riippuvuuksia.
- Jäsennys: Olemme kirjoittaneet uuden HTML-parserin Rustilla, keskittyen sekä turvallisuuteen että spesifikaation noudattamiseen. Emme ole vielä lisänneet spekulatiivista jäsennystä tai rinnakkaisuutta parseriin.
- Kuvien dekoodaus: Useiden kuvien dekoodaus rinnakkain on suoraviivaista.
- Muiden resurssien dekoodaus: Tämä on todennäköisesti vähemmän tärkeää kuin kuvien dekoodaus, mutta kaikki, mitä sivun täytyy ladata, voidaan tehdä rinnakkain, esim. kokonaisten tyylitiedostojen jäsentäminen tai videoiden dekoodaus. Tyylitiedostot jäsennetään rinnakkain aina kun mahdollista.
Haasteet
- Rinnakkaisuutta vastustavat kirjastot: Jotkin tarvitsemamme kolmannen osapuolen kirjastot eivät toimi hyvin monisäieisissä ympäristöissä. Fontit ovat olleet erityisen hankalia. Vaikka kirjastot olisivat teknisesti säie-turvallisia, säie-turvallisuus saavutetaan usein kirjaston laajuisella mutex-lukolla, mikä heikentää rinnakkaisuusmahdollisuuksiamme.
- Liian monta säiettä: Jos heitämme maksimaalisen rinnakkaisuuden ja samanaikaisuuden kaikkeen, ylikuormitamme järjestelmän liian monella säieellä.
- Liian monta avointa tiedostokahvaa: IPC-viestintä vaatii yleensä tiedostokahvan avaamisen järjestelmässä. Olemme törmänneet ongelmiin (#23910, #33672, #23905 tiedostokahvojen loppumiseen IPC-mekanismien liiallisen käytön vuoksi.
JavaScript ja DOM-bindings
Käytämme tällä hetkellä SpiderMonkeyta, vaikka vaihdettavat moottorit ovat pitkän aikavälin, matalan prioriteetin tavoite. Jokainen web-sisällön prosessi saa oman JavaScript-runtimeensa. DOM-bindings käyttävät natiivia JavaScript-moottorin API:a XPCOM:n sijaan, ja ne generoidaan automaattisesti WebIDL:n kautta.
Moniprosessiarkkitehtuuri
Kuten Chromiumissa ja WebKit2:ssa, tarkoituksemme on luoda luotettu upotusprosessi ja useita vähemmän luotettavia web-sisällön prosesseja. Korkean tason API on IPC-pohjainen, ei-IPC-toteutuksilla testausta ja yksiprosessikäyttötapauksia varten, vaikka odotetaankin, että useimmat vakavat käyttötapaukset käyttävät useita prosesseja. Moottoriprosessit käyttävät käyttöjärjestelmän sandboxointimahdollisuuksia rajoittaakseen pääsyä järjestelmäresursseihin.
Rustin tyyppijärjestelmä lisää myös merkittävän puolustuskerroksen muistiturvallisuusaukkoja vastaan. Tämä yksinään ei tee sandboxista vähemmän tärkeää turvallisen koodin, tyyppijärjestelmän virheiden ja kolmannen osapuolen/isäntäkirjastojen puolustamiseksi, mutta se pienentää Servon hyökkäyspintaa merkittävästi verrattuna muihin selainmoottoreihin. Lisäksi meillä on suorituskykyyn liittyviä huolia joistakin sandboxointitekniikoista (esimerkiksi kaikkien OpenGL-kutsujen välittäminen erilliseen prosessiin).
I/O ja resurssienhallinta
Verkkosivut riippuvat laajasta valikoimasta ulkoisia resursseja, joilla on monia hakemiseen ja dekoodaukseen liittyviä mekanismeja. Nämä resursseja välimuistitetaan useilla tasoilla — levylle, muistiin ja/tai dekoodatussa muodossa. Rinnakkaisessa selainympäristössä nämä resurssit on jaettava samanaikaisille worker-säieille.
Perinteisesti selaimet ovat olleet yksisäieisiä, suorittaen I/O:n “pääsäieellä”, jossa suurin osa laskennasta tapahtuu. Tämä johtaa viiveongelmiin. Servossa ei ole “pääsäiettä”, ja kaikkien ulkoisten resurssien latauksen hoitaa yksi resource manager -tehtävä.
Selaimilla on monia välimuisteja, ja Servon tehtäväpohjainen arkkitehtuuri tarkoittaa, että niitä on todennäköisesti enemmän kuin olemassa olevissa selainmoottoreissa (esim. meillä voi olla sekä globaali tehtäväpohjainen välimuisti että tehtäväkohtainen välimuisti, joka tallentaa tuloksia globaalista välimuistista säästääkseen schedulerin kierroksen). Servolla tulisi olla yhtenäinen välimuistitarina, säädettävillä välimuisteilla, jotka toimivat hyvin vähämuistisissa ympäristöissä.
Viitteet
Tärkeää tutkimusta ja kertynyttä tietoa selaimen toteutuksesta, rinnakkaisesta layoutista jne.:
- How Browsers Work - perustason selitys nykyaikaisten verkkoselaimien yleisestä suunnittelusta Gecko-insinööri Ehsan Akhgari
- More how browsers work - artikkeli, joka on vanhentunut mutta sisältää paljon enemmän yksityiskohtia
- Webkit overview
- Fast and parallel web page layout (2010) - Leo Meyerovichin vaikutusvaltainen rinnakkaiset selektorit, layout ja fontit. Se suosittelee rinnakkaisten selektorien erottamista rinnakkaisesta cascade:sta muistinkäytön parantamiseksi. Katso myös 2013 artikkeli layoutin automatisoinnista ja 2009 artikkeli, joka käsittelee spekulatiivista lexing/jäsentämistä.
- Servo layout on mozilla wiki
- Robert O’Callahan’s mega-presentation - Paljon tietoa selaimista
- ZOOMM paper - Qualcommin verkon esihaku ja yhdistetyt selektorit/cascade
- Strings in Blink
- Incoherencies in Web Access Control Policies - Analyysi document.domainin, cross-origin iframejen ja muun outouden yleisyydestä
- A Case for Parallelizing Web Pages – Sam Kingin palvelinproxy verkkosivujen partitiointiin. Katso myös hänen prosessieristystyönsä, joka raportoi rinnakkaisuuden hyödyistä.
- High-Performance and Energy-Efficient Mobile Web Browsing on Big/Little Systems Säästä virtaa vaihtamalla dynaamisesti käytettävää ydintä automaattisen työkuorman heuristiikan perusteella
- C3: An Experimental, Extensible, Reconfigurable Platform for HTML-based Applications Microsoft Researchin C#-selainprototyyppi, joka tarjosi samanaikaisen (vaikkakaan ei onnistuneesti rinnakkaistetun) arkkitehtuurin
- CSS Inline vertical alignment and line wrapping around floats - dbaron jakaa viisautta floateista
- Quark - Muodollisesti verifioitu selainkernel
- HPar: A Practical Parallel Parser for HTML
- Gecko HTML parser threading