大型網際網路架構與叢集技術(Java方向)
java架構必須掌握的幾點技術?
關於學習架構,必須會的幾點技術
1. java反射技術
2. xml檔案處理
3. properties屬性檔案處理
4. 執行緒安全機制
5. annocation註解
6. 設計模式
7. 代理機制(aop)
8. serlvet基礎(過濾器等等)
幾樣比較實用的技術:
1. 模板語言freemarker
2. ognl
3. gson json工具類
大家對於幾大框架望而生畏,實際上只要明白他的原理,就會觸類旁通,在這裡我說說自己的幾點拙見!
MVC層(Struts,Springmvc):
非常簡單就是採用一個servlet實現統一跳轉,配置檔案儲存了請求、處理類、轉發請求的關係(通過xml檔案或者註解)
操作流程:頁面觸發請求,框架通過讀取配置檔案獲取到處理類,然後通過反射例項化該類,進行對應的業務處理
(現在流行的零配置,更是簡化了mvc層的編寫)
持久層(Mybatis/Hibernate):
mybatis其實就是sql+mybatis邏輯標籤
邏輯標籤的理解如何大家用過模板語言freemarker或者velocity應該會很容易理解,就是自定義的規則標籤
Hibernate略顯高階,也很簡單,他是採用註解或者配置的方式將實體欄位和表字段進行一個配置,在啟動的時候動態生成sql
大家可以看下開源專案minidao,就會知道持久層原來寫很簡單;
所以架構可以簡單理解為:
配置+反射+設計模式+指令碼+AOP
配置常用做法:
1.xml檔案
2.annocation註解
3.properties屬性檔案
4.零配置思想
指令碼處理方法:
可以自己寫,也可以採用模板語言freemarker等等
1.大型網際網路架構的演化
前言
一個成熟的大型網站(如淘寶、京東等)的系統架構並不是開始設計就具備完整的高效能、高可用、安全等特性,它總是隨著使用者量的增加,業務功能的擴充套件逐漸演變完善的,在這個過程中,開發模式、技術架構、設計思想也發生了很大的變化,就連技術人員也從幾個人發展到一個部門甚至一條產品線。所以成熟的系統架構是隨業務擴充套件而完善出來的,並不是一蹴而就;不同業務特徵的系統,會有各自的側重點,例如淘寶,要解決海量的商品資訊的搜尋、下單、支付,例如騰訊,要解決數億的使用者實時訊息傳輸,百度它要處理海量的搜尋請求,他們都有各自的業務特性,系統架構也有所不同。儘管如此我們也可以從這些不同的網站背景下,找出其中共用的技術,這些技術和手段可以廣泛執行在大型網站系統的架構中,下面就通過介紹大型網站系統的演化過程,來認識這些技術和手段。
一、最開始的網站架構
最初的架構,應用程式、資料庫、檔案都部署在一臺伺服器上,如圖:
二、應用、資料、檔案分離
隨著業務的擴充套件,一臺伺服器已經不能滿足效能需求,故將應用程式、資料庫、檔案各自部署在獨立的伺服器上,並且根據伺服器的用途配置不同的硬體,達到最佳的效能效果。
三、利用快取改善網站效能
在硬體優化效能的同時,同時也通過軟體進行效能優化,在大部分的網站系統中,都會利用快取技術改善系統的效能,使用快取主要源於熱點資料的存在,大部分網站訪問都遵循28原則(即80%的訪問請求,最終落在20%的資料上),所以我們可以對熱點資料進行快取,減少這些資料的訪問路徑,提高使用者體驗。
快取實現常見的方式是本地快取、分散式快取。當然還有CDN、反向代理等,這個後面再講。本地快取,顧名思義是將資料快取在應用伺服器本地,可以存在記憶體中,也可以存在檔案,OSCache就是常用的本地快取元件。本地快取的特點是速度快,但因為本地空間有限所以快取資料量也有限。分散式快取的特點是,可以快取海量的資料,並且擴充套件非常容易,在門戶類網站中常常被使用,速度按理沒有本地快取快,常用的分散式快取是Memcached、Redis。
四、使用叢集改善應用伺服器效能
應用伺服器作為網站的入口,會承擔大量的請求,我們往往通過應用伺服器叢集來分擔請求數。應用伺服器前面部署負載均衡伺服器排程使用者請求,根據分發策略將請求分發到多個應用伺服器節點。
常用的負載均衡技術硬體的有F5,價格比較貴,軟體的有LVS、Nginx、HAProxy。LVS是四層負載均衡,根據目標地址和埠選擇內部伺服器,Nginx是七層負載均衡和HAProxy支援四層、七層負載均衡,可以根據報文內容選擇內部伺服器,因此LVS分發路徑優於Nginx和HAProxy,效能要高些,而Nginx和HAProxy則更具配置性,如可以用來做動靜分離(根據請求報文特徵,選擇靜態資源伺服器還是應用伺服器)。
五、資料庫讀寫分離和分庫分表
隨著使用者量的增加,資料庫成為最大的瓶頸,改善資料庫效能常用的手段是進行讀寫分離以及分表,讀寫分離顧名思義就是將資料庫分為讀庫和寫庫,通過主備功能實現資料同步。分庫分表則分為水平切分和垂直切分,水平切換則是對一個數據庫特大的表進行拆分,例如使用者表。垂直切分則是根據業務不同來切換,如使用者業務、商品業務相關的表放在不同的資料庫中。
六、使用CDN和反向代理提高網站效能
假如我們的伺服器都部署在成都的機房,對於四川的使用者來說訪問是較快的,而對於北京的使用者訪問是較慢的,這是由於四川和北京分別屬於電信和聯通的不同發達地區,北京使用者訪問需要通過互聯路由器經過較長的路徑才能訪問到成都的伺服器,返回路徑也一樣,所以資料傳輸時間比較長。對於這種情況,常常使用CDN解決,CDN將資料內容快取到運營商的機房,使用者訪問時先從最近的運營商獲取資料,這樣大大減少了網路訪問的路徑。比較專業的CDN運營商有藍汛、網宿。
而反向代理,則是部署在網站的機房,當用戶請求達到時首先訪問反向代理伺服器,反向代理伺服器將快取的資料返回給使用者,如果沒有沒有快取資料才會繼續走應用伺服器獲取,也減少了獲取資料的成本。反向代理有Squid,Nginx。
七、使用分散式檔案系統
使用者一天天增加,業務量越來越大,產生的檔案越來越多,單臺的檔案伺服器已經不能滿足需求。需要分散式的檔案系統支撐。常用的分散式檔案系統有NFS。
八、使用NoSql和搜尋引擎
對於海量資料的查詢,我們使用nosql資料庫加上搜索引擎可以達到更好的效能。並不是所有的資料都要放在關係型資料中。常用的NOSQL有mongodb和redis,搜尋引擎有lucene。
九、將應用伺服器進行業務拆分
隨著業務進一步擴充套件,應用程式變得非常臃腫,這時我們需要將應用程式進行業務拆分,如百度分為新聞、網頁、圖片等業務。每個業務應用負責相對獨立的業務運作。業務之間通過訊息進行通訊或者同享資料庫來實現。
十、搭建分散式服務
這時我們發現各個業務應用都會使用到一些基本的業務服務,例如使用者服務、訂單服務、支付服務、安全服務,這些服務是支撐各業務應用的基本要素。我們將這些服務抽取出來利用分部式服務框架搭建分散式服務。淘寶的Dubbo是一個不錯的選擇。
小結
大型網站的架構是根據業務需求不斷完善的,根據不同的業務特徵會做特定的設計和考慮,本文只是講述一個常規大型網站會涉及的一些技術和手段。
載自http://www.cnblogs.com/Creator/Mysql在網站架構中的演變
V1.0 簡單網站架構
一個簡單的小型網站或者應用背後的架構可以非常簡單, 資料儲存只需要一個mysql instance就能滿足資料讀取和寫入需求(這裡忽略掉了資料備份的例項),處於這個時間段的網站,一般會把所有的資訊存到一個database instance裡面。
在這樣的架構下,我們來看看資料儲存的瓶頸是什麼?
1.資料量的總大小 一個機器放不下時
2.資料的索引(B+ Tree)一個機器的記憶體放不下時
3.訪問量(讀寫混合)一個例項不能承受
只有當以上3件事情任何一件或多件滿足時,我們才需要考慮往下一級演變。 從此我們可以看出,事實上對於很多小公司小應用,這種架構已經足夠滿足他們的需求了,初期資料量的準確評估是杜絕過度設計很重要的一環,畢竟沒有人願意為不可能發生的事情而浪費自己的經歷。
這裡簡單舉個我的例子,對於使用者資訊這類表 (3個索引),16G記憶體能放下大概2000W行資料的索引,簡單的讀和寫混合訪問量3000/s左右沒有問題,你的應用場景是否
V2.0 垂直拆分
一般當V1.0 遇到瓶頸時,首先最簡便的拆分方法就是垂直拆分,何謂垂直?就是從業務角度來看,將關聯性不強的資料拆分到不同的instance上,從而達到消除瓶頸的目標。以圖中的為例,將使用者資訊資料,和業務資料拆分到不同的三個例項上。對於重複讀型別比較多的場景,我們還可以加一層cache,來減少對DB的壓力。
在這樣的架構下,我們來看看資料儲存的瓶頸是什麼?
1.單例項單業務 依然存在V1.0所述瓶頸
遇到瓶頸時可以考慮往本文更高V版本升級, 若是讀請求導致達到效能瓶頸可以考慮往V3.0升級, 其他瓶頸考慮往V4.0升級
V3.0 主從架構
此類架構主要解決V2.0架構下的讀問題,通過給Instance掛資料實時備份的思路來遷移讀取的壓力,在Mysql的場景下就是通過主從結構,主庫抗寫壓力,通過從庫來分擔讀壓力,對於寫少讀多的應用,V3.0主從架構完全能夠勝任
在這樣的架構下,我們來看看資料儲存的瓶頸是什麼?
1.寫入量主庫不能承受
V4.0 水平拆分
對於V2.0 V3.0方案遇到瓶頸時,都可以通過水平拆分來解決,水平拆分和垂直拆分有較大區別,垂直拆分拆完的結果,在一個例項上是擁有全量資料的,而水平拆分之後,任何例項都只有全量的1/n的資料,以下圖Userinfo的拆分為例,將userinfo拆分為3個cluster,每個cluster持有總量的1/3資料,3個cluster資料的總和等於一份完整資料(注:這裡不再叫單個例項 而是叫一個cluster 代表包含主從的一個小mysql叢集)
資料如何路由?
1.Range拆分
sharding key按連續區間段路由,一般用在有嚴格自增ID需求的場景上,如Userid, Userid Range的小例子:以userid 3000W 為Range進行拆分 1號cluster userid 1-3000W 2號cluster userid 3001W-6000W
2.List拆分
List拆分與Range拆分思路一樣,都是通過給不同的sharding key來路由到不同的cluster,但是具體方法有些不同,List主要用來做sharding key不是連續區間的序列落到一個cluster的情況,如以下場景:
假定有20個音像店,分佈在4個有經銷權的地區,如下表所示:
地區 | 商店ID 號 |
北區 | 3, 5, 6, 9, 17 |
東區 | 1, 2, 10, 11, 19, 20 |
西區 | 4, 12, 13, 14, 18 |
中心區 | 7, 8, 15, 16 |
業務希望能夠把一個地區的所有資料組織到一起來搜尋,這種場景List拆分可以輕鬆搞定
3.Hash拆分
通過對sharding key 進行雜湊的方式來進行拆分,常用的雜湊方法有除餘,字串雜湊等等,除餘如按userid%n 的值來決定資料讀寫哪個cluster,其他雜湊類演算法這裡就不細展開講了。
資料拆分後引入的問題:
資料水平拆分引入的問題主要是隻能通過sharding key來讀寫操作,例如以userid為sharding key的切分例子,讀userid的詳細資訊時,一定需要先知道userid,這樣才能推算出再哪個cluster進而進行查詢,假設我需要按username進行檢索使用者資訊,需要引入額外的反向索引機制(類似HBASE二級索引),如在redis上儲存username->userid的對映,以username查詢的例子變成了先通過查詢username->userid,再通過userid查詢相應的資訊。
實際上這個做法很簡單,但是我們不要忽略了一個額外的隱患,那就是資料不一致的隱患。儲存在redis裡的username->userid和儲存在mysql裡的userid->username必須需要是一致的,這個保證起來很多時候是一件比較困難的事情,舉個例子來說,對於修改使用者名稱這個場景,你需要同時修改redis和mysql,這兩個東西是很難做到事務保證的,如mysql操作成功 但是redis卻操作失敗了(分散式事務引入成本較高),對於網際網路應用來說,可用性是最重要的,一致性是其次,所以能夠容忍小量的不一致出現. 畢竟從佔比來說,這類的不一致的比例可以微乎其微到忽略不計(一般寫更新也會採用mq來保證直到成功為止才停止重試操作)
在這樣的架構下,我們來看看資料儲存的瓶頸是什麼?
在這個拆分理念上搭建起來的架構,理論上不存在瓶頸(sharding key能確保各cluster流量相對均衡的前提下),不過確有一件噁心的事情,那就是cluster擴容的時候重做資料的成本,如我原來有3個cluster,但是現在我的資料增長比較快,我需要6個cluster,那麼我們需要將每個cluster 一拆為二,一般的做法是
1.摘下一個slave,停同步,
2.對寫記錄增量log(實現上可以業務方對寫操作 多一次寫持久化mq 或者mysql主建立trigger記錄寫 等等方式)
3.開始對靜態slave做資料, 一拆為二
4.回放增量寫入,直到追上的所有增量,與原cluster基本保持同步
5.寫入切換,由原3 cluster 切換為6cluster
有沒有類似飛機空中加油的感覺,這是一個髒活,累活,容易出問題的活,為了避免這個,我們一般在最開始的時候,設計足夠多的sharding cluster來防止可能的cluster擴容這件事情
V5.0 雲端計算 騰飛(雲資料庫)
雲端計算現在是各大IT公司內部作為節約成本的一個突破口,對於資料儲存的mysql來說,如何讓其成為一個saas(Software as a Service)是關鍵點。在MS的官方文件中,把構建一個足夠成熟的SAAS(MS簡單列出了SAAS應用的4級成熟度)所面臨的3個主要挑戰:可配置性,可擴充套件性,多使用者儲存結構設計稱為"three headed monster". 可配置性和多使用者儲存結構設計在Mysql saas這個問題中並不是特別難辦的一件事情,所以這裡重點說一下可擴充套件性。
Mysql作為一個saas服務,在架構演變為V4.0之後,依賴良好的sharding key設計, 已經不再存在擴充套件性問題,只是他在面對擴容縮容時,有一些髒活需要幹,而作為saas,並不能避免擴容縮容這個問題,所以只要能把V4.0的髒活變成 1. 擴容縮容對前端APP透明(業務程式碼不需要任何改動) 2.擴容縮容全自動化且對線上服務無影響 那麼他就拿到了作為Saas的門票.
對於架構實現的關鍵點,需要滿足對業務透明,擴容縮容對業務不需要任何改動,那麼就必須eat our own dog food,在你mysql saas內部解決這個問題,一般的做法是我們需要引入一個Proxy,Proxy來解析sql協議,按sharding key 來尋找cluster, 判斷是讀操作還是寫操作來請求主 或者 從,這一切內部的細節都由proxy來遮蔽。
這裡借淘寶的圖來列舉一下proxy需要幹哪些事情
百度公開的技術方案中也有類似的解決方案,見文章最後資料部分連結
對於架構實現的關鍵點,擴容縮容全自動化且對線上服務無影響; 擴容縮容對應到的資料操作即為資料拆分和資料合併,要做到完全自動化有非常多不同的實現方式,總體思路和V4.0介紹的瓶頸部分有關,目前來看這個問題比較好的方案就是實現一個偽裝slave的sync slave, 解析mysql同步協議,然後實現資料拆分邏輯,把全量資料進行拆分。具體架構見下圖:
其中Sync slave對於Original Master來說,和一個普通的Mysql Slave沒有任何區別,也不需要任何額外的區分對待。需要擴容/縮容時,掛上一個Sync slave,開始全量同步+增量同步,等待一段時間追資料。以擴容為例,若擴容後的服務和擴容前資料已經基本同步了,這時候如何做到切換對業務無影響? 其實關鍵點還是在引入的proxy,這個問題轉換為了如何讓proxy做熱切換後端的問題。這已經變成一個非常好處理的問題了.
網站的效能問題?
本文將講述大型網站中一個重要的要素,效能。
什麼是效能
有人說效能就是訪問速度快慢,這是最直觀的說法,也是使用者的真實體驗。一個使用者從輸入網址到按下回車鍵,看到網頁的快慢,這就是效能。對於我們來說,需要去挖掘這個過程,因為這決定我們怎麼去做效能優化。
這中間發生了什麼?
使用者訪問網站的整個流程:使用者輸入網站域名,通過DNS解析,找到目標伺服器IP,請求資料經網際網路達到目標伺服器,目標伺服器收到請求資料,進行處理(執行程式、訪問資料庫、檔案伺服器等)。處理完成,將響應資料又經網際網路返回給使用者瀏覽器,瀏覽器得到結果進行計算渲染顯示給使用者。
我們把整個過程,分為三段路徑:
1、第一段在使用者和瀏覽器端,主要負責發出使用者請求,以及接受響應資料進行計算渲染顯示給使用者;
2、第二段在網路上,負責對請求資料、響應資料的傳輸;
3、第三段在網站伺服器端,負責對請求資料進行處理(執行程式、訪問資料庫、檔案等),並將結果返回;
第一路徑
第一路徑花費的時間包括輸入域名發起請求的時間和瀏覽器收到響應後計算渲染的時間。
輸入域名發起請求,實質過程是:
1、使用者在瀏覽器輸入要訪問的網站域名;
2、本地DNS請求網站授權的DNS伺服器對域名進行解析,並得到解析結果即IP地址(並將IP地址快取起來)。
3、向目標IP地址發出請求。
從這個過程我們可以看到,優化的地方主要是減少DNS解析次數,而如果使用者瀏覽器設定了快取,則再第二次訪問相同域名的時候就不會去請求DNS伺服器,直接用快取中的IP地址發出請求。因此這個過程主要取決於瀏覽器的設定。現在主流的瀏覽器預設設定了DNS的預取功能(DNS Prefetch),當然你也可以主動告知瀏覽器我的網站需要做DNS預取:
<meta http-equiv="x-dns-prefetch-control" content="on" />
瀏覽器將資料進行計算渲染的過程:
1、瀏覽器解析響應資料;
2、瀏覽器建立DOM樹;
3、瀏覽器下載CSS樣式,並應用到DOM樹,進行渲染;
4、瀏覽器下載JS檔案,開始解析執行;
5、顯示給使用者。
從這個過程,我們可以找出不少可以優化的地方。首先我們可以儘量控制頁面大小,使得瀏覽器解析的時間更短;並且將多個CSS檔案、JS檔案檔案合併壓縮減少檔案下載的次數和大小;另外注意將CSS放在頁面前面,JS訪問頁面後面,這樣便於頁面首先能渲染出來,再執行js指令碼,對於使用者來說有更好的體驗。最後我還可以設定瀏覽器快取,下次訪問時從快取讀取內容,減少http請求。
<meta http-equiv="Cache-Control" content="max-age=5" />
該程式碼說明了瀏覽器啟用了快取並在5秒內不會再次訪問伺服器。注意快取的設定需要結合你的業務特性來適當配置。
以下是京東商城的HTML簡圖:
css樣式放在html前面,並且進行了合併。
大多數的JS檔案放在頁尾。
第二路徑
第二路徑在網路上,花費的時間同樣包括請求資料的傳輸時間和響應資料的傳輸時間,這個兩個時間取決於資料傳輸的速度,這裡我們要講一個名詞“頻寬”。什麼是頻寬,我們經常說頻寬10M,20M是什麼意思?我的頻寬20M,這意味著什麼?我們知道頻寬速度分為上行、下行速度,也就是上傳和下載的速度。頻寬20M對於使用者來說則是下載速度20M(20×1024×1024位元率),換算成位元組20M/8=2.5M。也就是說20M的頻寬下載速度理論可達2.5M/s,而對於家庭使用者而言上傳速度一般比下載速度小的多,大約是不到十分之一。而對於網站伺服器(企業使用者)來說,則不然,一般上行速度等於下載速度。這也是運營商根據實際需求分配的,畢竟使用者的主要需求是下載資料,而不是上傳資料。
整個流程從傳輸方式看就是:使用者傳送請求資料(上傳),網站伺服器接受請求資料(下載),網站伺服器返回響應資料(上傳),使用者接受響應資料(下載)。對於使用者來說,上傳資料是很小的(Url引數),而下載資料是較大的(響應資料);對於伺服器來說,下載資料是很小的(url引數),上傳資料是較大(響應資料)。理解了這個,我們可以解釋為什麼有時使用者反映為什麼自己的頻寬足夠,但開啟某些網站仍然很慢,就是因為儘管使用者的下載速度很快,但網站伺服器的上傳速度很慢,這就像一個抽水管和一個出水管,不管抽水管再大,但出水管很小,同樣抽到的水量是有限的。瞭解了這個原理我們來看怎麼提高資料傳輸的速度,首先使用者的上傳、下載速度我們是無法決定的,我們能決定的是網站伺服器的上傳、下載速度,所以我們可以做的是適當的增加伺服器頻寬(頻寬是很貴的,盲目的增加只會增加不必要成本)。購買合適的頻寬需要根據網站業務特性、規模以及結合運維人員的經驗來選擇。通常可以考慮的演算法,即根據一次響應資料的大小,乘以PV數,除以對應的高峰時間段,從而大致估算出網站頻寬的需求。
下面我們繼續進一步研究第二路徑:
上圖表示使用者訪問網站伺服器時網路的大致情況,從圖上可以看出假設網站伺服器從電信網路接入,而使用者A作為電信的寬頻使用者,則可以通過電信骨幹網快速的訪問到網站伺服器。使用者B,使用者C作為移動和聯通使用者需要通過運營商的互聯互通經過較長路徑才能訪問到伺服器。
針對這種情況,我們可以採取以下方法來優化:
1、在各運營商發達的地區的IDC(網際網路資料中心,可以理解成機房)部署網站伺服器,各運營商的使用者即可通過各自的骨幹網訪問伺服器。
2、購買代理服務,也就是原來聯通使用者需要通過聯通骨幹網——>聯通互聯互通路由器——>電信骨幹網——>網站伺服器的過程。通過代理服務,代理伺服器直連到電信骨幹網,訪問網站伺服器。
2、在主要地區城市購買CDN服務,快取對應的資料,使用者可先從最近的CDN運營商獲取請求資料。
第三路徑
第三路徑主要是網站伺服器內部處理的過程,當中包括執行程式、訪問檔案、資料庫等資源。
這是對於我們來說最可以發揮的地方:
1、使用快取,根據需要使用本地快取或分散式快取;
2、使用非同步操作,這種方式不僅可以提高效能,也提高了系統的擴充套件性;
3、程式碼優化;
4、儲存優化;
快取
如果快取資料較少,可以利用OSCache實現本地快取:
當快取資料過多時,利用Memcached實現分散式快取:
Memcached實現分散式快取,快取伺服器之間是互不通訊的,也就是我們可以方便的通過增加Memcached伺服器對系統進行擴充套件。
非同步操作
使用同步請求的方式,在高併發的情況下,會對資料庫造成很大的壓力,也會讓使用者感覺響應時間過長。非同步請求方式,則可以快速的對使用者做出響應,而具體的資料庫操作請求,則通過訊息佇列伺服器傳送給資料庫伺服器