坑系列 —— 緩存 + 哈希 = 高併發?

今天繼續坑系列,高可用已經講過了,當前互聯網時代,怎麼少的了高併發呢?高併發高可用同樣, 已經變成各個系統的標配了,若是你的系統QPS沒有個大幾千上萬,都很差意思跟人打招呼,雖然可能天天的調用量不超過100。前端

高併發這個詞,我我的感受是從電商領域開始往外流傳的,特別是電商領域雙11那種藐視全球的流量,再把技術架構出來分享一把,如今搞得全互聯網都在說高併發,並且你注意回憶一下全部你看到的高併發系統,每每都逃不開一個核心概念,那就是緩存+哈希,一切都是以這個概念和基礎的,彷彿這就是高併發的核心技術了。`面試

咱們看到的高併發技術

圍繞這個核心技術,一般咱們看到的各類高併發的架構系統,在博客,論壇,現場分享出來的高併發系統,都跑不出如下幾個方面的東西。redis

資源靜態化

就是那種單個頁面流量巨大無比,每秒的QPS幾十萬上百萬的系統,確實併發高的系統,核心解決方案就是靜態化,靠機器和帶寬去抗,假如沒有CDN的話,全部流量都落到同一個IP下面的話,基本上也就是用Nginx的文件靜態化了,單機的承受能力主要取決於帶寬和單機的性能,要再多的話,那就LVS(或者F5)+集羣了,這種的典型場景就是搞活動時候的首頁,活動頁面了,還有就是引流搜索引擎的着陸頁了,通常都是現成的圖片和文字靜態化,固然,這種還有不少前端的技巧和技術了,這一點我不是很瞭解,就不得瑟了,就中後臺來講,大部分狀況下直接Nginx搞定了,核心仍是使用了緩存技術算法

讀寫分離和分庫分表

讀寫分離是你們看到的第二個高併發的架構了,也很常規,由於通常狀況下讀比寫要多得多,因此數據庫的主庫寫,從庫們提供讀操做,一下就把數據庫的併發性能提升了。數據庫

若是還不夠,那麼分庫分表把,把數據分到各個數據庫的各個機器上,進一步的減小單臺機器的壓力,從而達到高併發的目的。編程

若是是分庫分表,有時候使用的就是哈希技術了,以某個字段哈希一下而後來分庫分表,讀寫分離的讀操做,基本也是經過哈希技術把讀落到不一樣的機器上去減輕單機壓力。後端

萬能的緩存

說到高併發,不得不說緩存了,如今各類緩存的工具也不少也很成熟,memcache,redis之類的KV數據庫做爲緩存已經很是成熟了,並且基本上均可以集羣化部署,操做起來也很簡單,簡直變成了一個高併發的代言詞了,核心就是緩存技術了,而memcacheredis只是用來實現這個緩存技術的工具而已。緩存

無敵的哈希

但凡大數據處理,高併發系統,必言哈希,隨機插入,時間複雜度O(1),隨便查詢,時間複雜度O(1),除了耗費點空間之外,幾乎沒什麼缺點了,在如今這個內存廉價的時代,哈希表變成了一個高併發系統的標配。性能優化

正面的例子

咱們來看個例子,看看一些個你們眼中標準的高併發系統的設計,這些設計你們應該都看過,無非就是上面的幾個要點,最重要的就是緩存+哈希,這兩個東西的組合好像無所不能。微信

活動秒殺頁面

活動秒殺頁面,這是個標準的高併發吧,到了搞活動的那個時刻,單頁面的訪問量是天量數據了,但這種系統有個特色邏輯簡單,只要帶寬和性可以,就必定能提供穩定的服務 服務能迅速的返回數據便可,沒有什麼計算邏輯,這種高併發系統的設計基本上就是在怎麼壓榨機器的IO性能了,若是有CDN絕對使用CDN,能在本機讀取的毫不走網絡獲取,能讀取到內存中毫不放在硬盤上,把系統的磁盤IO和網絡IO都儘量的壓榨,使用緩存+哈希技術,只要設計合理,99%的狀況能搞定。

活動頁面的衝擊感實在太強,想象一下幾千萬人同時訪問網站尚未掛,讓不少人以爲高併發應該就是這樣子,這估計也是高併發此次常常在電商技術中出現的緣由吧,由於搞個活動就能夠搞出一個高併發事件。

這樣的場景再擴展一點,就是凡是能提早提供數據的併發訪問,就能夠用緩存+哈希來搞定併發。

12306

接下來,咱們再看看這個星球併發量最瘋狂的網站,瞬間的訪問量碾壓其餘網站的12306,這種場景下的高併發也有個特色,那就是雖然量大,但其實沒法給每一個用戶提供服務

相似的其實還有商品的搶購系統,商品和車票一共就1000張,你100萬的人搶,你係統作得再好,也沒法給100萬人提供服務,以前12306剛剛上線的時候不少人噴,說若是讓某某公司來作確定能作好,但你們不少只看到了表面,讓某很厲害的公司來作,最多也只能作到你們訪問的時候不會掛掉,你買不到車票仍是買不到,並且如今的12306體驗也已經作得很好了,也不卡了,可是仍是不少人罵,爲何?還不是由於買不到票。

對於這樣的系統,設計關注的就不只僅是提升性能了,由於性能瓶頸已經擺在那了,就1000張票,作得更多的是分流和限流了,除了緩存+哈希來保證用戶體驗之外,出現了奇葩驗證碼,各個站點分時間點放票。而後經過排隊系統來以一種異步的方式提供最終的服務。

咱們給這樣的場景再擴展一下,凡是不能提早提供數據的,能夠經過緩存+哈希來提升用戶體驗,而後經過異步方式來提供服務。

高併發系統如何設計

若是把上面兩個場景的狀況合併一下,彷彿緩存+哈希變成萬能的了,不少人眼中的高併發就是上面的場景的組合,認爲緩存+哈希就能夠解決高併發的問題,其餘的場景中,加上緩存提升讀寫速度,在加上哈希提供分流技術,再經過一個異步提供最終服務,高併發就這麼搞定了,但其實是不是這樣呢?顯然沒那麼簡單,那如何來設計一個高併發的系統呢?

合理的數據結構

舉個例子來講吧,搜索提示功能你們都知道吧,就是下面這個圖的東西。

若是是google,baidu這種大型搜索系統,或者京東淘寶這種電商系統,搜索提示的調用量是搜索服務自己調用量的幾倍,由於你每輸入一個鍵盤,就要調用一次搜索提示服務,這算得上是個標準的高併發系統吧?那麼它是怎麼實現的呢?

可能不少人腦子裏馬上出現了緩存+哈希的系統,把搜索的搜索提示詞存在redis集羣中,每次來了請求直接redis集羣中查找key,而後返回相應的value值就好了,完美解決,雖然耗費點內存,可是空間換時間嘛,也能接受,這麼作行不行?恩,我以爲是能夠的,但有人這麼作嗎?沒有。

瞭解的人應該知道,沒有人會這麼來實現,這種搜索提示的功能通常用trie樹來作,耗費的內存很少,查找速度爲O(k),其中k爲字符串的長度,雖然看上去沒有哈希表的O(1)好,可是少了網絡開銷,節約了不少內存,而且實際查找時間還要不比緩存+哈希慢多少,一種合適當前場景的核心數據結構纔是高併發系統的關鍵,緩存+哈希若是也當作一種數據結構,但這種數據結構並不適用於全部的高併發場景,因此

高併發系統的設計,關鍵在合理的數據結構的設計,而不在架構的套用

不斷的代碼性能優化

有了上面的數據結構,而且設計出了系統了,拿到線上一跑,效果還行,但感受沒達到極限,這時候可千萬不能就直接上外部工具(好比緩存)提高性能,須要作的是不斷的代碼性能的優化,簡單的說,就是不斷的review你的代碼,不斷的找出能夠優化的性能點,而後進行優化,由於以前設計的時候就已經經過理論大概能算出來這個系統的併發量了,好比上面那個搜索提示,若是咱們假定平均每一個搜索詞6個字符,檢索一次大約須要查詢6次,須要2-3毫秒,這樣的話,若是8核的機器,多線程編程方式,一秒鐘最多能接受3200次請求(1000ms/2.5ms*8),若是沒達到這個量級,那麼確定是代碼哪裏有問題。

這個階段可能須要藉助一些個工具了,JAVA有JAVA的性能優化工具,你們都有本身以爲好使的,我自己JAVA用得不多,也沒啥可推薦的,若是是Golang的話,自帶的go tool pprof就能很好的進行性能優化。

或者最簡單的,就是把各個模塊的時間打印出來,壓測一遍,看看哪一個模塊耗時,而後再去仔細review那個模塊的代碼,進行算法和數據結構的優化,我我的比較推崇這個辦法,雖然比較笨,可是比較實在,性能差就是差,比較直觀能看出來,也能看出須要優化的點,並且比較貼近代碼,少了外部工具的干擾,可能也比較裝逼吧。

這個過程是一個長期的過程,也是《重構:改善代碼的既有設計》中提到的,一個優秀的系統須要不斷的進行代碼級別的優化和重構,因此

高併發系統的實現,就是不斷的優化你代碼的性能,不斷逼近你設計時的理論值

再考慮外部通用方法

以上兩個都完成了,併發量也基本達到理論值了,可是還有提高的需求,這時候再來考慮外部的通用方法,好比加一個LRU緩存,把熱詞的查詢時間變成O(1),進一步提升性能。

提及LRU,多說一句,這是個標準的緩存技術了,實現起來代碼也不復雜,就是個哈希表+鏈表的數據結構,一個合格的開發人員,即使沒有據說過,給定一個場景,應該也能本身設計出來,我見過不少簡歷都說本身有大型高併發系統的開發經驗,能熟練運用各類緩存技術,也對緩存技術有深刻的瞭解,可是一面試的時候我讓他寫個LRU,首先有50%的人沒據說過,OK,沒聽過不要緊,我描述一下,而後給一個場景,硬盤上有N條數據,而且有一個程序包,提供GET和SET方法,能夠操做磁盤讀寫數據,可是速度太慢,請設計一個內存中的數據結構,也提供GET和SET方法,保存最近訪問的前100條數據,這個數據結構就是一個LRU了,讓面試者實現出來,若是以爲寫代碼麻煩,能夠把數據結構設計出來描述一下就好了,就這樣,還不少人不會,這怎麼能說是對緩存技術有深刻了解呢?就這樣,怎麼能說有過大型高併發系統的經驗呢?這只是開源工具的使用經驗罷了。

在沒把系統的性能壓榨徹底以前,不要使用外部的通用方法,由於使用了之後就沒有太多進一步優化空間了。

最後靠運維技術了

上面幾種都已經弄完了,還須要提高性能,這時候再考慮運維的技術了,好比常規的加負載均衡,部署成集羣之類的,經過運維和部署的方法提升服務的併發性。

高併發系統只是相對的,沒有什麼無上限的高併發,流量的洪流來了,再高的高併發同樣掛,新浪微博的高併發應該作得很好吧?可是林心如發條微博說她和霍建華談戀愛了,同樣把微博搞掛了(非官方消息啊,我猜想的,呵呵,那天下午新浪微博正好掛了),呵呵,你說要是TFBOY明天過生日,微博是否是要連夜加幾個redis集羣啊?若是有微博的朋友,留個言溜溜唄:)

總結

羅裏吧嗦說了這麼多,其實我就想表達一個意思,無論是前面的高可用,仍是今天的高併發

代碼纔是關鍵,架構都是錦上添花的東西,既然是錦上添花的,必然坑多,沒有什麼捷徑。

代碼的健壯性決定了高可用,這些印度人就能作到,而高性能,高併發須要的不只僅是代碼的健壯性,還有數據結構的設計和代碼的調優能力了。

架構模式是你們總結出來的,和你的系統可能關係不是很大,學習太多的架構,腦殼會亂,還不如實打實的看幾本書,而後對着架構多推敲練習,不少人對數據結構嗤之以鼻,以爲對於現有的開發來講,數據結構沒那麼重要了,但對於後端開發來講,數據結構是很重要的技能,雖然面試的時候不會讓你去翻轉一棵二叉樹,但二叉樹是什麼,什麼場景下用仍是應該知道的吧?

找準合適的數據結構,不斷的優化代碼,這樣來提高你的系統性能,這樣的系統纔是你可控的,纔有不斷優化的空間,更好的高併發,若是一開始就上外部的緩存技術,極可能若是性能達不到要求,就沒有優化空間了,由於要修改外部的系統仍是很困難的。

這幾篇我以爲我都在瞎扯淡,雖然比較虛,但也是我工做這麼些年淌坑無數之後的總結吧,後面的文章會寫一些實際的了,個人搜索引擎部分還沒寫完呢。盡請期待。呵呵。。


若是你以爲不錯,歡迎轉發給更多人看到,也歡迎關注個人公衆號,主要聊聊搜索,推薦,廣告技術,還有瞎扯。。文章會在這裏首先發出來:)掃描或者搜索微信號XJJ267或者搜索西加加語言就行

相關文章
相關標籤/搜索