????這篇文章是根據(jù)《分布式學(xué)習(xí)最佳實(shí)踐:從分布式系統(tǒng)的特征開始(附思維導(dǎo)圖)》這篇博客寫的隨心記。這里只供自己學(xué)習(xí),請(qǐng)有志于學(xué)習(xí)的跳轉(zhuǎn)上面的文章。
????分布式系統(tǒng)是一個(gè)很大的概念,系統(tǒng)的學(xué)習(xí)非常的重要,所以最好先從本質(zhì)出發(fā)來看分布式系統(tǒng)。雖然各個(gè)分布式系統(tǒng)的算法可能不一樣,但是其本質(zhì)的分布式特征卻是一致的。
????分布式的四大特征:可擴(kuò)展性、高性能、高可用、一致性。這幾個(gè)特性也是分布式系統(tǒng)的衡量指標(biāo),正是為了在不同的程度上滿足這些特性(或者說達(dá)到這些指標(biāo)),才會(huì)設(shè)計(jì)出各種各樣的算法、協(xié)議,然后根據(jù)業(yè)務(wù)的需求在這些特性間平衡。
可拓展性
? ? 可拓展性是分布式系統(tǒng)必須的,因?yàn)?b>分布式系統(tǒng)是由一組通過網(wǎng)絡(luò)進(jìn)行通信、為了完成共同的任務(wù)而協(xié)調(diào)工作的計(jì)算機(jī)節(jié)點(diǎn)組成的系統(tǒng),所以在系統(tǒng)增加任務(wù)的時(shí)候能夠增加資源來應(yīng)對(duì)任務(wù)增長,達(dá)到自適應(yīng)的能力。
? ??擴(kuò)展性的目標(biāo)是使得系統(tǒng)中的節(jié)點(diǎn)都在一個(gè)較為穩(wěn)定的負(fù)載下工作,這就是負(fù)載均衡,當(dāng)然,在動(dòng)態(tài)增加節(jié)點(diǎn)的時(shí)候,需要進(jìn)行任務(wù)(可能是計(jì)算,可能是數(shù)據(jù)存儲(chǔ))的遷移,以達(dá)到動(dòng)態(tài)均衡。
? ? 這時(shí)候就要考慮如何對(duì)任務(wù)拆分了,任務(wù)的拆分就是數(shù)據(jù)分片,即按照一定的規(guī)則將數(shù)據(jù)集劃分成相互獨(dú)立,正交的數(shù)據(jù)子集,然后將數(shù)據(jù)子集分布到不同的節(jié)點(diǎn)上。
? ? 數(shù)據(jù)分片有三種方式:hash方式,一致性hash(consistent hash),按照數(shù)據(jù)范圍(range based)。對(duì)于任何方式,都需要思考以下幾個(gè)問題:1.具體如何劃分原始數(shù)據(jù)集?2.當(dāng)原問題的規(guī)模變大的時(shí)候,能否通過增加節(jié)點(diǎn)來動(dòng)態(tài)適應(yīng)?3.當(dāng)某個(gè)節(jié)點(diǎn)故障的時(shí)候,能否將該節(jié)點(diǎn)上的任務(wù)均衡的分?jǐn)偟狡渌?jié)點(diǎn)?4.對(duì)于可修改的數(shù)據(jù)(比如數(shù)據(jù)庫數(shù)據(jù)),如果某節(jié)點(diǎn)數(shù)據(jù)量變大,能否以及如何將部分?jǐn)?shù)據(jù)遷移到其他負(fù)載較小的節(jié)點(diǎn),及達(dá)到動(dòng)態(tài)均衡的效果?5.元數(shù)據(jù)的管理(即數(shù)據(jù)與物理節(jié)點(diǎn)的對(duì)應(yīng)關(guān)系)規(guī)模?元數(shù)據(jù)更新的頻率以及復(fù)雜度?
? ? hash方式:按照數(shù)據(jù)的某一特征(key)來計(jì)算哈希值,并將哈希值與系統(tǒng)中的節(jié)點(diǎn)建立映射關(guān)系,從而將哈希值不同的數(shù)據(jù)分布到不同的節(jié)點(diǎn)上。但hash方式的缺點(diǎn)是:當(dāng)加入或者刪除一個(gè)節(jié)點(diǎn)的時(shí)候,大量的數(shù)據(jù)需要移動(dòng),而且很難解決數(shù)據(jù)不均衡的問題。
? ? 一致性hash:將數(shù)據(jù)按照特征值映射到一個(gè)首尾相接的hash環(huán)上,同時(shí)也將節(jié)點(diǎn)(按照IP地址或者機(jī)器名hash)映射到這個(gè)環(huán)上。一致性hash方式在增刪的時(shí)候只會(huì)影響到hash環(huán)上響應(yīng)的節(jié)點(diǎn),不會(huì)發(fā)生大規(guī)模的數(shù)據(jù)遷移。缺點(diǎn)是:一致性hash方式在增加節(jié)點(diǎn)的時(shí)候,只能分?jǐn)傄粋€(gè)已存在節(jié)點(diǎn)的壓力;同樣,在其中一個(gè)節(jié)點(diǎn)掛掉的時(shí)候,該節(jié)點(diǎn)的壓力也會(huì)被全部轉(zhuǎn)移到下一個(gè)節(jié)點(diǎn)。我們希望的是“一方有難,八方支援”,因此需要在增刪節(jié)點(diǎn)的時(shí)候,已存在的所有節(jié)點(diǎn)都能參與響應(yīng),達(dá)到新的均衡狀態(tài)。在實(shí)際工程中,一般會(huì)引入虛擬節(jié)點(diǎn),即讓一個(gè)物理節(jié)點(diǎn)管理多個(gè)虛擬節(jié)點(diǎn),虛擬節(jié)點(diǎn)入環(huán)。這樣在物理節(jié)點(diǎn)失效的時(shí)候,可以有多個(gè)節(jié)點(diǎn)來分配這個(gè)失效節(jié)點(diǎn)原本持有的虛擬節(jié)點(diǎn),不過這也帶來了不好管理分配的壞處。
? ??range based:按照關(guān)鍵值劃分成不同的區(qū)間,每個(gè)物理節(jié)點(diǎn)負(fù)責(zé)一個(gè)或者多個(gè)區(qū)間。其實(shí)這種方式跟一致性hash有點(diǎn)像,可以理解為物理節(jié)點(diǎn)在hash環(huán)上的位置是動(dòng)態(tài)變化的。區(qū)間的大小不是固定的,每個(gè)數(shù)據(jù)區(qū)間的數(shù)據(jù)量與區(qū)間的大小沒有關(guān)系,但是與區(qū)間的數(shù)量有關(guān)系,當(dāng)一個(gè)區(qū)間的數(shù)據(jù)量達(dá)到一個(gè)閾值的時(shí)候,區(qū)間會(huì)變成兩個(gè)。如果一個(gè)節(jié)點(diǎn)負(fù)責(zé)的數(shù)據(jù)只有一個(gè)區(qū)間,range based與沒有虛擬節(jié)點(diǎn)概念的一致性hash很類似;如果一個(gè)節(jié)點(diǎn)負(fù)責(zé)多個(gè)區(qū)間,range based與有虛擬節(jié)點(diǎn)概念的一致性hash很類似。
? ? 分片特征值的選擇,對(duì)數(shù)據(jù)的分片是基于關(guān)鍵值、特征值的。選擇特征值需要基于最常用的訪問模式,即通過什么訪問的就是通過什么當(dāng)特征值。有時(shí)候還需要用到“聯(lián)合特征值”等多重屬性來當(dāng)特征值。主要還是要根據(jù)系統(tǒng)的設(shè)計(jì)來選擇。
? ? 元數(shù)據(jù)服務(wù)器,記錄數(shù)據(jù)與節(jié)點(diǎn)的映射關(guān)系、節(jié)點(diǎn)狀態(tài)等等元數(shù)據(jù)的服務(wù)器。如master、namenode等。元數(shù)據(jù)服務(wù)器需要達(dá)到高性能,高可用兩個(gè)目標(biāo),以應(yīng)對(duì)元數(shù)據(jù)的增長。元數(shù)據(jù)需要有多個(gè)備份,并且能夠在故障的時(shí)候迅速切換。這時(shí)候就要保證數(shù)據(jù)的一致性了??梢允褂弥鲝耐?,以主服務(wù)器的日志為標(biāo)準(zhǔn);也可以使用分布式一致性算法如PBFT或Paxos協(xié)議或Raft協(xié)議等等來實(shí)現(xiàn)強(qiáng)一致性了。
? ? 為了緩解每次數(shù)據(jù)請(qǐng)求對(duì)元數(shù)據(jù)服務(wù)器的壓力,一般會(huì)在訪問節(jié)點(diǎn)上做緩存,這時(shí)候就要確保緩存的元數(shù)據(jù)與元數(shù)據(jù)服務(wù)器上的元數(shù)據(jù)是一致的,這里使用到的常見技術(shù)是使用版本號(hào),即請(qǐng)求的時(shí)候帶上版本號(hào),路由到具體存儲(chǔ)數(shù)據(jù)的節(jié)點(diǎn)的時(shí)候,比較版本號(hào),如果不一致就要從元數(shù)據(jù)服務(wù)器中重新拉取元數(shù)據(jù)并緩存。
? ? 還有一種保證緩存強(qiáng)一致的方法就是lease機(jī)制,其實(shí)就是當(dāng)元數(shù)據(jù)服務(wù)器發(fā)給緩存節(jié)點(diǎn)數(shù)據(jù)的時(shí)候附帶一個(gè)lease,這個(gè)lease包含一個(gè)有限期,服務(wù)器保證在這個(gè)有限期內(nèi)數(shù)據(jù)不會(huì)發(fā)生變化,如果服務(wù)器在lease期間遇到外部修改請(qǐng)求就會(huì)阻塞這個(gè)修改,直到lease過期后才會(huì)修改數(shù)據(jù),并將新的數(shù)據(jù)和lease發(fā)送給節(jié)點(diǎn)。此機(jī)制需要克服一個(gè)服務(wù)器和節(jié)點(diǎn)時(shí)間不一致的問題,服務(wù)器時(shí)間過慢會(huì)使lease發(fā)揮不了作用,而過快會(huì)有潛藏的危險(xiǎn),工程中一般會(huì)將服務(wù)器的過期時(shí)間設(shè)置得比節(jié)點(diǎn)得到的過期時(shí)間略大來解決問題,當(dāng)然為了保持一致性最好的方法就是使用NTP(Network Time Protocol)來保證時(shí)間同步。
? ? 上面說了數(shù)據(jù)分片,為了達(dá)到動(dòng)態(tài)均衡,進(jìn)行數(shù)據(jù)的遷移是必要的,如何保證在遷移的過程中保持對(duì)外提供服務(wù),這也是一個(gè)需要精心設(shè)計(jì)的復(fù)雜問題。
可用性
? ??可用性(Availability)是系統(tǒng)不間斷對(duì)外提供服務(wù)的能力,可用性是一個(gè)度的問題,最高目標(biāo)就是7 * 24,即永遠(yuǎn)在線。但事實(shí)上做不到的,一般是用幾個(gè)9來衡量系統(tǒng)的可用性,也就是如果要達(dá)到4個(gè)9的可用度(99.99%),那么一年之中只能有52.6分鐘不可用,這是個(gè)巨大的挑戰(zhàn)。
? ? 之所以說要考慮可用性是因?yàn)榉植际较到y(tǒng)故障概率非常高,所以分布式系統(tǒng)其中一個(gè)設(shè)計(jì)目標(biāo)就是容錯(cuò),在一定的故障情況下,分布式系統(tǒng)還可以提供服務(wù),這就是系統(tǒng)的可用性。
? ? 冗余可以提高分布式系統(tǒng)的可用性。就是說多個(gè)節(jié)點(diǎn)負(fù)責(zé)相同的任務(wù),這在分布式存儲(chǔ)中使用非常廣泛,維護(hù)同一份數(shù)據(jù)的多個(gè)節(jié)點(diǎn)稱之為多個(gè)副本。我們考慮一個(gè)問題,當(dāng)向這個(gè)副本集寫入數(shù)據(jù)的時(shí)候,怎么保證并發(fā)情況下數(shù)據(jù)的一致性,是否有一個(gè)節(jié)點(diǎn)有決定更新的順序,這就是中心化、去中心話副本協(xié)議的區(qū)別。
? ? 中心化副本協(xié)議中分為同步模式和異步模式,所謂同步(Synchronous?replication),就是說對(duì)于客戶端請(qǐng)求,系統(tǒng)阻塞到復(fù)制集中所有節(jié)點(diǎn)都更新完成,才能向客戶端返回,即write all。而異步(Asynchronous?replication)模式,只要一個(gè)或者部分節(jié)點(diǎn)更新則算寫入操作成功,通常是write one。兩種模式各有各的優(yōu)劣,在數(shù)據(jù)同步的時(shí)候選擇同步模式還是異步模式呢,這個(gè)取決于系統(tǒng)對(duì)一致性、可用性、響應(yīng)延遲的要求。
? ? 中心化副本協(xié)議的數(shù)據(jù)流向分為鏈?zhǔn)胶椭鲝哪J?,鏈?zhǔn)骄褪侵笍囊粋€(gè)節(jié)點(diǎn)推送到最近的節(jié)點(diǎn),比如GFS,“最近” 可以用IP地址或者節(jié)點(diǎn)間心跳TTL來衡量,優(yōu)點(diǎn)是充分利用網(wǎng)絡(luò)帶寬,減輕primary壓力,但缺點(diǎn)是寫入延遲會(huì)大一些。主從模式則是指數(shù)據(jù)同時(shí)從primary節(jié)點(diǎn)到secondary節(jié)點(diǎn),在主從模式下,Secondary會(huì)從Primary拉取OPLOG并應(yīng)用到本地。顯然,在這種模式下Primary節(jié)點(diǎn)的帶寬壓力比較大,但是寫入延遲會(huì)小一些。
? ??理論上,副本集中的多個(gè)節(jié)點(diǎn)的數(shù)據(jù)應(yīng)該保持一致,因此多個(gè)數(shù)據(jù)的寫入理論上應(yīng)該是一個(gè)事務(wù):要么都發(fā)生,要么都不發(fā)生。但是分布式事務(wù)(如2pc)是一個(gè)復(fù)雜的、低效的過程,因此副本集的更新一般都是best effort 1pc,如果失敗,則重試,或者告訴應(yīng)用自行處理。
? ? 而選舉出primary節(jié)點(diǎn)的方法也有兩種,一種是由內(nèi)部節(jié)點(diǎn)自行投票,一種是通過其它組件來任命產(chǎn)生。
一致性

