動態

詳情 返回 返回

深入瞭解現代網絡瀏覽器(第 1 部分) - 動態 詳情

前言

本文是進擊的大葱對Mario Kosaka寫的inside look at modern web browser系列文章的翻譯。這裏的翻譯不是指直譯,而是結合個人的理解將作者想表達的意思表達出來,而且會盡量補充一些相關的內容來幫助大家更好地理解。

CPU,GPU,內存和多進程架構

在本篇文章中,我將會從Chrome瀏覽器的高層次架構(high-level architecture)開始説起,一直深入講到頁面渲染流水線(rendering pipeline)的具體細節。如果你想知道瀏覽器是怎麼把你編寫的代碼轉變成一個可用的網站,或者你不知道為什麼一些特定的代碼寫法可以提高網站的性能的,那你就來對地方了,這篇文章就是為你準備的。

首先我們先了解一些關鍵的計算機術語以及Chrome瀏覽器的多進程架構

計算機的核心 - CPU和GPU

要想理解瀏覽器的運行環境,我們先要搞明白一些計算機組件以及它們的作用。

CPU

首先我們要説的是計算機的大腦 - CPUCentral Processing Unit)。CPU是計算機裏面的一塊芯片,上面有一個或者多個核心(core)。我們可以把CPU的一個核心(core)比喻成一個辦公室工人,他功能強大,上知天文下知地理,琴棋書畫無所不能,它可以串行地一件接着一件處理交給它的任務。很久之前的時候大多數CPU只有一個核心,不過在現在的硬件設備上CPU通常會有多個核心,因為多核CPU可以大大提高手機和電腦的運算能力。如何理解處理器、CPU、多處理器、內核、多核?

image.png
圖 1:四個CPU核心愉快地在各自工位上一個接着一個地處理交給它們的任務

GPU

圖形處理器 - 或者説GPUGraphics Processing Unit)是計算機的另外一個重要組成部分。和功能強大的CPU核心不一樣的是,單個GPU核心只能處理一些簡單的任務,不過它勝在數量多,單片GPU上會有很多很多的核心可以同時工作,也就是説它的並行計算能力是非常強的。圖形處理器(GPU)顧名思義一開始就是專門用來處理圖形的,所以在説到圖形使用GPUusing)或者GPU支持backed)時,人們就會聯想到圖形快速渲染或者流暢的用户體驗相關的概念。最近幾年來,隨着GPU加速概念的流行,在GPU上單獨進行的計算也變得越來越多了。

image.png
圖 2:每個GPU核心手裏只有一個扳手,這就説明它的能力是非常有限的,可是它們人多啊!

當你在手機或者電腦上打開某個應用程序的時候,背後其實是CPUGPU支撐着這個應用程序的運行。通常來説,你的應用要通過操作系統提供的一些機制才能跑在CPUGPU上面。

image.png
圖 3:計算機的三層架構,最下層是硬件機器,操作系統夾在中間,最上層是運行的應用

在進程和線程上執行程序

在深入到瀏覽器的架構之前我們還得了解一下進程(process)和線程(thread)的相關概念。進程可以看成正在被執行的應用程序(executing program)。而線程是跑在進程裏面的,一個進程裏面可能有一個或者多個線程,這些線程可以執行任何一部分應用程序的代碼。

image.png
圖 4:進程就像一個大魚缸,而線程就是浴缸裏面暢遊的魚兒

當你啓動一個應用程序的時候,操作系統會為這個程序創建一個進程同時還為這個進程分配一片私有的內存空間,這片空間會被用來存儲所有程序相關的數據和狀態。當你關閉這個程序的時候,這個程序對應的進程也會隨之消失,進程對應的內存空間也會被操作系統釋放掉。

圖 5:進程使用系統分配的內存空間去存儲應用的數據

