寫這篇文章之前,需要有些論點和論據,以表明網絡系統在極端情況下的情況,先來看看世界上排名靠前的網站。
1、???????????? FaceBook
2、???????????? Google
?
從這兩個站可以看出,當下比較極限的日均訪問量在2~3億,PV值達到4~5億
就算是很龐大的系統了。
?
下面要用通俗一點的話講一下這個互聯網的訪問過程。
從上面的過程中文明知道,Whois我們是無法左右的,我們的可以著手負載的地方就是DNS級別開始。域名解析到DNS,具體和什么IP進行交互,可以由DNS動態綁定分配。
首先我們要測定一個理論值,測試一下單機極端能力情況下的結果。
測試機器配置
?
測試代碼:
private void button1_Click(object sender, EventArgs e)
??????? {
??????????? //1000萬臺服務器折半查找,10次
??????????? string ees = "";
??????????? long dtst = DateTime.Now.Ticks;
??????????? for (int i = 0; i < 100000000; i++)
??????????? {
??????????????? ees = "211.112.111.212";
??????????? }
??????????? string dted = TimeSpan.FromTicks(DateTime.Now.Ticks - dtst).ToString();
??????????? MessageBox.Show(dted);
??????? }
?
?
測試結論:
本次測試采用的是筆記本上網本電腦,凌動(Atom)處理器1.6Ghz的主頻。循環賦值了一億次,時間大概為1秒左右。現在的服務器的至強CPU運算速度能力至少在Atom的運算速度的10倍以上。從DNS解析中,中間可能要涉及到IP地址的路徑查找,就算一臺DNS解析器帶一萬臺服務器,一萬臺服務器IP地址進行排序后,折半查找路徑查找路徑的計算過程為10000/2=5000/2=2500/2=1250/2=625/2=314/2=157/2=78/2=39/2=19/2=9/2=4/2=2/2=1,計算結果后,一共是計算了14次。就拿本次測試CPU的可以接受結果1億來計算。
100000000/14=7142857
相當于1萬臺服務器,每臺每秒分配可以并發7142857的DNS返回值。
?
從單臺電腦的并發來看,如果每秒可以解析轉發700多萬次。這樣每分鐘42000萬,每小時2520000萬次,就拿一天24小時,可能網站的高峰期為8小時吧,因為很多人都是在醒著的時候訪問網站,2520000*8=20160000萬次,也就是20160億次。這個數據比較現在極端情況下的網站來講,日均訪問量的PV最多也不超過5億。更何況現在采用測試配置是那么的低,一般服務器CPU都要比這速度高十倍以上。當然,本次測試并沒有考慮到帶寬線路等問題,但是理論結果,想證明的是,從DNS開始進來解決負載問題是可行的結果。基本不用考慮是否會對DNS服務器造成多大的壓力。
架構原理
現今面臨的Web有幾種:
1.?????? CMS內容管理系統,就是類似一些門戶網站,發些新聞資訊等內容。
2.?????? B2B B2C商城系統,里面有商品,有購物車,還有賬戶,還有針對商品的分類以及查詢。
3.?????? 論壇/博客/微博系統,就是每一個用戶都有發信息,讀信息的權限功能。
4.?????? 搜索引擎,就是利用蜘蛛程序把網站信息爬到系統內部,然后分析整理出關鍵字,以關鍵字作為索引,對內容進行整理。
5.?????? OA/CRM/MIS等辦公后臺類型系統,能涉及到醫藥,社保,公安等等諸多系統。
面臨問題:
一般網站面臨的問題就是負載的問題,當人數多,導致速度慢是主要解決的問題。 而其實最主要原因就是瓶頸問題,現在很多網站都是一個DNS綁定一個網站IP的A記錄,然后為了達到功能上的負載,可能會利用二級域名綁定N個IP,然后相互利用入口進行從功能上的切割達到負載目的。而第二個瓶頸點,就是數據庫,無論用什么樣的數據庫服務器,單機作戰一定有它的最大負荷,如并發連接過大,數據過多,就容易導致數據返回慢,從而導致前臺web服務器應用的速度慢。
技術原理:
數據庫有些問題,首先就是當數據大了,多了的時候,面臨的問題就是查詢速度。學過數據結構的人都則,數據庫的查詢速度增加,可以利用折半查找方式,而折半查找,就需要一個排序好的文件數據。這就是數據庫中所謂的索引。而帶索引字段的表,有一個弊,因為每次要排序的字段都要重新尋找位置,所以在插入修改刪除數據的時候,一定會更新一下索引表,導致增刪改的操作速度會慢,數據越大,它越慢。
下面做一個測試:
測試一(返回數據):
條件一:
未加索引
數據庫總共數據,200多萬
條件二:
Type加索引
數據庫總共數據,200多萬
從以上的測試可以對比
未加索引 | 加了索引 |
| |
Top:1% Scan Table: 99% | Top:6% Scan Table: 94% |
3秒 | 2秒 |
測試二(模糊查詢):
?
未加索引
?
帶索引
數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。索引的實現通常使用B樹及其變種B+樹。
在數據之外,數據庫系統還維護著滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
為表設置索引要付出代價的:一是增加了數據庫的存儲空間,二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)。
上圖展示了一種可能的索引方式。左邊是數據表,一共有兩列七條記錄,最左邊的是數據記錄的物理地址(注意邏輯上相鄰的記錄在磁盤上也并不是一定物理相鄰的)。為了加快Col2的查找,可以維護一個右邊所示的二叉查找樹,每個節點分別包含索引鍵值和一個指向對應數據記錄物理地址的指針,這樣就可以運用二叉查找在O(log2n)的復雜度內獲取到相應數據。
?
創建索引可以大大提高系統的性能。
第一,通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。
第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。
第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。
第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。
第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。?
?
也許會有人要問:增加索引有如此多的優點,為什么不對表中的每一個列創建一個索引呢?因為,增加索引也有許多不利的方面。
第一,創建索引和維護索引要耗費時間,這種時間隨著數據量的增加而增加。
第二,索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大。
第三,當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。
?
索引是建立在數據庫表中的某些列的上面。在創建索引的時候,應該考慮在哪些列上可以創建索引,在哪些列上不能創建索引。一般來說,應該在這些列上創建索引:在經常需要搜索的列上,可以加快搜索的速度;在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度。
?
同樣,對于有些列不應該創建索引。一般來說,不應該創建索引的的這些列具有下列特點:
第一,對于那些在查詢中很少使用或者參考的列不應該創建索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,并不能提高查詢速度。相反,由于增加了索引,反而降低了系統的維護速度和增大了空間需求。
第二,對于那些只有很少數據值的列也不應該增加索引。這是因為,由于這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,并不能明顯加快檢索速度。
第三,對于那些定義為text, image和bit數據類型的列不應該增加索引。這是因為,這些列的數據量要么相當大,要么取值很少。
第四,當修改性能遠遠大于檢索性能時,不應該創建索引。這是因為,修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改性能遠遠大于檢索性能時,不應該創建索引。
?
根據數據庫的功能,可以在數據庫設計器中創建三種索引:唯一索引、主鍵索引和聚集索引。
唯一索引?
唯一索引是不允許其中任何兩行具有相同索引值的索引。
當現有數據中存在重復的鍵值時,大多數數據庫不允許將新創建的唯一索引與表一起保存。數據庫還可能防止添加將在表中創建重復鍵值的新數據。例如,如果在employee表中職員的姓(lname)上創建了唯一索引,則任何兩個員工都不能同姓。
主鍵索引
數據庫表經常有一列或列組合,其值唯一標識表中的每一行。該列稱為表的主鍵。
在數據庫關系圖中為表定義主鍵將自動創建主鍵索引,主鍵索引是唯一索引的特定類型。該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對數據的快速訪問。
聚集索引
在聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同。一個表只能包含一個聚集索引。
如果某索引不是聚集索引,則表中行的物理順序與鍵值的邏輯順序不匹配。與非聚集索引相比,聚集索引通常提供更快的數據訪問速度。
?
?
由于存儲介質的特性,磁盤本身存取就比主存慢很多,再加上機械運動耗費,磁盤的存取速度往往是主存的幾百分分之一,因此為了提高效率,要盡量減少磁盤I/O。為了達到這個目的,磁盤往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個字節,磁盤也會從這個位置開始,順序向后讀取一定長度的數據放入內存。這樣做的理論依據是計算機科學中著名的局部性原理:當一個數據被用到時,其附近的數據也通常會馬上被使用。程序運行期間所需要的數據通常比較集中。
由于磁盤順序讀取的效率很高(不需要尋道時間,只需很少的旋轉時間),因此對于具有局部性的程序來說,預讀可以提高I/O效率。
預讀的長度一般為頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操作系統往往將主存和磁盤存儲區分割為連續的大小相等的塊,每個存儲塊稱為一頁(在許多操作系統中,頁得大小通常為4k),主存和磁盤以頁為單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會找到數據的起始位置并向后連續讀取一頁或幾頁載入內存中,然后異常返回,程序繼續運行。
到這里終于可以分析B-/+Tree索引的性能了。
上文說過一般使用磁盤I/O次數評價索引結構的優劣。先從B-Tree分析,根據B-Tree的定義,可知檢索一次最多需要訪問h個節點。數據庫系統的設計者巧妙利用了磁盤預讀原理,將一個節點的大小設為等于一個頁,這樣每個節點只需要一次I/O就可以完全載入。為了達到這個目的,在實際實現B-Tree還需要使用如下技巧:
每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁里,加之計算機存儲分配都是按頁對齊的,就實現了一個node只需一次I/O。
B-Tree中一次檢索最多需要h-1次I/O(根節點常駐內存),漸進復雜度為O(h)=O(logdN)。一般實際應用中,出度d是非常大的數字,通常超過100,因此h非常小(通常不超過3)。
而紅黑樹這種結構,h明顯要深的多。由于邏輯上很近的節點(父子)物理上可能很遠,無法利用局部性,所以紅黑樹的I/O漸進復雜度也為O(h),效率明顯比B-Tree差很多。
?
綜上所述,用B-Tree作為索引結構效率是非常高的。
?
?
應該花時間學習B-樹和B+樹數據結構
=============================================================================================================
1)B樹
B樹中每個節點包含了鍵值和鍵值對于的數據對象存放地址指針,所以成功搜索一個對象可以不用到達樹的葉節點。
成功搜索包括節點內搜索和沿某一路徑的搜索,成功搜索時間取決于關鍵碼所在的層次以及節點內關鍵碼的數量。
在B樹中查找給定關鍵字的方法是:首先把根結點取來,在根結點所包含的關鍵字K1,…,kj查找給定的關鍵字(可用順序查找或二分查找法),若找到等于給定值的關鍵字,則查找成功;否則,一定可以確定要查的關鍵字在某個Ki或Ki+1之間,于是取Pi所指的下一層索引節點塊繼續查找,直到找到,或指針Pi為空時查找失敗。
2)B+樹
B+樹非葉節點中存放的關鍵碼并不指示數據對象的地址指針,非也節點只是索引部分。所有的葉節點在同一層上,包含了全部關鍵碼和相應數據對象的存放地址指針,且葉節點按關鍵碼從小到大順序鏈接。如果實際數據對象按加入的順序存儲而不是按關鍵碼次數存儲的話,葉節點的索引必須是稠密索引,若實際數據存儲按關鍵碼次序存放的話,葉節點索引時稀疏索引。
B+樹有2個頭指針,一個是樹的根節點,一個是最小關鍵碼的葉節點。
所以 B+樹有兩種搜索方法:
一種是按葉節點自己拉起的鏈表順序搜索。
一種是從根節點開始搜索,和B樹類似,不過如果非葉節點的關鍵碼等于給定值,搜索并不停止,而是繼續沿右指針,一直查到葉節點上的關鍵碼。所以無論搜索是否成功,都將走完樹的所有層。
B+ 樹中,數據對象的插入和刪除僅在葉節點上進行。這兩種處理索引的數據結構的不同之處:
a,B樹中同一鍵值不會出現多次,并且它有可能出現在葉結點,也有可能出現在非葉結點中。而B+樹的鍵一定會出現在葉結點中,并且有可能在非葉結點中也有可能重復出現,以維持B+樹的平衡。
b,因為B樹鍵位置不定,且在整個樹結構中只出現一次,雖然可以節省存儲空間,但使得在插入、刪除操作復雜度明顯增加。B+樹相比來說是一種較好的折中。
c,B樹的查詢效率與鍵在樹中的位置有關,最大時間復雜度與B+樹相同(在葉結點的時候),最小時間復雜度為1(在根結點的時候)。而B+樹的時候復雜度對某建成的樹是固定的。
架構設計:
由于數據庫的單臺負載能力問題,所以,數據量到一定規模,無論什么數據庫,都有一定的瓶頸在里面。所以分布式數據庫是需要考慮的。就像Google那么大的數據量,根本就不可能單臺服務器能解決,也不是哪一個服務器機房的集群能解決的,Google利用GFS分布式存儲一樣。
1、 CMS內容管理系統,就是類似一些門戶網站,發些新聞資訊等內容。
擋在前面的就應該是靜態頁面的緩存,這需要每次刷一次新內容,要把數據庫動態內容進行生成靜態頁面,可以利用CDN服務器,進行內容分發負載。也可以部署分布式文件服務器,利用DNS動態解析來進行負載。因為網絡上有很多服務器節點,被分發到同樣的數據內容。這樣,客戶訪問會找到最近得節點進行連接從而達到負載目的。
訪問操作流程:
客戶訪問:
客戶首先通過DNS服務器找到最近的CDN節點。從節點讀出緩存的靜態內容,當客戶想進行數據的查詢的時候,才調用Web服務器的程序內容,數據庫服務器里的表結構都是一樣的,由于數據庫可能會成為瓶頸,所以Web服務器會去一個使用率并不高的數據庫節點進行查詢。因為Web服務器也是個集群,系統在緩存內容的時候,就自動分配一個Web服務器寫到CDN所緩存的內容里。這樣,就可以靈活調配 (緩存-Web-數據庫) 的數量,當訪問量達到一定量,系統變慢,可以合理分析出原因,高松散耦合性的增加服務器。
后臺操作:
內容分發管理應該有一個專門的后臺系統,訪問數據庫其中的任何一個固定的數據庫,然后連接,當進行增刪改操作的時候,這臺服務器立刻進行響應結果,然后把對應的SQL語句發送到消息隊列,同步其他數據庫的相關內容。同時通知緩存整理服務器訪問這臺固定的數據庫,進行緩存內容整理上傳到CDN。??????
以上圖例負載如果是都在內網,也可以采用類似F5,LVS那種負載分發機配合緩存服務器進行解決。
系統特點:適用于更新相對不是特別頻繁的企業站,門戶網站,新聞類,分類信息等等網站。
2、 B2B B2C商城系統,里面有商品,有購物車,還有賬戶,還有針對商品的分類以及查詢
這種網站類型,里面涉及到交易,交易就涉及到事務,如果是單臺服務器數據庫,可以用事務進行解決,但是單臺數據庫服務器到一定規模,遠遠的達不到性能負載要求。而且,系統要解決有幾方面的問題,對于新發布的商品,要有查看和查詢,面臨著客戶的訪問量也是需要考慮高負載并發的,同時,又要兼顧買賣交易問題。這一點,淘寶做的就很好。他的原理就是相當于有若干個小的商城網站系統,然后利用淘寶平臺把所有小的商城網站聯系在一起。
訪問操作流程
客戶注冊后,在把信息錄入到某個小商城網站的同時留在用戶索引數據庫一份索引值,來記錄這個用戶屬于哪個小商城網站的。在登錄的時候,通過用戶索引數據庫,就把對應的客戶Session狀態固定在當初注冊的小商品網站上。小商品網站數據庫采用雙機熱備形式,里面有店商的產品資料,客戶資料,客戶的購物車資料,以及當天的交易記錄資料。交易記錄每天要把其交易信息填入到歷史交易數據庫中,并按著日期進行添加索引。這樣保證工作表數據一直都是少的,操作起來就會很快。店商把產品信息發布的同時,也推送到CMS系統一份,CMS系統進行內容分類整理緩存索引等。當客戶登錄后,首先通過CMS系統整體搜索自己想要的關鍵字以及分類信息,搜素到后,點擊就進入提供商品信息小商城網站服務器下瀏覽。添加購物車的時候,是把對方的商品編號記錄在自己注冊的小商城服務器下。最后是交易。由于有可能注冊的服務器,和提供商品的服務器不是同一服務器,所以,要借助中間交易服務器進行清算。就像支付寶一樣,一方面客戶服務器預付款,同時交易服務器向商品提供電商發送指令預減去商品數量,然后交易服務器最后匯總并向兩臺服務器同時保證交易的事務性。當然,在交易過程中,商品數量被其他交易影響減為零的時候,預付款也會進行回滾,把錢還給客戶。
異常處理:
在客戶端向商品服務器提送預減商品的同時,自己的交易狀態表就要掛起,同一時間只能有一個交易狀態,一個交易狀態結束后,才可以進行下一個交易,如果客戶在交易途中出現如網絡斷線等問題時候,異常進行等待。等恢復后,客戶端向交易服務器請求詢問商品服務器是否狀態交易成功,成功后,自己把欠款扣下恢復到非交易狀態,如果未成功,就把欠款恢復到交易以前。當然,在斷線后,商品服務器有可能接手不到交易服務器的確認信息,可以在1分鐘后超時,恢復狀態。
系統特點:系統有很多瓶頸,當發現小商城網站不夠用或飽和的時候,可以無限增加小商品網站和數據庫服務器,也可以按著地域和注冊時候的IP,選擇就近可以操作服務器進行注冊和操作。搜索商品信息,可以利用上面的CMS系統框架,可以承受很大的負載,同時保證兩者的高松散耦合性。
3、論壇/博客/微博系統,就是每一個用戶都有發信息,讀信息的權限功能。
和商城系統的理念差不多,前端為了解決用戶并發訪問的問題,還是要用CMS來解決問題。同時為了解決客戶操作龐大問題,也是要用戶索引表,索引到每一臺Web服務器上。不過這種發文章性質的系統,在發布到CMS系統之前,要根據相關法律規定,要對內容有審核,也許是人工審核,也許是系統關鍵字審核。
訪問和操作流程:
注冊的時候,根據網絡情況系統固定分配一臺論壇Web服務器,比如論壇web服務器1。客戶登錄后就進入論壇Web服務器1系統,客戶在系統上進行寫文章,發文章,發出的文章同時提交到內容審核數據庫,審核成功后就發送到CMS系統上。然后其他可以通過CMS系統可以查找到你的對應文章。
4、搜索引擎,就是利用蜘蛛程序把網站信息爬到系統內部,然后分析整理出關鍵字,以關鍵字作為索引,對內容進行整理。
顧名思義搜索引擎的數據內容,都是利用蜘蛛程序在網絡上爬下來的,然后進行針對用戶搜索的關鍵字,漢字常用詞組等進行索引連接制作。比如,客戶搜索? “大連 北京 機票”,搜索引擎會同時對這三個關鍵字的索引進行展開搜索。其次就是對服務器的內容進行整理,建立索引的過程。
訪問操作流程:
客戶通過DNS尋找到CDN節點后,輸入關鍵字內容,然后服務器邏輯把關鍵字內容用 空格或其他符號進行拆分出幾個關鍵字。然后到關鍵字索引數據庫中進行查詢,返回的結果排序自然是根據SEO規則進行(詳細情況請搜索“SEO”),同時如果發現關鍵字數據庫里沒有的,就把新的關鍵字記錄到關鍵字數據庫。返回的結果集可以通過連接,連接到當初抓取數據的數據庫,同時也可以利用快照地址讀取分布式文件系統里抓取的快照內容查看。
蜘蛛服務器程序每天實時的在互聯網上獲取新的快照網頁信息。加工關鍵字符服務器擁有中國漢字里常見的詞組和詞句,并聯合客戶本身輸入的關鍵字數據庫,在蜘蛛抓到的快照內容中不斷的比對并制作關鍵字索引到索引服務器上。為了解決負載問題,同時去更新多個關鍵字索引數據庫,以便前臺Web服務器分布式連接。
5、OA/CRM/MIS等辦公后臺類型系統,能涉及到醫藥,社保,公安等等諸多系統。
這類系統要求可能會要求比較復雜,首先是要求查詢速度,其次是要求更新的要及時。就是說,要更新馬上出結果,查詢馬上能找到剛剛更新的內容。前段入口有幾種方式。
一、可以采用緩存形式DNS+CDN,緩存的類似前臺框架,比如extjs,或者jquery的框架內容,登錄后,利用js級別的程序,去確定連接哪臺web服務器,因為這種無刷新框架采用的幾乎都是數據傳輸模式,這就有點像寫Winform+Winserver(CS模式),只不過其中的Client是用JS寫的,服務器也是JS去選擇的。
二、可以才用二級域名綁定,或者干脆使用IP,當客戶在頁面登陸后,自動跳轉到對應的系統。
這類系統,一定是各個分部,乃至各個部門都有自己的服務和分系統,這種架構思想其實就是把所有業務一樣的系統,利用一個查詢庫聯系起來,各個分系統實時上傳最新的消息,以備其他系統
訪問操作流程:
客戶通過一個總入口,進入到分系統,每個分系統服務器就在一部門內部,比如:公安系統,在某個分局或派出所。當然,這種松散耦合就直接可以考增加分系統解決,比如某派出所系統達到飽和,可以在增加一套分系統,比如分局二號網。
而整體聯網的重擔就肩負在上傳信息的服務器上了。數據庫有個矛盾點,數據加了索引,查詢速度快,而增刪改的速度就慢。而數據少的數據庫,查詢速度也很快,利用這個特點,分系統在進行增刪改的同時,向工作數據庫提交一份備份信息,在有另一臺服務器實時的把數據拷貝到歷史數據庫并生成索引,當查詢的時候,同時從兩臺服務器共同返回結果。當有刪和改的數據時,要在工作數據庫中進行標注,改的數據,以工作庫為準,刪的數據即使從歷史索引數據庫里提出來,也不進行顯示。在查詢中,勢必要有分頁算發,當兩張表進行并的時候,所以就要在查詢時候,功能上有所區別。分上下兩個表顯示。在查單條信息時,合并兩個表選出內容即可。
?