? ??從上面可以看到,為了高可用性,引入了冗余(副本)機(jī)制,而副本機(jī)制就帶來了一致性問題。當(dāng)然,如果沒有冗余機(jī)制,或者不是數(shù)據(jù)(狀態(tài))的冗余,那么不會(huì)出現(xiàn)一致性問題,比如MapReduce。一致性與可用性在分布式系統(tǒng)中的關(guān)系,已經(jīng)有足夠的研究,形成了CAP理論。CAP定理就是說分布式數(shù)據(jù)存儲(chǔ),最多只能同時(shí)滿足一致性(C,Consistency)、可用性(A,?Availability)、分區(qū)容錯(cuò)性(P,Partition?Tolerance)中的兩者。
? ??一致性從系統(tǒng)的角度和用戶的角度有不同的等級(jí)。系統(tǒng)角度的一致性有:強(qiáng)一致性、弱一致性、最終一致性。用戶角度的一致性有單調(diào)讀一致性,單調(diào)寫一致性,讀后寫一致性,寫后讀一致性。
? ? 這里順便講一個(gè)之前在鏈聞上看到的關(guān)于終結(jié)性的概念(來自:一文理解區(qū)塊鏈共識(shí)機(jī)制的終結(jié)性),這是關(guān)于區(qū)塊鏈的一個(gè)概念,終結(jié)性「finality」是指一旦提交到區(qū)塊鏈,所有格式正確的區(qū)塊都不會(huì)被撤銷。當(dāng)用戶進(jìn)行交易時(shí),他們希望一旦其交易通過,交易就不會(huì)被任意更改或回滾。因此,在設(shè)計(jì)區(qū)塊鏈共識(shí)協(xié)議時(shí),終結(jié)性就顯得至關(guān)重要。終結(jié)性可分為概率終結(jié)性,即交易不被回滾的概率很大,在比特幣區(qū)塊鏈上,一個(gè)交易其實(shí)要等到六個(gè)區(qū)塊后才確認(rèn)其真實(shí)性,這就保證了回滾可能性很低;還可以分為絕對(duì)終結(jié)性,是指基于實(shí)用拜占庭容錯(cuò) PBFT 的協(xié)議提供的終結(jié)性,交易一旦包含在區(qū)塊中并添加到區(qū)塊鏈上,就會(huì)立即被認(rèn)為已經(jīng)最終完成;還有一種經(jīng)濟(jì)終結(jié)性,這種概念中,一個(gè)區(qū)塊的回滾成本會(huì)非常高昂。
? ??雖然看起來絕對(duì)終結(jié)性比概率上的終結(jié)性更可取,但是由于存在CAP定理,在進(jìn)行挑選時(shí),仍然存在一些基本的權(quán)衡。由于在分區(qū)的情況下系統(tǒng)必須滿足分區(qū)容錯(cuò)性,那么區(qū)塊鏈要么保留一致性,要呢保留可用性。保留一致性的系統(tǒng)寧可中止,也不會(huì)允許不準(zhǔn)確的交易通過。而保留可用性的系統(tǒng)會(huì)允許不準(zhǔn)確的交易通過,自身也會(huì)繼續(xù)存在。偏好一致性的系統(tǒng)提供拜占庭容錯(cuò)終結(jié)性,而偏好可用性的系統(tǒng)提供概率上的終結(jié)性。,

