天天看點

海量資料的處理方案,高并發處理。

一、網站應用背景

開發一個網站的應用程式,當使用者規模比較小的時候,使用簡單的:一台應用伺服器+一台資料庫伺服器+一台檔案伺服器,這樣的話完全可以解決一部分問題,也可以通過堆硬體的方式來提高網站應用的通路性能,當然,也要考慮成本的問題。

當問題的規模在經濟條件下通過堆硬體的方式解決不了的時候,我們應該通過其他的思路去解決問題,網際網路發展至今,已經提供了很多成熟的解決方案,但并不是都具有适用性,你把淘寶的技術全部都搬過來也不一定達到現在淘寶的水準,道理很簡單。

當然,很多文章都在強調,一個網站的發展水準,是逐漸的演變過來的,并不是一朝一夕的事情。雖然目前的情況網際網路的泡沫越來越大,但是整個網際網路技術的發展确實為我們提供了友善快捷的上網體驗。下邊是一張早期的淘寶官網的界面:

海量資料的處理方案,高并發處理。

目前,部落客正在跟随導師做一個創業項目,使用的技術是SSM+MySQL+Linux這些,但是由于資金的限制和考慮到使用者群體的特殊性,系統的架構無奈的選擇的就是最簡單的方式:一台應用伺服器、一台資料庫伺服器、一台檔案系統伺服器,沒有用到進階的技術,也沒有用到分布式部署的方案。下邊整理的是一些針對海量資料和高并發情況下的解決方案,技術水準有限,歡迎留言指導。

二、針對海量資料和高并發的主要解決方案

海量資料的解決方案:

  1. 使用緩存;
  2. 頁面靜态化技術;
  3. 資料庫優化;
  4. 分離資料庫中活躍的資料;
  5. 批量讀取和延遲修改;
  6. 讀寫分離;
  7. 使用NoSQL和Hadoop等技術;
  8. 分布式部署資料庫;
  9. 應用服務和資料服務分離;
  10. 使用搜尋引擎搜尋資料庫中的資料;
  11. 進行業務的拆分;

高并發情況下的解決方案:

  1. 應用程式和靜态資源檔案進行分離;
  2. 頁面緩存;
  3. 叢集與分布式;
  4. 反向代理;
  5. CDN;

三、海量資料的解決方案

(1)使用緩存

網站通路資料的特點大多數呈現為“二八定律”:80%的業務通路集中在20%的資料上。

例如:在某一段時間内百度的搜尋熱詞可能集中在少部分的熱門詞彙上;新浪微網誌某一時期也可能大家廣泛關注的主題也是少部分事件。

總的來說就是使用者隻用到了總資料條目的一小部分,當網站發展到一定規模,資料庫IO操作成為性能瓶頸的時候,使用緩存将這一小部分的熱門資料緩存在記憶體中是一個很不錯的選擇,不但可以減輕資料庫的壓力,還可以提高整體網站的資料通路速度。

使用緩存的方式可以通過程式代碼将資料直接儲存到記憶體中,例如通過使用Map或者ConcurrentHashMap;另一種,就是使用緩存架構:Redis、Ehcache、Memcache等。 

海量資料的處理方案,高并發處理。

使用緩存架構的時候,我們需要關心的就是什麼時候建立緩存和緩存失效政策。

緩存的建立可以通過很多的方式進行建立,具體也需要根據自己的業務進行選擇。例如,新聞首頁的新聞應該在第一次讀取資料的時候就進行緩存;對于點選率比較高的文章,可以将其文章内容進行緩存等。

記憶體資源有限,選擇如何建立緩存是一個值得思考的問題。另外,對于緩存的失效機制也是需要好好研究的,可以通過設定失效時間的方式進行設定;也可以通過對熱門資料設定優先級,根據不同的優先級設定不同的失效時間等;

需要注意的是,當我們删除一條資料的時候,我們要考慮到删除該條緩存,還要考慮在删除該條緩存之前該條資料是否已經到達緩存失效時間等各種情況!

使用緩存的時候還要考慮到緩存伺服器發生故障時候如何進行容錯處理,是使用N多台伺服器緩存相同的資料,通過分布式部署的方式對緩存資料進行控制,當一台發生故障的時候自動切換到其他的機器上去;還是通過Hash一緻性的方式,等待緩存伺服器恢複正常使用的時候重新指定到該緩存伺服器。Hash一緻性的另一個作用就是在分布式緩存伺服器下對資料進行定位,将資料分布在不用緩存伺服器上。關于資料緩存的Hash一緻性也是一個比較打的問題,這裡隻能大緻描述一下,關于Hash一緻性的了解,推薦一篇文章:​​javascript:void(0)​​

(2)頁面靜态化技術

