乾貨|建議初創團隊起初也要構建分佈式應用前端
本文內容整理自W-Time技術分享沙龍-天津站現場演講《一切都是分佈的》,演講者:李傲,問啊聯合創始人,前中交車聯網總架構。redis
好多人都會問什麼是架構師?其實架構師的定義很寬泛,前端後端的定義都不同。做爲後端出身的架構師,我認爲後端並非你們想的封裝組件,它要定義的是規劃,規劃模塊以前的關係。在一臺機器搞不定時怎麼辦?答:集羣!這詞說着很容易,但真要給你,你發現how?怎麼去加?算法
有人問我,架構師要作什麼?我認爲,架構師就是要在軟件起初階段就可以從情景當中預先想到這問題,經過架構分佈式解決方案,預先把問題都埋好。可能有人會說這算不算重度設計?其實所謂重度設計,要看團隊的基本能力,若是團隊寫代碼還寫不利索的狀況下,那麼這個設計就很重要。由於不能期望一個代碼都沒有寫過幾行的人去寫架構,這個是不可能的,作分佈式都很難。若是團隊能力屬於中上層,那麼有兩種可能:一、團隊作過十幾年的代碼,但架構差一些,那麼也會把程序寫的很是漂亮,由於對代碼有把控能力,對底層的研究比較透徹;二、代碼寫的並非很好,可是架構師對新技術有了解,那麼也是有可能作好分佈式的。若是你的團隊作不到以上這些,那只有一種方法——用服務器抗。但服務器是一回事,團隊能力也不能太差。sql
下面就咱們「問啊」來講給你們作一下簡單的分享,「問啊」是一款訂製化IT教育平臺,能夠一鍵呼叫大牛解決IT 問題。數據庫
關於分佈式存儲後端
「問啊」利用了一些分佈式的概念,也就是分佈式存儲。咱們都知道,每一臺服務器資源佔用都是有限的,咱們用的是雲服務器,通常上來都會去買本地磁盤,但不管容量多大,總有一天會用完,當這一天到來的時候,有兩種可能:一、在你不知道的時候,服務死了,怎麼也起不來。可能會不運行、cpu太高,有人會問,這什麼緣由致使的?計算量太大了?其實不是,由於一直在作無謂的io操做;二、無從下手,有個公司叫emc的作的磁盤能夠解決,但是太貴,300萬左右的價格初創公司老闆確定不批,並且性能也不能保證。緩存
可是分佈式存儲就把這個事解決了,將要存儲的文件預先就散出去,而不是放在一個地方。拿的時候就很快的知道在哪了。舉個例子,就像你們都有房子,每一個房子都有地址,這個地址都是預先規劃好的,就跟分佈式存儲同樣,在規劃的時候就解決了將來若是數據膨脹會怎麼樣的問題。服務器
關於高速緩存數據結構
接下來再說高速緩存,這也是一個分佈式緩存的概念,對存儲和緩存來說,在算法的選擇上是不同的,數據分爲兩種,維度數據和事實數據。維度數據能夠理解爲是一種屬性,人也是一種維度數據,這個數據是有盡頭的。事實數據就是我出門的時候可能會踩死一隻螞蟻,但我不知道我這一路會踩死多少隻,這就是事實數據。包括廣大的女性同胞養活了淘寶,這也是最好的例子,都是事實數據。多線程
事實數據存儲和維度數據是不同的,你們通常按時間存儲是最多的,這樣數據在取得時候有一些優點——能夠單獨拿一段出來。在數據結構中,拿一段怎麼拿?確定得是連續存儲,這樣對cpu的消耗則是最小的。那維度數據呢,數據量自己就不大,咱們用hash是比較靠譜的。
對於內存和磁盤的存儲來說,磁盤是一個盤片,咱們在尋找一個道的時候,咱們會連續去打,這樣是最快的。由於不會跳針,跳針速度是最慢的。但內存不是,內存是隨機存儲,咱們在利用存儲的時候也會考慮到,若是對於連續存儲來說,內存就必定比磁盤快嗎?在我看來,不必定。
關於任務隊列
我以前作車聯網,包括如今的滴滴打車都是同樣的,你們之因此能打到車,是車的位置信息已經上傳上來了。由於在同一時間內會爆發不少小高峯,致使我存數據的時候很慢,因此我不直接存儲,我先存到另外一層去。爲何要存到另外一層呢?咱們存儲的目的就是爲了要拿出來,簡單的說:存的目的就是拿。其實存和拿是一個悖論,好存很差拿,好拿很差存。舉一個例子,這麼說可能能夠直觀一些。上大學時,放學回宿舍,書包就扔在地上。爲何?由於懶,扔的速度特別快,可是你可能轉天再找就找不到了。問題就出在存儲快可是沒有索引。想要快速查到怎麼辦?那就在存的時候分門別類,細緻存好。這樣拿比較快,存的時候就會費一些時間。如何解決這個悖論?讀寫分離。存和查的時候必定要作分離。軟件有一個理論叫「解偶」,如何解偶?簡單來講,a層和b層之間加一個c層就是解偶。只要你發現兩層之間有一個很緊密的聯繫,你就往裏面加一個。
因此,任務隊列就是這樣,咱們先把東西寫到隊列裏,讓它慢慢的去消費。也就是說你把數據拿到隊列裏面來的時候,我就認爲你存了。等你取得時候,看你的消費水平,消費水平慢,最多就一個感受:這個更新好慢,僅此而已。而後下一步就該研究怎麼把這個消費作快,你是有這個機會的。但若是你這個事兒不這麼作,你就會發現,在你存的時候就已經死了。這樣用戶的感覺可能會有兩種,一個是用戶並不知道,他只會以爲大家公司的數據比較少;二是我知道,大家已經死了。這樣的用戶體驗度是很是很差的。
關於高速查詢
這裏我要講一下咱們查詢的數據結構。對於每種查詢來講,數據結構都不太同樣。如今有一種比較好的既能查又能存的數據結構叫LSM-TREE,就是hbase一個數據結構,你們有興趣能夠看一下。
若是你是一個應用,你可能會發現其實沒有現成的東西能夠用,怎麼辦?那就用最短的時間研發出來一個輕量級的分佈式,像任務下發。這種東西其實比較佔資源,當你的服務器數量不夠龐大,節點數量也不夠龐大的時候,你拿到的結果可能跟你最初的預想不太同樣。
互聯網公司都有個比較難受的事兒,就是作運維不敢動機器。咱們在作「問啊」的時候也沒有徹底作到不停機,這個挺難的。有的時候爲了嘗試試錯,咱們須要作降級指標,其實有時候比升級指標難的多,會丟數據、丟節點,以後數據還可以均攤,這個是挺難的。咱們如今降級指標尚未作到徹底不停機,但升級指標已經可以作到了。其實這就是各類負載均衡,經過負載均衡來代替ha,那麼這兩個概念是什麼概念呢?ha,高可用。負載均衡,就是就是你一我的搞不定,四五我的一塊兒上!ha是什麼?一個活着,另外一個就得死。通常用負載均衡來解決高可用有個問題,就是機器不閒着。通常來說,作機器空閒的話,總有一臺機器是不幹活的,這個對於初創公司來講成本比較高,配置選擇就是個難題。因此各類ha方案通常就是共用,那個節點可能會分攤好多個節點的共用,可是忽然間發現兩個小高峯,兩個死了這個也就算死了。對於loadbalance自己有個很是大的優點,就是自己來說,只要有1/2以上活了,這服務也就認爲是活的,這個是比較好保證的。可是有一點,作lb算法就必定要作到線上的配額必定要高於你目前的配額,不然你是無法作的。
下面分享一下咱們用過得一些東西:
Redis
一個基於內存的存儲。最大優點就是單線程處理的。確定有人問爲何作單線程,很慢的!可是若是你測過的話就會發現,單線程多任務有時候不必定就比多線程多任務慢,多線程多任務有個空閒的概念,交替的概念,我要去調度。這個就徹底省去調度,只要存儲速度特別快,能讓一個線程別空閒了,遠比多線程多任務要快。單線程有一個不可替代的優點:無鎖,能夠作到一致性。多線程自己來說只要併發對一個數據操做的時候,你就必須得加鎖。你的鎖若是設計不合理的話,你這個數據原本能夠加到5的,結果才加到2就沒了。
若是用redis徹底不用考慮這些事。包括咱們作訂單號的話,單號取一個數,這是個最普通業務。咱們對單號+1就會考慮一個線程去作,若是能夠搞定的話,那速度就快了,那我爲何要去作多線程?那麼作多線程有一個方法,你能夠先把訂單號切割,就是預計今年的訂單號能有多少,你先把他分好了。而後每個進程怎麼樣操做,這樣不會出問題。可是訂單是跳躍,永遠不要用訂單號去作排序,這是最不合理的。就像你們都玩過搖紅包,其實都是同樣的,搖紅包爲何能作到這麼快。其實不可能快,這個事情不是一個快的動做,有交互就不可能快。只能先把交互的紅包預先切好了,存在緩存裏。甚至最狠的是用一些空池,就是沒獎。結果你的ip正好打到這一核了,hash到這一核裏。不換ip拿不出來。
Redis自己來說,它的存儲速度包括查詢速度是能夠上到10萬級的,是很是快的。可是咱們線上測的話。可能也是由於咱們用的是雲平臺的一個服務,它自己是基於codis作的分佈式服務。咱們沒有時間去作本身的分佈式redis,因此codis已經成爲咱們的瓶頸了。它大概的速度也就是1w,對於剛起步的應用來講應該夠用,那如何作到更快,只有一個方法:當你對一個事兒作到不能更快了,就三個字解決:分佈式。這樣就確定能解決,下一步再去琢磨這一個事該怎麼解決,這個就更高深了,有機會我會再詳細的爲你們講解。
Hbase
有人說Hbase是大數據,其實我以爲很詫異,我認爲大數據更偏重於分析。這個東西自己就是一個nosql ,爲何要放到大數據呢?也許由於存的數據多?
一開始起步的時候是三個節點,這算大數據嗎?這算是實驗。其實不是,它就是一個數據庫,你們不要對它有偏見,認爲非要數據到多少的時候我把它遷過來,記住,數據量大的那天,你再想遷就遷不過來了。個人經驗告訴我,重構能夠作局部模塊重構,但絕對不能作大遷移。只要作大遷移:丟數據、版本覈對,動態版本覈對,特別頭疼。
我最怕跳槽,由於個人位置是救火的。經驗告訴我這個最好提早設計好。由於到那天了你難受,有兩方都不滿意:第一,用戶那裏,一直在用,你就得每天看着,怎麼還有用戶用?不知道該用高興仍是該不用高興;第二,產品經理、運營就會使勁催你問你好了嗎?可是提早規劃好,就能夠避開這些問題。
Hbase自己來說呢,既然它能存這麼多數據,咱們也不想太浪費。有兩套出報表的方案,一套是你們熟知的spark,可能用的比較多。對於一個初創團隊來說,spake自己它的worker節點配置有點高,由於它專門吃內存的。還有一種。Tkeyang24:06,替代hadoop,可是它自己沒有計算模塊,你仍是上s,逃不過去。咱們的方案呢,做爲一個初創團隊來說,對於運營這一塊可能有點殘忍,可是沒有辦法,沒有這麼大的數據量,沒有必要。
那麼插入數據方案呢,就兩個:
一、經過集成phoenix序列化方法使用原生Hbase API插入更新數據,數據裝載速率並無下降;
二、插入數據時採用雙保證,緩存和hbase均須要徹底插入成功,不然記錄日誌進入修復隊列異步保證數據同步。
高速緩存
關於高速緩存,剛剛有說過, redis最好的方案就是hash。這裏說兩個應用,Redis自己有個pub/sub,作數據隊列的,並列時隊列比較麻煩的是,若是想用它作一對一隊列,你是作不了的,其實一對一有不少隊列。可是做爲初創團隊不必,那如何來解決這個問題呢?很簡單。咱們分佈式裏,分三個redis,我這一個應用先用三個redis,寫數據的時候我在三個裏面作shard,你這一個應用shard這三個,那這一個應用就能夠把這三個歸過來我用,若是兩個應用怎麼辦?有兩種方法,一種方法從k上,我監控不一樣的shard的隊列,a監控a隊列,b監控b隊列,每一個人都監控三個,沒問題,但還有一個問題,redis自己來說,提供一個key失效的概念,緩存必定會有時效時間,可是緩存失效以後,他所定義的隊列的名字是寫死的。是跟十六庫綁定的,咱們能夠切16個做爲拓展。若是十六不夠的話,切兩組做爲拓展,這樣的話就能夠無限的擴大。B監聽b的零號庫。這樣能夠無限的擴大這樣能夠經過闊機器,來提高一我的的消費能力。另外一方面經過縱深,來分散消費能力。
關於Redis2.8.22,可能用的比較多。3.0和3.2用的並很少。這有個毛病,TTL只要move一次庫,這個TTL就廢了,就是失效時間。原本是想用什麼巧妙的方法來作黑科技的,結果發現2.8.23解決了,因此你們用的時候從2.8.23以上用。
咱們在任務隊列主要作的事是,咱們應用有個紅包的概念,爲了讓你們都有學習的機會,可以去問問題,因此咱們有個紅包。若是用分佈式的話,會有不少坑就能夠繞過去了。
Pub/sub,有一個比較噁心的事,當你消費的時候,若是消費函數,你沒有消費下一條的時候,pub/sub是不日後挪數據的,因此他會大量的堆積在redis裏出不來,這個必定要注意。
我推薦一個工具,如今有很多公司都在用這個:ES。這個仍是比較好用的,可是如今有個問題:隨機函數。它裏面能夠隨機抽量數據,在隨機抽量數據的時候咱們發現兩個坑,一、散不開,大部分都同樣,隨機不太好;二、隨機速度特別慢,100w就開始特別慢了。作抽量的話,其實還有不少能夠試一下。
關於咱們自主研發的,主要就是如下這幾點:一、針對服務節點運行數據決定任務的下發;二、任務之間沒有任何牽扯;三、任務死亡能夠實時分裂新任務繼續執行;四、支持定時消息及紅包的應用。
我發現不少人有個誤區,不寫代碼就真的省事嗎?我以爲吧,不寫代碼知足需求最省事,用現成的有時候還不如本身寫,有什麼問題也好找。
關於不停機運維
Zookeeper這個東西挺好的。我如今註冊一些服務,馬上就會建上臨時的連接,臨時文件。比較坑人的地方就是它的存儲是限量的。每一個節點存儲都同樣。必定要注意,存儲要省着使用,別寫進數據,不要用它作分佈式事務所。Zabbix挺好用的,咱們運維如今就使用這個。