應對高併發系統有沒有通用的解決方案呢?

{"type":"doc","content":[{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"靈魂拷問:"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"應對高併發系統有沒有一些通用的解決方案呢?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些方案解決了什麼問題呢?"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些方案有那些優勢和劣勢呢?"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對性能孜孜不倦的追求是互聯網技術不斷髮展的根本驅動力,從最初的大型機到現在的微型機,在本質上也是爲了性能而生。軟件系統也存在類似的現象,一個系統從最初的少量訪問請求到後期的大併發請求,這都需要我們對性能的提升提供一系列解決方案。像最初的淘寶,也僅僅是一個外包做出來的產品,隨着業務的不斷髮展,淘寶的併發量指數級增加,同時對系統提出了嚴峻的挑戰,這才逐步造就了現在淘寶這樣可以支撐數千萬人同時在線的高併發系統。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提起應對高併發,每個人都或多或少可以說出幾種解決方案,高併發系統的設計魅力在於我們能夠憑藉程序員的聰明才智設計巧妙的方案,從而應對巨大流量的衝擊。從目前已知的方案中,大體可以歸納爲以下幾種"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#提升單機性能","title":null}},{"type":"text","text":"提升單機性能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘可能的提升單機的性能是一個永恆的話題,無論是採用分佈式還是其他方案,單機性能的提高,對於一個系統來說只有益處。拿編程語言來說,c或者c++語言編寫的程序理論上會比java ,net,Python寫的程序要高效,當然這需要建立在程序正常運行的情況下。提升單機性能最簡單粗暴的方式就是提升硬件性能,舉一個簡單例子:假如數據庫DB的服務器內存爲8G,隨着數據量的增加,你會發現有些sql執行會慢慢的變慢,原因是數據庫的索引或者數據在內存中完全存放不下,需要回寫磁盤,有些查詢在內存中並不能命中,造成了一些sql會在磁盤中查詢數據,這個時候如果把服務器的內存增加到16G,你會發現這些慢sql居然憑空消失了,這是硬件提升性能的一個典型案例。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於運行的程序也是同樣的道理,儘可能的把程序優化到極致,也許單機就可以達到別人分佈式部署的性能效果,當然這需要我們在編寫代碼的時候仔細構思。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"無論什麼時候,我覺得提升單機性能都有必要"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#橫向擴展","title":null}},{"type":"text","text":"橫向擴展"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當一個單機系統無法抵抗巨大流量衝擊的時候,最簡單有效的解決方案之一便是橫向擴展,橫向擴展是指把巨大的流量分割爲數個比較小的流量,從而解決高併發系統的性能問題,本質上,橫向擴展屬於分而治之的理論,屬於分佈式的概念範疇。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉一個很簡單的例子,假設目前單機處理請求數爲200/s,當每秒的請求數到達1000的時候,單臺機器肯定會遇到瓶頸,這個時候如果處理請求的服務器增加到5臺,甚至更多,這樣便輕鬆解決了性能問題。當然,能否方便的橫向擴展還要看具體的系統設計,如果系統是無狀態的,理論上橫向擴展是沒問題的,但是一些有狀態的服務,可能會涉及到狀態的遷移等工作,這也是爲什麼很多架構師提倡無狀態服務的一個原因。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個應用程序的橫向擴展可以通過負載均衡來實現,像阿里雲的SLB服務,nginx的反向代理功能,這些都可以很方便實現應用程序的橫向擴展。但是,像數據庫比如mysql,這樣的DB系統,無限制的橫向擴展可能只是一個目標。大多數DB採用的主從或者多主多從來解決橫向擴展問題,主節點負責寫操作,從節點負責讀操作,當然這裏涉及到主從同步的機制,主從同步的延遲等問題,有興趣的同學可以去深入研究一下。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f6/f6f9045a2c4a0945c7f399c5725f3eeb.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那什麼時候該選擇橫向擴展呢?一般來講,在系統的設計之初便會考慮橫向擴展,因爲這種方案足夠簡單,可以用堆砌硬件來解決的問題就不是問題。現在我敢說90%以上的系統在第一版上線的時候就做了類似負載均衡的部署方案,其中有很多就利用了nginx的反向代理功能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e2/e247dc42f5f4fbb71111676707e91fd2.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然橫向擴展並非沒有負面影響,和單機系統一樣,橫向擴展也要考慮某個節點down掉的問題,所以監控和健康檢查是現在一個系統必備的手段,而且在系統設計之初便會在整體架構之中。就像我前幾篇的文章所說,橫向擴展既然屬於分佈式範疇,必然需要考慮分佈式系統需要考慮的問題:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"http://suo.im/60S8zy","title":null},"content":[{"type":"text","text":"分佈式系統的問題"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#緩存","title":null}},{"type":"text","text":"緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了上面所說的橫向擴展方案,另外一種行之有效並且足夠簡單的便是緩存方案。這一點毋庸置疑,緩存可以遍佈在一個系統的各個角落,從操作系統到瀏覽器,從cpu到磁盤,從數據庫到消息隊列,任何稍微複雜的服務和組件中都有緩存的影子。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存爲什麼可以大幅度提高性能的性能呢?這還需要從系統的瓶頸來說,在客戶端一個請求的生命週期中,這個請求的響應時間嚴重受限於最慢的那個環節,這類似於木桶效應(一個木桶可以存的水量,取決於最短那個木板)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"舉一個很簡單的例子:當客戶端請求商城的一個商品信息的時候,請求經過http協議到達服務器的某個端口,服務端程序把請求解包然後去請求數據庫,數據庫不單單在另外一臺服務器上,而且還需要從磁盤中加載數據,所謂的DB緩存沒有命中。在這整個過程中,請求磁盤的過程是最慢的,普通磁盤是由機械手臂,磁頭,轉軸,盤片組成,磁盤在查詢數據的時候,磁頭是需要花費很長時間累尋道的,當然SSD的速度要比普通磁盤快的多,但是相比較內存還是要慢幾個量級。而我們最想要的流程是這樣的:當一個請求到達服務端的時候能儘快的從某個設備上取出信息,然後返給客戶端,這個設備絕不可能是磁盤,這個設備在速度和容量上比較均衡,它應該是內存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存在語義上要豐富很多,我們可以把任何可以降低響應時間的中間存儲都稱之爲緩存。比如CPU的一級緩存,二級緩存,三級緩存,瀏覽器的緩存等。緩存主要解決了上下游設備速度不匹配的問題"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/24/24c1c5238fce2214a852f789a4bbdb58.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"程序界有一句古話:把數據放在離用戶最近的地方纔是最快的。CDN本質上就是做的這件事。對於緩存而言,我們經常會聽到瀏覽器緩存,進程內緩存,進程外緩存等概念。目前針對於服務端一般的緩存策略爲採用第三方kv存儲設備,比如redis,Memcache等。當然在對性能極其苛刻的系統中,我還是推薦使用進程內緩存,具體可見之前的推文:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/6YL3SnSriKEnpCyB5qkk0g","title":null},"content":[{"type":"text","text":"高併發下爲什麼更喜歡進程內緩存"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"link","attrs":{"href":"#異步","title":null}},{"type":"text","text":"異步"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"談到異步,必須要說下同步,同步調用是指調用方要阻塞等待被調用方執行完畢纔可以返回。系統現在普遍都會採用多線程的方式來提供系統的吞吐量(多進程的方式現在很少,但不代表沒有,比如:nodejs,nginx),在同步這種方式下,如果被調用方的響應時間過長,會造成調用方的線程長時間處於等待狀態,線程的利用率大幅度降低,線程對於系統來說,是很昂貴的資源,創建大量的線程去應對高併發是不明智的,不僅僅浪費了內存,而且會加大線程上下文cpu切換的成本。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個高吞吐量的系統,理論上所有的線程都要時時刻刻在工作,而且把cpu資源壓榨到最多。對於一個IO密集型操作來說,採用異步方式可以大大提高系統吞吐量。異步不需要等待被調用方執行完成就可以執行其他的邏輯,在被調用方執行完畢之後通過通知回調的方式反饋給調用方。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"異步本質上是一種編程思想,一種編程模型。他提高的是系統整體的吞吐量,但是請求的響應時間對比同步方式來說會略微加大。"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"像平時用的最多的消息隊列,在模型上也屬於異步編程模型。調用方會把消息丟到隊列中,然後直接返回去執行其他業務,被調用方接收到消息然後進行處理,然後根據具體的業務看是否需要給予結果回覆。有不少秒殺系統會採用消息隊列進行流量削峯,這是異步帶來的優勢之一。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/06/0681d2b3fe35c3320dfa3f0c6843d54c.jpeg","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關於異步更加詳細的介紹可以查看之前的推文:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s/3eGESmaKkUTfo3hh38Cg4g","title":null},"content":[{"type":"text","text":"問世間異步爲何物?"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在這裏我需要多說一句:異步並不是沒有代價,在多數情況下,採用異步會比同步方式編寫更多的代碼,而且查找bug會花費更多的時間。但是對於一個高併發系統來說,異步帶來的益處還是值得的,前提是你正確應用了異步。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"更多精彩文章"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342955119549267969&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"分佈式大併發系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342959003139227648&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"架構設計系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342962375443529728&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"趣學算法和數據結構系列"}]}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1342964237798391808&__biz=MzIwNTc3OTAxOA==#wechat_redirect","title":null},"content":[{"type":"text","text":"設計模式系列"}]}]}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f8/f8af5984765a267892bf1a1272272625.png","alt":"image","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章