使用傳統的JSP界面,前端界面的顯示是通過背景伺服器進行渲染後傳回給前端遊覽器進行解析執行,如下圖: 

海量資料的處理方案,高并發處理。

當然,現在提倡前後端分離,前端界面基本都是HTML網頁代碼,通過Angular JS或者NodeJS提供的路由向後端伺服器送出請求擷取資料,然後在遊覽器對資料進行渲染,這樣在很大程度上降低了後端伺服器的壓力。

還可以将這些靜态的HTML、CSS、JS、圖檔資源等放置在緩存伺服器上或者CDN伺服器上,一般使用最多的應該是CDN伺服器或者Nginx伺服器提供的靜态資源功能。

另外,在《高性能網站建設進階指南-Web開發者性能優化最佳實踐(口碑網前端團隊 翻譯)》這本書中,對網站性能的前端界面提供了一些很寶貴的經驗,如下:

海量資料的處理方案,高并發處理。

是以,在這些靜态資源的處理上,選擇正确的處理方式還是對整體網站性能還是有很大幫助的!

(3)資料庫優化

資料庫優化是整個網站性能優化的最基礎的一個環節,因為,大多數網站性能的瓶頸都是開在資料庫IO操作上,雖然提供了緩存技術,但是對資料庫的優化還是一個需要認真的對待。一般公司都有自己的DBA團隊,負責資料庫的建立,資料模型的确立等問題,不像我們現在幾個不懂資料庫優化的人隻能在網上找一篇篇資料庫優化的文章,自己去摸索,并沒有形成一個系統的資料庫優化思路。

對于資料庫的優化來說,是一種用技術換金錢的方式。資料庫優化的方式很多,常見的可以分為:資料庫表結構優化、SQL語句優化、分區、分表、索引優化、使用存儲過程代替直接操作等 。

1、表結構優化

對于資料庫的 開發規範與使用技巧以及設計和優化,前邊的時候總結了一些文章,這裡偷個懶直接放位址,有需要的可以移步看一下: 

另外,再設計資料庫表的時候需不需要建立外鍵,使用外鍵的好處之一可以友善的進行級聯删除操作,但是現在在進行資料業務操作的時候,我們都通過事物的方式來保證資料讀取操作的一緻性,我感覺相比于使用外鍵關聯MySQL自動幫我們完成級聯删除的操作來說,還是自己使用事物進行删除操作來的更放心一些。當然可能也是有适用的場景,大家如有很好的建議,歡迎留言!

2、SQL優化

對于SQL的優化,主要是針對SQL語句處理邏輯的優化,而且還要根據索引進行配合使用。另外,對于SQL語句的優化我們可以針對具體的業務方法進行優化,我們可以将執行業務邏輯操作的資料庫執行時間記錄下來,來進行有針對性的優化,這樣的話效果還是很不錯的!例如下圖,展示了一條資料庫操作執行調用的時間:

海量資料的處理方案,高并發處理。

分表

分表是将一個大表按照一定的規則分解成多張具有獨立存儲空間的實體表,我們可以稱為子表,每個表都對應三個檔案,MYD資料檔案,.MYI索引檔案,.frm表結構檔案。這些子表可以分布在同一塊磁盤上,也可以在不同的機器上。資料庫讀寫操作的時候根據事先定義好的規則得到對應的子表名,然後去操作它。

例如:使用者表 

使用者的角色有很多種,可以通過枚舉類型的方式将使用者分為不同類别category:學生、教師、企業等 ,這樣的話,我們就可以根據類别category來對資料庫進行分表,這樣的話每次查詢的時候現根據使用者的類型鎖定一個較小的範圍。

不過分表之後,如果需要查詢完整的順序就需要使用多表操作了。

分區

資料庫分區是一種實體資料庫設計技術,DBA和資料庫模組化人員對其相當熟悉。雖然分區技術可以實作很多效果,但其主要目的是為了在特定的SQL操作中減少資料讀寫的總量以縮減響應時間。

分區和分表相似,都是按照規則分解表。不同在于分表将大表分解為若幹個獨立的實體表,而分區是将資料分段劃分在多個位置存放,可以是同一塊磁盤也可以在不同的機器。分區後,表面上還是一張表,但資料散列到多個位置了。資料庫讀寫操作的時候操作的還是大表名字,DMS自動去組織分區的資料。

當一張表中的資料變得很大的時候,讀取資料,查詢資料的效率非常低下,很容易的就是講資料分到不同的資料表中進行儲存,但是這樣分表之後會使得操作起來比較麻煩,因為,将同類的資料分别放在不同的表中的話,在搜尋資料的時候需要便利查詢這些表中的資料。想進行CRUD操作還需要先找到對應的所有表,如果涉及到不同的表的話還要進行跨表操作,這樣操作起來還是很麻煩的。

