1. 程式人生 > >坑:高可用架構的銀彈

坑:高可用架構的銀彈

伯樂線上小編注:本文是作者的舊文


呵呵,題圖是一隊困在坑中的鴨子:)作為一個搬磚的,我經常被困著。今天高考,想起15年前的今天(哦,那時候是七月高考),恩,考完了,還不錯,然而15年後還是搬磚:)

0. 承上啟下

之前那篇文章寫出來以後我就覺得會有很多不同的意見,哈哈,那隻代表我個人的意見啊,歡迎討論。

先說說之前那一篇,我舉例子舉的OA系統,並不是說OA一定要這麼設計,只是一種誇張的手法,為了說明後面的完全脫離了業務場景來進行技術架構的設計就是過度設計,並不是說OA系統太簡單所以不能這麼設計,另外,寫PHP效率低也只是打個比方,並非貶低全世界最好的語言,很多人拿這兩個來噴,實在沒必要。

1. 迷信架構可以解決高可用,但並沒有銀彈

高可用,我知道一旦帶上這個詞,不管寫什麼都會有人有不同意見,我說說我認為的高可用下的坑吧。

我想很多人理解的高可用就是單臺機器掛掉了整個服務不會掛掉,所以寫程式碼的時候使用叢集的思想去寫程式碼,比如做成無狀態的服務,保證在叢集使用的時候無狀態,單機故障不影響服務,從而達到高可用的效果。

由這種思想搭建起來的系統很可能長成下面這個樣子,我想很多人都看到過這種架構模式吧。

首先,這種架構模式本身並沒什麼問題,而且也確實很好,有服務發現,有叢集,單臺機器掛掉了還有其他機器可使用,在搜尋系統,推薦系統,廣告系統,網站後臺系統中都在大量使用。

很多人接收到的資訊是有了上圖的那種架構,那麼這個系統就變成了一個高可用的系統了,覺得這種架構模式就是高可用

的一顆銀彈了。

但實際上,上圖的系統解決的主要是下面的兩個問題。

  • 資料同步,主要是公共配置這種少量資料的在各個機器間的同步。
  • 服務發現,新增或者減少機器以後,讓其他機器能感知得到有新節點加入或者有老節點下線了。

除了上面兩個問題以外,最後才是解決所謂的高可用的問題,這裡用了所謂兩個字,因為我覺得高可用這種東西不是一個架構的模式能解決的,一個高可用的系統是程式碼級別解決的,不是靠幾個開源模組能解決的。

有些人總認為高可用系統有銀彈,在各種論壇,會議上看到各種架構,而且基本上都用到了一些成熟的開源軟體,所以覺得有了這些以後就可以是一個高可用的系統了,我有zookeeper,那麼服務單機掛了,服務照常跑,但實際上然並卵,zookeeper解決的是外部不可控因素導致的機器掛了,比如機器硬碟壞了,網路斷了,這種因素導致的服務掛了,zookeeper能解決,你程式碼出問題導致機器掛了,zookeeper下掛1000臺機器也解決不了啊,一般情況下還是一掛全掛。

比如一個分散式的搜尋系統,索引分片了,所以有個叢集,有50臺機器,每個分片大概10臺機器,並且機器可以動態增加減少,叢集用zookeeper管理,這算高可用系統嗎?這可是一個標準的搜尋系統的高可用架構,也只能說,在程式碼優秀的前提下,這個系統高可用了,網路問題和機器硬體問題已經比較難搞掛整個叢集了。但一旦程式碼有個小bug,或者索引資料生成的時候出現了點問題,一般情況下,叢集就全掛了,談何高可用。

高可用沒有銀彈,你在各處看到的,聽到的,學習到的各種高可用架構,他們只會告訴你這個系統架構多麼牛逼,用幾個框框框住某幾個模組,然後告訴你,這個框框裡的服務各種突發情況都能自適應,流量洪峰來了線性加機器就能解決,對你來說卻是然並卵,他們沒有告訴你他們的程式碼有多牛逼,並且只有在這個前提下才高可用的,想純粹靠幾個框框來架構出一個高可用的系統,那是PPT架構師。

真正的高可用不用糾結架構設計,只需要程式碼的健壯,健壯的程式碼加上主備系統設計,不需要其他的,基本上就是一個高可用的系統了,銀行的核心資料處理中心加上異地災備就是這樣子的,你敢說他不是高可用的?

所以,寫好程式碼吧,才能高可用,學習架構,更多的只是對提高系統全域性性認識的一種補充,高可用的架構不存在,存在的只有高可用的程式碼

2. 一個栗子

我前段時間看到過這樣一個系統,這是一個O2O的創業公司的後臺的一個模組,主要功能是給剛開啟APP的使用者提供一個個性化的推薦頁面,外部接入了一些其他系統產生的一些資料。

資料從其他系統推過來以後,先是接入到一個kafka的訊息佇列,資料進來了以後有一個服務的叢集獲取這個資料,不同的服務通過kafka不同的topic獲取,然後二次加工這些資料,生成一個結構化的個性化資料,把生成的資料存到redis叢集中,每個APP使用者對應redis中一個key,前面的APP呼叫API以後,直接從redis叢集中獲取資料返回,這些個叢集都用zookeeper管理的。

這麼架構出來,訊息佇列是為了解決第三方資料推送太猛,做快取用的,而redis叢集其實是為了解決前端APP的高併發訪問的。

我先問了一下,訊息佇列這個叢集在其他系統模組也在用,這沒問題,大家都要用嘛,部署一個叢集也很應該哈。

但是這個redis叢集只有這裡在用,這裡我覺得有點問題了,有必要做個帶zookeeper的叢集嗎?只是為了開啟APP的個性化頁面,用個redis叢集?不是大家共用資源的話,我覺得完全沒必要redis叢集,一主一備足矣,還容易維護。如果你覺得單機記憶體不夠大,可以用redis2.0,開啟VM功能,突破實體記憶體的限制,redis還能自己在記憶體保持熱點資料。

你說這樣是為了解決高併發下的高可用,如果redis掛了,還能自動切換,這麼說吧,我覺得一個系統中,排除硬體故障的問題,一般情況下,等你的服務全掛光了,redis也還堅挺著。並且redis的併發能力簡直只能用恐怖來形容,單機2,3萬的QPS(資料大小2,3kb左右)完全沒什麼問題,一個創業公司的日活使用者量一般情況下也沒必要用叢集去抗併發吧?

後來,我建議他們把redis叢集幹掉,換成單機主備的,而且我發現所謂的個性化推薦其實大部分人看到的頁面是一樣的,這也很好理解,初期沒資料的情況下,個性化推薦出來的東西也不夠豐富,redis叢集的記憶體使用率其實很低,於是我進一步建議他們用nginx+lua的本地字典來快取最熱的資料,後面掛個redis,變成一個三級快取(redis本地磁碟,redis記憶體,nginx本地字典)。如果真的業務量上來了,換成redis叢集也很容易,現在就沒必要浪費機器資源了,畢竟創業公司嘛。

恩,最後他們衝我投來鄙夷的目光,這架構,人家看不上,萬一突然一天使用者量暴增怎麼辦,而且最關鍵的是人家不差錢,好吧,呵呵。

3. 高可用的銀彈在哪?

瞎扯了這麼多,有沒有高可用的銀彈呢?恩,優秀的程式碼就是一切高可用架構的基石和銀彈,優秀的程式碼加上合理的架構就是高可用的架構,一個高可用的架構不是靠開源軟體搭積木來得到的,成熟的開源軟體解決的是把一部分本應該你寫的程式碼變得更優秀。

好吧,歡迎大家繼續討論:)