1
無論是我們在學(xué)校剛開始學(xué)編程,還是在剛參加工作開始處理實(shí)際問題,寫出來的程序都是很簡單的。因?yàn)槊鎸Φ膯栴}很簡單。
以處理數(shù)據(jù)為例,可能只是把一個幾十 K 的文件解析下,然后生成一個詞頻分析的報告。很簡單的程序,十幾行甚至幾行就搞定了。
直到有一天,給你扔過來 1000 個文件,有些還特別大,好幾百 M 了。你用之前的程序一跑,發(fā)現(xiàn)跑的時間有點(diǎn)長。于是想要去優(yōu)化下。
1000 個文件,互相還沒業(yè)務(wù)聯(lián)系,用多線程呀,一個線程處理一個文件,結(jié)果再匯總就搞定了。總算把學(xué)校里學(xué)的操作系統(tǒng)知識和編程語言里的多線程庫都運(yùn)用起來了。你很高興,老師知道了也會很欣慰。
如果多線程效果不夠好,比如像 Python 的多線程,沒法利用多核的威力,那就用多進(jìn)程。
如果嫌線程和進(jìn)程切換開銷太大,大到影響整體性能 -- 通常就是所謂的 I/O bound 的場景,還可以用協(xié)程這類技術(shù)。
無論是線程、進(jìn)程,還是協(xié)程,本質(zhì)上,目的都是為了計算的并行化,解決的是算的慢的問題。
而如果計算量足夠大,就算榨干了機(jī)器的計算能力,也算不過來,咋辦?
一臺機(jī)器不夠,那就多搞幾臺機(jī)器嘛。所以就從多線程/進(jìn)程/協(xié)程的「計算并行化」,進(jìn)化到了「計算的分布式化」(當(dāng)然,分布式一定程度上也是并行化)。
2
這還沒完,另一方面,如果處理的數(shù)據(jù)有 10T,而你手上的機(jī)器只有 500G 的硬盤,怎么辦?
一種辦法是縱向擴(kuò)展,搞一臺幾十 T 硬盤的機(jī)器;另一種是橫向擴(kuò)展,多搞幾臺機(jī)器,分散著放。前者很容易到瓶頸,畢竟數(shù)據(jù)無限,而一臺機(jī)器的容量有限,所以在大數(shù)據(jù)量的情況下,只能選后者。
把數(shù)據(jù)分散到多臺機(jī)器,本質(zhì)上解決的是存不下的問題。
同時,剛才提到計算分布式化后,總不能所以程序都去同一臺機(jī)器讀數(shù)據(jù)吧,這樣效率必然會受到單臺機(jī)器性能的拖累,比如磁盤 IO、網(wǎng)絡(luò)帶寬等,也就逼著數(shù)據(jù)存儲也要分散到各個機(jī)器去了。
基于這兩個原因,數(shù)據(jù)存儲也分布式起來了。
3
前面說計算的分布式化的時候,有這么一句話:
一個線程處理一個文件,結(jié)果再匯總就搞定了
先做任務(wù)的拆分,然后再做結(jié)果的合并。本質(zhì)上就是分治的思想。很顯然,分治是個非常通用和應(yīng)用無關(guān)的方法,沒有必要每個應(yīng)用都去實(shí)現(xiàn)一遍,做個通用的庫就行了,或者裝逼點(diǎn),我們叫它框架。
解決這個問題之后,再做好抽象,豐富下功能,定義好 API,基本的樣子就出來了。
于是,我們有了一個分布式的計算框架。
4
而說存儲的分布式化的時候,忽略了一些問題,比如:
- 怎么拆分?jǐn)?shù)據(jù)?以什么粒度拆?
- 使用方怎么知道哪些數(shù)據(jù)在哪里?
這些問題的答案也不難:
- 像前面說的那樣以文件為單位去拆分,恐怕不妥。文件大小差距可能很大,不利于數(shù)據(jù)的均衡分布,需要拆的更細(xì)。
- 為了讓使用方知道該去哪臺機(jī)器拿想要的數(shù)據(jù),尤其在數(shù)據(jù)的切割粒度不再是使用方能理解的文件之后,需要維護(hù)一個數(shù)據(jù)單元和機(jī)器/服務(wù)位置的映射關(guān)系。
當(dāng)然,問題不只這些,只是舉例而已。解決這些問題之后,再加以完善,封裝好 API 和服務(wù),一個能存海量數(shù)據(jù)的框架就有了,或者裝逼點(diǎn),我們叫它引擎。
于是,我們有了一個分布式的存儲引擎。
5
分布式存儲引擎和分布式計算框架,就是一個分布式系統(tǒng)最基礎(chǔ)的組成部分。
廣義的分布式系統(tǒng),當(dāng)然不只包含這兩個東西。但它們是最基礎(chǔ)和核心的東西。有了它們,我們就能對海量數(shù)據(jù)做最基本和通用的處理,而不再被單臺機(jī)器束縛住。
是的,分布式系統(tǒng)很強(qiáng)大、很有用。但什么時候該用,什么時候又不要高射炮打蚊子呢?
其實(shí)也很簡單。和分布式系統(tǒng)嘗試解決的問題對應(yīng)起來,就一目了然了:
- 當(dāng)你嘗試了各種優(yōu)化方法,還是不能把計算時間降低到一個可接受的程度的時候
- 當(dāng)你發(fā)現(xiàn)找不到硬盤更大的機(jī)器來裝下你的數(shù)據(jù),或者無法承擔(dān)這個成本的時候
那很有可能,你需要考慮分布式系統(tǒng)了。
至于多慢叫慢,多大叫大,就區(qū)別于應(yīng)用場景了。
老板每天早上要看的報表,凌晨跑幾個小時都能接受;全平臺的準(zhǔn)實(shí)時監(jiān)控數(shù)據(jù),就等不了幾個小時了。
同樣是做指標(biāo)統(tǒng)計,幾百 G 的用戶注冊數(shù)據(jù)可能不算大,但幾百 G 的用戶行為數(shù)據(jù)可能就很大了。后者比前者更有可能需要分布式系統(tǒng),因?yàn)樵鲩L速度會快一兩個數(shù)量級。
6
一個乍看起來很無厘頭,細(xì)想又挺值得思考的問題:微服務(wù)是不是分布式系統(tǒng)?
類似的問題還有:分庫分表+訪問中間件的數(shù)據(jù)庫是不是分布式系統(tǒng)?
廣義來講,都可以算是。
狹義來講,也是從這個系列關(guān)注的角度來看,分布式系統(tǒng)是指大數(shù)據(jù)領(lǐng)域下,以處理海量數(shù)據(jù)為目的的系統(tǒng)。
當(dāng)然,分布式系統(tǒng)遠(yuǎn)不止這么簡單的兩個分類,也遠(yuǎn)不止表面上看起來這樣隨便弄弄就能用好,還有非常多需要考慮和解決的問題,其中很多恰恰是分布式本身帶來的問題(聽起來很無奈吧),這也是這個系列后面會花大量篇幅去講的內(nèi)容。
這樣,我們就對開頭提到的 What -- 這個東西是什么,也有了基本的認(rèn)識。
(看吧,先講 Why,再講 What,也沒有影響我們學(xué)習(xí)這個東西。我這么組織,也是想借這點(diǎn)來強(qiáng)調(diào)開頭提到的多思考 Why 的重要性。)
總結(jié):
這個系列文章關(guān)注的分布式系統(tǒng),是指以處理海量數(shù)據(jù)為目的的多機(jī)系統(tǒng)。
我們之所以需要分布式系統(tǒng),是為了擺脫單機(jī)資源的束縛。再具體點(diǎn),是為了解決這兩個問題:
- 單臺機(jī)器算的慢,哪怕協(xié)程、多線程、多進(jìn)程全用上
- 單臺機(jī)器裝不下,哪怕你有再多的錢
實(shí)際應(yīng)用中,分布式系統(tǒng)最基礎(chǔ)核心的是兩種:
- 分布式計算框架,用來解決算的慢的問題
- 分布式存儲引擎,用來解決存不下的問題
知道了為什么要有分布式系統(tǒng),以及什么時候應(yīng)該用分布式系統(tǒng)。緊接著一個問題就是,分布式系統(tǒng)都是怎么來的,又是誰做出來的呢?