使用分區的方式可以解決這個問題,分區是将一張表中的資料按照一定的規則分到不同的區中進行儲存,這樣進行資料查詢的時候如果資料的範圍在同一個區域内那麼就可以支隊一個區中的資料進行操作,這樣的話操作起來資料量更少,操作速度更快,而且該方法是對程式透明的,程式不需要進行任何的修改。

索引優化

索引的大緻原理是在資料發生變化的時候就預先按指定字段的順序排列後儲存到一個類似表的結構中,這樣在查找索引字段為條件記錄時就可以很快地從索引中找到對應記錄的指針并從表中擷取到相應的資料,這樣速度是很快地。

不過,雖然查詢的效率大大提高了,但是在進行增删改的時候,因為資料的變化都需要更新相應的索引,也是一種資源的浪費。

關于使用索引的問題,對待不同的問題,還是需要進行不同的讨論,根據具體的業務需求選擇合适的索引對性能的提高效果是很明顯的一個舉措!

使用存儲過程代替直接操作

存儲過程(Stored Procedure)是在大型資料庫系統中,一組為了完成特定功能的SQL 語句集,存儲在資料庫中,經過第一次編譯後再次調用不需要再次編譯,使用者通過指定存儲過程的名字并給出參數(如果該存儲過程帶有參數)來執行它。存儲過程是資料庫中的一個重要對象,任何一個設計良好的資料庫應用程式都應該用到存儲過程。

在操作過程比較複雜并且調用頻率比較高的業務中,可以将編寫好的sql語句用存儲過程的方式來代替,使用存儲過程隻需要進行一次變異,而且可以在一個存儲過程裡做一些複雜的操作。

(4)分離資料庫中活躍的資料

正如前邊提到的“二八定律”一樣,網站的資料雖然很多,但是經常被通路的資料還是有限的,是以可以講這些相對活躍的資料進行分離出來單獨進行儲存來提高處理效率。

其實前邊使用緩存的思想就是一個很明顯的分離資料庫中活躍的資料的使用案例,将熱門資料緩存在記憶體中。

還有一種場景就是,例如一個網站的所用注冊使用者量很大千萬級别,但是經常登入的使用者隻有百萬級别,剩下的基本都是很長時間都沒有進行登入操作,如果不把這些“僵屍使用者”單獨分離出去,那麼我們每次查詢其他登入使用者的時候,就白白浪費了這些僵屍使用者的查詢操作。

(5)批量讀取和延遲修改

批量讀取和延遲修改的原理是通過減少操作資料庫的操作來提高效率。

批量讀取是将多次查詢合并到一次中進行讀取,因為每一個資料庫的請求操作都需要連結的建立和連結的釋放,還是占用一部分資源的,批量讀取可以通過異步的方式進行讀取。

延遲修改是對于一些高并發的并且修改頻繁修改的資料,在每次修改的時候首先将資料儲存到緩存中,然後定時将緩存中的資料儲存到資料庫中,程式可以在讀取資料時可以同時讀取資料庫中和緩存中的資料。

例如:我現在在編寫這份部落格,我一開始寫了一寫内容然後點選釋出了,在次回到Markdown進行修改操作,我有一個習慣,沒寫一些東西總是按一下上邊的 “儲存”按鈕,然後我在另一個頁面打開這篇部落格檢視,我的修改已經被更新,但是我還在 編輯!

海量資料的處理方案,高并發處理。

不知道CSDN的技術是不是在我沒有點選釋出之前,這些資料都是先放到緩存裡邊的。

(6) 讀寫分離

讀寫分離的實質是将應用程式對資料庫的讀寫操作配置設定到多個資料庫伺服器上,進而降低單台資料庫的通路壓力。

讀寫分離一般通過配置主從資料庫的方式,資料的讀取來自從庫,對資料庫增加修改删除操作主庫。

海量資料的處理方案,高并發處理。

(7)使用NoSQL和Hadoop等技術

NoSQL是一種非結構化的非關系型資料庫,由于其靈活性,突破了關系型資料庫的條條框框,可以靈活的進行操作,另外,因為NoSQL通過多個塊存儲資料的特點,其操作大資料的速度也是相當快的。

(8)分布式部署資料庫

任何強大的單一伺服器都滿足不了大型網站持續增長的業務需求。資料庫通過讀寫分離之後将一台資料庫伺服器拆分為兩台或者多台資料庫伺服器,但是仍然滿足不了持續增長的業務需求。分布式部署資料庫是将網站資料庫拆分的最後手段,隻有在單表資料規模非常龐大的時候才使用。

分布式部署資料庫是一種很理想的情況,分布式資料庫是将表存放在不同的資料庫中然後再放到不同的資料庫中,這樣在處理請求的時候,如果需要調用多個表,則可以讓多台伺服器同時處理,進而提高處理效率。

