應屆生在面試的時候,偶爾也會遇到一些系統設計題,而這些題目每每只是測試一下求職者的知識面,或者測試求職者對系統架構方面的瞭解,通常不會涉及到具體的編碼工做。雖然如此,對於此類問題,不少人仍是感受難以應對,也不知道從何提及。前端
如何應對此類題目呢?在正式介紹基礎知識以前,首先羅列幾個常見的系統設計相關的面試筆試題,以下所示。node
(1)設計一個DNS的Cache結構,要求可以知足每秒5000次以上的查詢,知足IP數據的快速插入,查詢的速度要快(題目還給出了一系列的數據,好比:站點數總共爲5000萬,IP地址有1000萬,等等)。面試
(2) 有N臺機器,M個文件,文件能夠以任意方式存放到任意機器上,文件可任意分割成若干塊。假設這N臺機器的宕機率小於1/3,想在宕機時能夠從其餘未宕機的機器中完整導出這M個文件,求最好的存放與分割策略。算法
(3) 假設有三十臺服務器,每臺服務器上面都存有上百億條數據(有可能重複),如何找出這三十臺機器中,根據某關鍵字,重複出現次數最多的前100條?要求使用Hadoop來實現。數據庫
(4) 設計一個系統,要求寫速度儘量快,並說明設計原理。編程
(5) 設計一個高併發系統,說明架構和關鍵技術要點。後端
(6) 有25T的log(query->queryinfo),log在不段的增加,設計一個方案,給出一個query能快速返回queryinfo緩存
以上全部問題中凡是不涉及高併發的,基本能夠採用Google的三個技術解決,分別爲:GFS,MapReduce,Bigtable,這三個技術被稱爲「Google三駕馬車」,Google只公開了論文而未開源代碼,開源界對此很是有興趣,仿照這三篇論文實現了一系列軟件,如:Hadoop、HBase、HDFS、Cassandra等。服務器
在Google這些技術還未出現以前,企業界在設計大規模分佈式系統時,採用的架構每每是database+sharding+cache,如今不少公司(好比taobao,weibo.com)仍採用這種架構。在這種架構中,仍有不少問題值得去探討。如採用什麼數據庫,是SQL界的MySQL仍是NoSQL界的Redis/TFS,二者有何優劣?採用什麼方式sharding(數據分片),是水平分片仍是垂直分片?據網上資料顯示,weibo.com和taobao圖片存儲中曾採用的架構是Redis/MySQL/TFS+sharding+cache,該架構解釋以下:前端cache是爲了提升響應速度,後端數據庫則用於數據永久存儲,防止數據丟失,而sharding是爲了在多臺機器間分攤負載。最前端由大塊大塊的cache組成,要保證至少99%(該數據在weibo.com架構中的是本身猜的,而taobao圖片存儲模塊是真實的)的訪問數據落在cache中,這樣能夠保證用戶訪問速度,減小後端數據庫的壓力,此外,爲了保證前端cache中數據與後端數據庫中數據一致,須要有一箇中間件異步更新(爲啥異步?理由簡單:同步代價過高。異步有缺定,如何彌補?)數據,這個有些人可能比較清楚,新浪有個開源軟件叫memcachedb(整合了Berkeley DB和Memcached),正是完成此功能。另外,爲了分攤負載壓力和海量數據,會將用戶微博信息通過片後存放到不一樣節點上(稱爲「sharding」)。網絡
這種架構優勢很是明顯:簡單,在數據量和用戶量較小的時候徹底能夠勝任。但缺定遲早一天暴露出來,即:擴展性和容錯性太差,維護成本很是高,尤爲是數據量和用戶量暴增以後,系統不能經過簡單的增長機器解決該問題。
因而乎,新的架構便出現了。主要仍是Google的那一套東西,下面分別說一下:
GFS是一個可擴展的分佈式文件系統,用於大型的、分佈式的、對大量數據進行訪問的應用。它運行於廉價的普通硬件上,提供容錯功能。如今開源界有HDFS(Hadoop Distributed File System),該文件系統雖然彌補了數據庫+sharding的不少缺點,但自身仍存在一些問題,好比:因爲採用master/slave架構,於是存在單點故障問題;元數據信息所有存放在master端的內存中,於是不適合存儲小文件,或者說若是存儲的大量小文件,那麼存儲的總數據量不會太大。
MapReduce是針對分佈式並行計算的一套編程模型。他最大的優勢是:編程接口簡單,自動備份(數據默認狀況下會自動備三份),自動容錯和隱藏跨機器間的通訊。在Hadoop中,MapReduce做爲分佈計算框架,而HDFS做爲底層的分佈式存儲系統,但MapReduce不是與HDFS耦合在一塊兒的,你徹底可使用本身的分佈式文件系統替換掉HDFS。當前MapReduce有不少開源實現,如Java實現Hadoop MapReduce,C++實現Sector/sphere等,甚至有些數據庫廠商將MapReduce集成到數據庫中了。
BigTable俗稱「大表」,是用來存儲結構化數據的,我的以爲,BigTable在開源界最火爆,其開源實現最多,包括:HBase,Cassandra,levelDB等,使用也很是普遍。
除了Google的這「三駕馬車」之外,還有其餘一些技術可供學習與使用:
Dynamo:亞馬遜的key-value模式的存儲平臺,可用性和擴展性都很好,採用DHT(Distributed Hash Table)對數據分片,解決單點故障問題,在Cassandra中,也借鑑了該技術,在BT和電驢的中,也採用了相似算法。
虛擬節點技術:該技術經常使用於分佈式數據分片中。具體應用場景是:有一大坨數據(maybeTB級或者PB級),咱們需按照某個字段(key)分片存儲到幾十(或者更多)臺機器上,同時想盡可能負載均衡且容易擴展。傳統的作法是:Hash(key) mod N,這種方法最大缺點是不容易擴展,即:增長或者減小機器均會致使數據所有重分佈,代價忒大。因而乎,新技術誕生了,其中一種是上面提到的DHT,如今已經被不少大型系統採用,還有一種是對「Hash(key) mod N」的改進:假設咱們要將數據分不到20臺機器上,傳統作法是hash(key)mod 20,而改進後,N取值要遠大於20,好比是20000000,而後咱們採用額外一張表記錄每一個節點存儲的key的模值,好比:
node1:0~1000000
node2:1000001~2000000
。。。。。。
這樣,當添加一個新的節點時,只需將每一個節點上部分數據移動給新節點,同時修改一下這個表便可。
Thrift:Thrift是一個跨語言的RPC框架,分別解釋一下「RPC」和「跨語言」,RPC是遠程過程調用,其使用方式與調用一個普通函數同樣,但執行體發生在遠程機器上。跨語言是指不一樣語言之間進行通訊,好比c/s架構中,server端採用C++編寫,client端採用PHP編寫,怎樣讓二者之間通訊,thrift是一種很好的方式。
文章最前面的幾道題都可以映射到以上幾個系統中的某個模塊中,如:
(1)關於高併發系統設計。主要有如下幾個關鍵技術點:緩存,索引,數據分片,鎖粒度儘量小。
(2)問題2涉及到如今通用的分佈式文件系統的副本存放策略。通常是將大文件切分紅小的block(如64MB)後,以block爲單位存放三份到不一樣的節點上,這三份數據的位置需根據網絡拓撲結構配置,通常而言,若是不考慮跨數據中心,能夠這樣存放:兩個副本存放在同一個機架的不一樣節點上,而另一個副本存放在另外一個機架上,這樣從效率和可靠性上,都是最優的(這個Google公佈的文檔中有專門的證實,有興趣的可參閱一下。)。若是考慮跨數據中心,可將兩份存在一個數據中心的不一樣機架上,另外一份放到另外一個數據中心。
(3)問題4涉及到BigTable的模型。主要思想是將隨機寫轉化爲順序寫,進而大大提升寫速度。具體是:因爲磁盤物理結構的獨特設計,其併發的隨機寫(主要是由於磁盤尋道時間長)很是慢,考慮到這一點,在BigTable模型中,首先會將併發寫的大批數據放到一個內存表(稱爲「memtable」)中,當該表大到必定程度後,會順序寫到一個磁盤表(稱爲「SSTable」)中,這種寫是順序寫,效率極高。說到這,可能有讀者問,隨機讀可不能夠這樣優化?答案是:看狀況。一般而言,若是讀併發度不高,則不能夠這麼作,由於若是將多個讀從新排列組合後再執行,系統的響應時間太慢,用戶可能接受不了,而若是讀併發度極高,也許能夠採用相似機制。