有時候為了滿足功能的需要,創建的進程會叫系統創建另外一些進程去處理其它任務,不過新建的進程會擁有全新的獨立的內存空間而不是和原來的進程共用內存空間。如果這些進程需要通信,它們要通過IPC機制(Inter Process Communication)來進行。很多應用程序都會採取這種多進程的方式來工作,因為進程和進程之間是互相獨立的它們互不影響,換句話來説,如果其中一個工作進程(worker process)掛掉了其他進程不會受到影響,而且掛掉的進程還可以重啓。


圖 6:不同的進程通過IPC來通信

瀏覽器架構

那麼瀏覽器是怎麼使用進程和線程來工作的呢?其實大概可以分為兩種架構,一種是單進程架構,也就是隻啓動一個進程,這個進程裏面有多個線程工作。第二種是多進程架構,瀏覽器會啓動多個進程,每個進程裏面有多個線程,不同進程通過IPC進行通信。


圖 7:單進程和多進程瀏覽器的架構圖

上面的圖表架構其實包含了瀏覽器架構的具體實現了,在現實中其實並沒有一個大家都遵循的瀏覽器實現標準,所以不同瀏覽器的實現方式可能會完全不一樣。

為了更好地在本系列文章中展開論述,我們主要討論最新的Chrome瀏覽器架構,它採用的是多進程架構,以下是架構圖:

Chrome瀏覽器會有一個瀏覽器進程(browser process),這個進程會和其他進程一起協作來實現瀏覽器的功能。對於渲染進程(renderer process),Chrome會盡可能為每一個tab甚至是頁面裏面的每一個iframe都分配一個單獨的進程。


圖 8:Chrome的多進程架構圖,多個渲染進程的卡片(render process)是用來表明Chrome會為每一個tab創建一個渲染進程。

各個進程如何分工合作呢?

以下是各個進程具體負責的工作內容:

img


圖 9:不同的進程負責瀏覽器不同部分的界面內容

除了上面列出來的進程,Chrome還有很多其他進程在工作,例如擴展進程(Extension Process)和工具進程(utility process)。如果你想看一下你的Chrome瀏覽器現在有多少個進程在跑可以點擊瀏覽器右上角的更多按鈕,選擇更多工具和任務管理器:

img

在彈出的窗口裏面你會看到正在工作的進程列表,以及每個進程使用的CPU和內存狀況。

Chrome多進程架構的好處

那麼為什麼Chrome會採取多進程架構工作呢?

其中一個好處是多進程可以使瀏覽器具有很好的容錯性。對於大多數簡單的情景來説,Chrome會為每個tab單獨分配一個屬於它們的渲染進程(render process)。舉個例子,假如你有三個tab,你就會有三個獨立的渲染進程。當其中一個tab的崩潰時,你可以隨時關閉這個tab並且其他tab不受到影響。可是如果所有的tab都跑在同一個進程的話,它們就會有連帶關係,一個掛全部掛。


圖 10:不同的tab會有不同的渲染進程來負責

Chrome採用多進程架構的另外一個好處就是可以提供安全性和沙盒性(sanboxing)。因為操作系統可以提供方法讓你限制每個進程擁有的能力,所以瀏覽器可以讓某些進程不具備某些特定的功能。例如,由於tab渲染進程可能會處理來自用户的隨機輸入,所以Chrome限制了它們對系統文件隨機讀寫的能力。

不過多進程架構也有它不好的地方,那就是進程的內存消耗。由於每個進程都有各自獨立的內存空間,所以它們不能像存在於同一個進程的線程那樣共用內存空間,這就造成了一些基礎的架構(例如V8 JavaScript引擎)會在不同進程的內存空間同時存在的問題,這些重複的內容會消耗更多的內存。所以為了節省內存,Chrome會限制被啓動的進程數目,當進程數達到一定的界限後,Chrome會將訪問同一個網站的tab都放在一個進程裏面跑

節省更多的內存 - Chrome的服務化

同樣的優化方法也可以被使用在瀏覽器進程(browser process)上面。Chrome瀏覽器的架構正在發生一些改變,目的是將和瀏覽器本身(Chrome)相關的部分拆分為一個個不同的服務,服務化之後,這些功能既可以放在不同的進程裏面運行也可以合併為一個單獨的進程運行。

