上層應用開發的多了以後,對底層技術的接觸就愈來愈少了。以致於不少人有了「底層技術無用論」的觀點。不少人認爲學習框架多好啊,你們都在用,跳槽的時候也能用的上。學習那些底層技術幹啥,平時都用不到。前端
本號並不這麼認爲。咱們先舉一個活生生的例子,好比咱們如今有個Web服務應用,崩潰重啓後在綁定套接字的時候出現報錯(socket_bind(): unable to bind address [98]: Address already in use。),致使服務端沒法工做。問題比較明確,是地址(端口)被佔用了。你這時候可能會猜想那個程序佔了端口呢?你們都清楚,服務器端口的使用都是嚴格受限的,確定是這個程序。可是可能會疑惑:「這個程序不是剛剛起來嗎?!」若是你只是使用API,不懂得底層的原理,別說解決問題,可能都不知道如何下手。這個問題咱們先放到這裏,後面再具體解釋,這裏只是想說明一下底層技術的重要性。算法
另一個比較典型的例子是關於前端開發的。不少人熱衷於學習各類框架。框架雖然能幫助咱們解決一些問題,節省開發成本並下降開發週期。可是,學習框架並不能掌握技術的根本,從而致使本身能力沒有本質的提高。咱們之前端框架爲例,在過去的幾年當中,JQuery、Bootstrap、Angular和Vue等等等等,輪番上陣。這個框架你還沒用熟悉呢,結果又來了一個新的框架,讓你目不暇接。而這些框架最本質的東西其實就是JS、CSS和HTML等內容,只有學會這些基礎技術,才能遊刃有餘。若是這些基礎技術不熟悉,而投入大量精力學習框架,這就好像還沒學會走,就想着跑,最後本身可能摔得滿頭是包。編程
可能扯的有點遠,前面的例子只是想告訴你們底層技術的重要性。對於咱們搞軟件開發的人來講,底層技術其實至關於大廈的地基,地基不穩,大廈是很危險的。固然,計算機技術的細分領域不少,每一個領域又有本身的底層技術,所以咱們不可能都有涉及。今天咱們介紹的底層技術則是最爲通用的技術,也就是計算、存儲、網絡和數據結構與算法。數組
關於計算相關的內容緩存
計算機技術天然核心是計算了。絕不誇張的說,全部應用都要依賴於計算,小到單機小遊戲,大到電商或者雲計算平臺。所以,計算問題天然是咱們最爲關心的問題了。說到計算,最主要的天然是程序的性能了,**若是咱們開發的程序的性能提高一倍,就至關於硬件成本下降了50%。**對於互聯網這種須要大量計算資源的應用,其價值可見一斑。性能優化
咱們先看一個具體的例子。下面是一段C語言的代碼,代碼很簡單,就是將二維數組中的內容作加一操做。可是若是你測試一下兩段代碼的耗時的話,就會發現二者有四倍的性能差別。你們能夠觀察一下圖中兩端代碼的差別,並思考一下爲何有如此之大的差別。前端框架
問題先放一下,咱們回到咱們今天的主角,CPU。CPU是計算依賴的硬件,你們都知道計算是在CPU內完成的。咱們先看一下CPU長什麼樣。CPU是計算機的核心單元,它負責從存儲設備讀取數據,通過計算後將生成的新數據再存儲起來。這就好像一個大型工廠的生產車間,將原材料加工成半成品或者成品(咱們後面單獨用一個章節介紹CPU相關的內容)。服務器
瞭解了CPU的基本功能,咱們再解剖了看看它的五臟六腑長什麼樣。下圖是一個簡化的CPU內部結構圖,最爲核心的組件就是計算單元(ALU)、寄存器(不少寄存器)和高速緩存。另外就是經過總線接口與外部的內存進行鏈接。這裏面最核心的組件就是ALU了,其原理很簡單,就是完成加減乘除運算。網絡
CPU要進行運算,就須要原料,而原料須要從內存搬運。有一個事實咱們須要記住,就是訪問內存的代價(延時)是訪問寄存器的100倍左右。最先的CPU是直接訪問內存的,後來隨着ALU性能的提高,發現有問題,就在ALU和內存之間增長了緩存。現代CPU緩存一般爲3級緩存,分別是L一、L2和L3,其中L1和L2是CPU核獨有的,而L3是同一顆CPU的多核共享的。其基本的架構以下圖所示。數據結構
這裏面有個關鍵問題是緩存的容量是遠遠小於主(內)存的容量的,所以,緩存中的數據一般是主存數據的很小的一部分。因爲應用訪問數據有區域局部性的特色,所以緩存中的數據一般是程序須要的數據,也就是ALU接下來要用的數據。另一個須要注意的地方是從主存讀取數據到緩存是有必定粒度(專業術語叫緩存行)的,當前處理器一般是64字節。以下圖所示,主存中的內容被讀取到緩存中。
而後,咱們回到一開始的關於上面兩段程序的性能問題來。上面代碼中一個是逐行訪問二維數組,另一個是逐列訪問二維數組。具體示意圖以下圖所示。
在逐行訪問時,訪問的地址是以4字節爲單位跳躍的,因爲緩存行大小是64字節,所以很容易命中緩存。而逐列訪問時,每次跳躍4096字節,遠遠超越了緩存行的大小,從而致使數據大部分是從內存讀取的。也正是由於這個,致使兩個程序有四倍的性能差別。
經過上面的介紹,咱們應該記住兩個關鍵點,一個是訪問內存的代價比較高,所以在編程時儘可能減小對內存的直接訪問;另一個是充分利用緩存的優點。關於如何作到上面兩點,具體細節咱們後續專門介紹。
關於存儲相關的內容
數據最終都要存儲在存儲設備上,不然系統一斷電全部東西都丟了,這個道理你們都懂。這裏的存儲包括磁盤和SSD硬盤等內容。本文主要從存儲設備及管理設備的文件系統分析存儲相關關鍵技術。存儲中最爲重要的有兩個方面,一個是存儲數據的可靠性,另一個是存儲數據的性能。
本文先從存儲的性能提及,可靠性咱們後續專門介紹。在存儲領域使用最多的仍是普通機械磁盤。機械磁盤的內部解剖圖以下圖所示,其數據的讀寫是經過一個機械臂完成的。機械臂擺來擺去,想一想就知道不會太快。機械磁盤是IBM發明的,第一塊磁盤的尋道時間(機械臂定位到目的位置的時間)在600毫秒左右。而現代的機械磁盤尋道時間有了比較明顯的改善,但因爲其機械特性的緣由,其耗時仍是比較長的,大概是4-8毫秒的樣子。
如下是付費內容
這個耗時是內存的近10萬倍,是寄存器耗時的千萬倍。所以機械磁盤的速度相對內存來講,無異於蝸牛對高鐵的速度。鑑於機械磁盤的上述缺陷,在軟件層面作了不少考量,從而保證性能最佳。
咱們一般在使用硬盤的時候不會直接寫代碼訪問(不排除個例),而是經過操做系統提供的接口訪問。這個操做系統的接口一般是文件系統的接口。爲了便於理解,咱們先看一下對於Linux操做系統來講,磁盤系統的整個軟硬件棧,從上到下分別是:文件系統、通用塊層、設備驅動層和設備層(具體的硬件設備,能夠理解爲磁盤)。
在這裏有兩個層面的軟件對磁盤的訪問作了優化,一個是文件系統,另一個是通用塊層。其中文件系統的核心功能是磁盤數據管理的功能,但考慮到磁盤的缺點,所以在讀寫數據方法作了一些性能方面的優化。而通用塊層則主要是針對磁盤的特性進行了各類優化。
文件系統對磁盤訪問的性能優化是經過頁緩存(頁緩存其實就是內存)完成的,這個頁緩存與CPU中的緩存有殊途同歸之妙。文件系統經過頁緩存在數據寫和讀兩方面分別做了優化。
寫方面的優化主要是延遲批量寫,也就是數據先寫到頁緩存中,通過積累後再磁盤驅動提交。這種積累和延遲寫主要目的是爲了增長數據的連續性,也就是爲了規避磁盤機械臂的擺動,由於磁盤機械臂擺動是最耗時的。
讀方面的優化主要是預讀功能,預讀就是根據當前應用讀取數據的模式,提早將數據讀到內存當中。因爲應用訪問數據的區域局部性特色,這種預讀就能夠避免應用直接從磁盤讀取數據的延時,從而提升讀性能。
通用塊層的主要做用是針對磁盤作IO調度,通俗的講就是決定哪一個IO先發送到磁盤,哪一個後發送到磁盤。
針對機械磁盤來講,最爲重要的就是通用塊層會進行IO的重排序(根據邏輯地址排序)。如上圖所示,假設上層應用按時間順序發送一、二、三、4和5等5個請求的時候。此時,通用塊層並不會按照時間順序發送給磁盤,而是按照圖中紅色虛線箭頭的順序(一、五、二、四、3)發送給我。這樣,磁盤的機械臂就不用來回擺動,從而大大提高其性能。
其實說了半天,這裏有一點是須要咱們注意的,那就是機械磁盤不善於處理IO地址差別比較大的請求(會致使機械臂頻繁擺動),這是咱們在作架構設計的時候須要注意的。雖然操做系統和通用塊層爲咱們作了不少工做,但其能力畢竟有限,所以咱們在設計的時候也必須考慮。後面咱們會經過實例給你們介紹大牛公司在設計應用的時候是如何考慮的。
因爲篇幅問題,今天先到這裏,後面再給你們介紹其它必備的底層技術。