分布式資料庫簡單的架構圖如下:

海量資料的處理方案,高并發處理。

(9)應用服務和資料服務分離

應用伺服器和資料庫伺服器進行分離的目的是為了根據應用伺服器的特點和資料庫伺服器的特點進行底層的優化,這樣的話能夠更好的發揮每一台伺服器的特性,資料庫伺服器當然是有一定的磁盤空間,而應用伺服器相對不需要太大的磁盤空間,這樣的話進行分離是有好處的,也能防止一台伺服器出現問題連帶的其他服務也不可以使用。

海量資料的處理方案,高并發處理。

(10)使用搜尋引擎搜尋資料庫中的資料

使用搜尋引擎這種非資料庫查詢技術對網站應用的可伸縮分布式特性具有更好的支援。

常見的搜尋引擎如Solr通過一種反向索引的方式,維護關鍵字到文檔的映射關系,類似于我們使用《新華字典》進行搜尋一個關鍵字,首先應該是看字典的目錄進行查找然後定位到具體的位置。

搜尋引擎通過維護一定的關鍵字到文檔的映射關系,能夠快速的定位到需要查找的資料,相比于傳統的資料庫搜尋的方式,效率還是很高的。

目前一種比較火的ELK stack技術,還是值得學習的。

(11) 進行業務的拆分

為什麼進行業務的拆分,歸根結底上還是使用的還是講不通的業務資料表部署到不用的伺服器上,分别查找對應的資料以滿足網站的需求。各個應用之間用過指定的URL連接配接擷取不同的服務,

例如一個大型的購物網站就會将首頁、商鋪、訂單、買家、賣家等拆分為不通的子業務,一方面将業務子產品分歸為不同的團隊進行開發,另外一方面不同的業務使用的資料庫表部署到不通的伺服器上,展現到拆分的思想,當一個業務子產品使用的資料庫伺服器發生故障也不會影響其他業務子產品的資料庫正常使用。另外,當其中一個子產品的通路量激增的時候還可以動态的擴充這個子產品使用到的資料庫的數量進而滿足業務的需求。

高并發情況下的解決方案

(1)應用程式和靜态資源檔案進行分離

所謂的靜态資源就是我們網站中用到的Html、Css、Js、Image、Video、Gif等靜态資源。應用程式和靜态資源檔案進行分離也是常見的前後端分離的解決方案,應用服務隻提供相應的資料服務,靜态資源部署在指定的伺服器上(Nginx伺服器或者是CDN伺服器上),前端界面通過Angular JS或者Node JS提供的路由技術通路應用伺服器的具體服務擷取相應的資料在前端遊覽器上進行渲染。這樣可以在很大程度上減輕後端伺服器的壓力。

例如,百度首頁使用的圖檔就是單獨的一個域名伺服器上進行部署的

海量資料的處理方案,高并發處理。

(2)頁面緩存

頁面緩存是将應用生成的很少發生資料變化的頁面緩存起來,這樣就不需要每次都重新生成頁面了,進而節省大量CPU資源,如果将緩存的頁面放到記憶體中速度就更快。

可以使用Nginx提供的緩存功能,或者可以使用專門的頁面緩存伺服器Squid。

(3)叢集與分布式

(4)反向代理

(5)CDN

CDN伺服器其實是一種叢集頁面緩存伺服器,其目的就是盡早的傳回使用者所需要的資料,一方面加速使用者通路速度,另一方面也減輕後端伺服器的負載壓力。

CDN的全稱是Content Delivery Network,即内容分發網絡。其基本思路是盡可能避開網際網路上有可能影響資料傳輸速度和穩定性的瓶頸和環節,使内容傳輸的更快、更穩定。

CDN通過在網絡各處放置節點伺服器所構成的在現有的網際網路基礎之上的一層智能虛拟網絡,CDN系統能夠實時地根據網絡流量和各節點的連接配接、負載狀況以及到使用者的距離和響應時間等綜合資訊将使用者的請求重新導向離使用者最近的服務節點上。其目的是使使用者可就近取得所需内容,解決 Internet網絡擁擠的狀況,提高使用者通路網站的響應速度。

也就是說CDN伺服器是部署在網絡運作商的機房,提供的離使用者最近的一層資料通路服務,使用者在請求網站服務的時候,可以從距離使用者最近的網絡提供商機房擷取資料。電信的使用者會配置設定電信的節點,聯通的會配置設定聯通的節點。

CDN配置設定請求的方式是特殊的,不是普通的負載均衡伺服器來配置設定的那種,而是用專門的CDN域名解析伺服器在解析與名的時候就配置設定好的。

CDN結構圖如下所示:

總結