這樣做的主要原因是讓Chrome在不同性能的硬件上有不同的表現。當Chrome運行在一些性能比較好的硬件時,瀏覽器進程相關的服務會被放在不同的進程運行以提高系統的穩定性。相反如果硬件性能不好,這些服務就會被放在同一個進程裏面執行來減少內存的佔用。其實在這次架構變化之前,ChromeAndroid上面已經開始採取類似的做法了。

圖 11:Chrome將瀏覽器相關的服務放在同一個進程裏面運行和放在不同的進程運行的區別

單幀渲染進程 - 網站隔離(Site Isolation)

網站隔離(Site Isolation)是最近Chrome瀏覽器啓動的功能,這個功能會為網站內不同站點的iframe分配一個獨立的渲染進程。之前説過Chrome會為每個tab分配一個單獨的渲染進程,可是如果一個tab只有一個進程的話不同站點的iframe都會跑在這個進程裏面,這也意味着它們會共享內存,這就有可能會破壞同源策略。同源策略是瀏覽器最核心的安全模型,它可以禁止網站在未經同意的情況下去獲取另外一個站點的數據,因此繞過同源策略是很多安全攻擊的主要目的。而進程隔離(proces isolation)是隔離網站最好最有效的辦法了。再加上CPU存在Meltdown和Spectre的隱患,網站隔離變得勢在必行。因此在Chrome 67版本之後,桌面版的Chrome會默認開啓網站隔離功能,這樣每一個跨站點的iframe都會擁有一個獨立的渲染進程。

2018年,GoogleProject Zero團隊和其他安全人員相繼發現了一個影響世界上絕大多數CPU的安全漏洞,Spectre[1]。這個漏洞允許一個進程讀取其本不允許讀取的內存數據。這也使得瀏覽器變得不安全,因為在瀏覽器中,不同網站的不同文檔可以在同一進程中運行[2]。惡意網站可能會利用這個漏洞讀取用户在其他網站上的信息。

為了防止類似的漏洞,WHATWG工作組先後新增了Cross-Origin-Resource-PolicyCross-Origin-Opener-PolicyCross-Origin-Embedder-Policy 3個HTTP響應首部,服務器使用這些首部告訴瀏覽器保護站點數據。此外,Chromium實現了站點隔離(Site Isolation)機制,保證不同站點獨立運行在不同進程中,並阻止敏感數據的傳播[3]。該機制從Chrome 67開始默認啓用。相應地,Firefox也正在測試類似機制(Fission)[4],Safari則正在跟進[5]。

跨源相關機制綜述(四):Spectre攻擊與跨源機制的改進

圖片
圖 12:網站隔離功能會讓跨站的iframe擁有獨立的進程

網站隔離技術匯聚了我們工程師好幾年的研發努力,它其實遠遠沒有想象中那樣只是為不同站點的iframe分配一個獨立的渲染進程那麼簡單,因為它從根本上改變了各個iframe之間的通信方式。網站隔離後,對於有iframe的網站,當用户打開右邊的devtool時,Chrome瀏覽器其實要做很多幕後工作才能讓開發者感覺不出這和之前的有什麼區別,這其實是很難實現的。對於一些很簡單的功能,例如在devtool裏面用Ctrl + F鍵在頁面搜索某個關鍵詞,Chrome都要遍歷多個渲染進程去完成。所以我們的瀏覽器工程師在網站隔離這個功能發佈後都感嘆這是一個里程碑式的成就。

總結

在本篇文章中,我們探討了瀏覽器高層次的架構設計以及多進程架構的帶來的好處。同時我們還討論了服務化和網站隔離這些和瀏覽器多進程架構息息相關的技術。在下一篇文章中我們要開始深入瞭解這些進程和線程是如何呈現我們的網站頁面的了。

user avatar maenj_ba_lah 頭像
點贊 1 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.