高性能
? ? 分布式系統(tǒng)的理想目標(biāo)是任務(wù)與節(jié)點(diǎn)按一定的比例線性增長。這就需要系統(tǒng)滿足高并發(fā)、高吞吐量、低延遲的指標(biāo),但是不同的系統(tǒng)關(guān)注的核心指標(biāo)不一樣,比如MapReduce,本身就是離線計(jì)算,無需低延遲。要滿足這三大指標(biāo)可行的辦法有:單個(gè)節(jié)點(diǎn)的scaleup、分片(partition)、緩存:比如元數(shù)據(jù)、短事務(wù)等等。
一個(gè)簡化的架構(gòu)圖

概念與實(shí)現(xiàn)
負(fù)載均衡:
Nginx:高性能、高并發(fā)的web服務(wù)器;功能包括負(fù)載均衡、反向代理、靜態(tài)內(nèi)容緩存、訪問控制;工作在應(yīng)用層
LVS: Linux virtual server,基于集群技術(shù)和Linux操作系統(tǒng)實(shí)現(xiàn)一個(gè)高性能、高可用的服務(wù)器;工作在網(wǎng)絡(luò)層
webserver:
Java:Tomcat,Apache,Jboss
Python:gunicorn、uwsgi、twisted、webpy、tornado
service:
SOA、微服務(wù)、spring boot,django
容器:
docker,kubernetes
cache:
memcache、redis等
協(xié)調(diào)中心:
zookeeper、etcd等
zookeeper使用了Paxos協(xié)議Paxos是強(qiáng)一致性,高可用的去中心化分布式。zookeeper的使用場景非常廣泛,之后細(xì)講。
rpc框架:
grpc、dubbo、brpc
dubbo是阿里開源的Java語言開發(fā)的高性能RPC框架,在阿里系的諸多架構(gòu)中,都使用了dubbo + spring boot
消息隊(duì)列:
kafka、rabbitMQ、rocketMQ、QSP
消息隊(duì)列的應(yīng)用場景:異步處理、應(yīng)用解耦、流量削鋒和消息通訊
實(shí)時(shí)數(shù)據(jù)平臺(tái):
storm、akka
離線數(shù)據(jù)平臺(tái):
hadoop、spark
PS: apark、akka、kafka都是scala語言寫的,看到這個(gè)語言還是很牛逼的
dbproxy:
cobar也是阿里開源的,在阿里系中使用也非常廣泛,是關(guān)系型數(shù)據(jù)庫的sharding + replica 代理
db:
mysql、oracle、MongoDB、HBase
搜索:
elasticsearch、solr
日志:
rsyslog、elk、flume