1. 程式人生 > >轉 瘋狂程式碼 大型網站架構系列 未完待續

轉 瘋狂程式碼 大型網站架構系列 未完待續

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

 

 

作者:瘋狂程式碼

來源:http://www.crazycoder.cn

 

大型網站架構系列之一 不得不考慮的問題

 

 

前言:這兩天機器壞了,正在送修中,寫個系列的大型網站架構的文章,希望對有志在網際網路做出一番事業的站長朋友們一些幫助。

  注意:這裡的大型網站架構只包括高互動性高互動性的資料型大型網站,基於大家眾所周知的原因,我們就不談新聞類和一些依靠HTML靜態化就可以實現的架構了,我們以高負載高資料交換高資料流動性的網站為例,比如海內,開心網等類似的web2.0系列架構。我們這裡不討論是PHP還是JSP或者.NET環境,我們從架構的方面去看問題,實現語言方面並不是問題,語言的優勢在於實現而不是好壞,不論你選擇任何語言,架構都是必須要面對的。

  文入正題:

  首先討論一下大型網站需要注意和考慮的問題

  A. 海量資料的處理。

  眾所周知,對於一些相對小的站點來說,資料量並不是很大,select和update就可以解決我們面對的問題,本身負載量不是很大,最多再加幾個索引就可以搞定。對於大型網站,每天的資料量可能就上百萬,如果一個設計不好的多對多關係,在前期是沒有任何問題的,但是隨著使用者的增長,資料量會是幾何級的增長的。在這個時候我們對於一個表的select和update的時候(還不說多表聯合查詢)的成本的非常高的。

  B. 資料併發的處理

  在一些時候,2.0的CTO都 有個尚方寶劍,就是快取。對於快取,在高併發高處理的時候也是個大問題。在整個應用程式下,快取是全域性共享的,然而在我們進行修改的時候就,如果兩個或者 多個請求同時對快取有更新的要求的情況下,應用程式會直接的死掉。這個時候,就需要一個好的資料併發處理策略以及快取策略。

  另外,就是資料庫的死鎖問題,也許平時我們感覺不到,死鎖在高併發的情況下的出現的概率是非常高的,磁碟快取就是一個大問題。

  C. 檔案存貯的問題

  對於一些支援檔案上傳的2.0的站點,在慶幸硬碟容量越來越大的時候我們更多的應該考慮的是檔案應該如何被儲存並且被有效的索引。常見的方案是對檔案按照日期和型別進行存貯。但是當檔案量 是海量的資料的情況下,如果一塊硬碟存貯了500個G的瑣碎檔案,那麼維護的時候和使用的時候磁碟的Io就是一個巨大的問題,哪怕你的頻寬足夠,但是你的磁碟也未必響應過來。如果這個時候還涉及上傳,磁碟很容易就over了。

  也許用raid和專用存貯伺服器能解決眼下的問題,但是還有個問題就是各地的訪問問題,也許我們的伺服器在北京,可能在雲南或者新疆的訪問速度如何解決?如果做分散式,那麼我們的檔案索引以及架構該如何規劃。

  所以我們不得不承認,檔案存貯是個很不容易的問題

  D. 資料關係的處理

  我們可以很容易的規劃出一個符合第三正規化的資料庫,裡面佈滿了多對多關係,還能用GUID來替換INDENTIFY COLUMN 但是,多對多關係充斥的2.0時代,第三正規化是第一個應該被拋棄的。必須有效的把多表聯合查詢降到最低。

  E. 資料索引的問題

  眾所周知,索引是提高資料庫效率查詢的最方面最廉價最容易實現的方案。但是,在高UPDATE的情況下,update和delete付出的成本會高的無法想想,筆者遇到過一個情況,在更新一個聚焦索引的時候需要10分鐘來完成,那麼對於站點來說,這些基本上是不可忍受的。

  索引和更新是一對天生的冤家,問題A,D,E這些是我們在做架構的時候不得不考慮的問題,並且也可能是花費時間最多的問題,

  F. 分散式處理

  對於2.0網站由於其高互動性,CDN實現的效果基本上為0,內容是實時更新的,我們常規的處理。為了保證各地的訪問速度,我們就需要面對一個絕大的問題,就是如何有效的實現資料同步和更新,實現各地伺服器的實時通訊有是一個不得不需要考慮的問題。

  G. Ajax的利弊分析

  成也AJAX,敗也AJAX,AJAX成為了主流趨勢,突然發現基於XMLHTTP的post和get是如此的容易。客戶端get或者post到伺服器資料,伺服器接到資料請求之後返回來,這是一個很正常的AJAX請求。但是在AJAX處理的時候,如果我們使用一個抓包工具的話,對資料返回和處理是一目瞭然。對於一些計算量大的AJAX請求的話,我們可以構造一個發包機,很容易就可以把一個webserver幹掉。

  H. 資料安全性的分析

  對於HTTP協議來說,資料包都是明文傳輸的,也許我們可以說我們可以用加密啊,但是對於G問題來說的話,加密的過程就可能是明文了(比如我們知道的QQ,可以很容易的判斷他的加密,並有效的寫一個跟他一樣的加密和解密方法出來的)。當你站點流量不是很大的時候沒有人會在乎你,但是當你流量上來之後,那麼所謂的外掛,所謂的群發就會接踵而來(從qq一開始的群發可見端倪)。也許我們可以很的意的說,我們可以採用更高級別的判斷甚至HTTPS來實現,注意,當你做這些處理的時候付出的將是海量的database,io以及CPU的成本。對於一些群發,基本上是不可能的。筆者已經可以實現對於百度空間和qq空間的群發了。大家願意試試,實際上並不是很難。

  I. 資料同步和叢集的處理的問題

  當我們的一臺databaseserver不 堪重負的時候,這個時候我們就需要做基於資料庫的負載和叢集了。而這個時候可能是最讓人困擾的的問題了,資料基於網路傳輸根據資料庫的設計的不同,資料延 遲是很可怕的問題,也是不可避免的問題,這樣的話,我們就需要通過另外的手段來保證在這延遲的幾秒或者更長的幾分鐘時間內,實現有效的互動。比如資料散 列,分割,內容處理等等問題

  K.資料共享的渠道以及OPENAPI趨勢

  Openapi已經成為一個不可避免的趨勢,從google,facebook,myspace到 海內校內,都在考慮這個問題,它可以更有效的留住使用者並激發使用者的更多的興趣以及讓更多的人幫助你做最有效的開發。這個時候一個有效的資料共享平臺,資料 開放平臺就成為必不可少的途徑了,而在開放的介面的情況保證資料的安全性和效能,又是一個我們必須要認真思考的問題了。

  當然還有更多需要考慮的問題,我這裡就寫一個最需要考慮的問題,歡迎補充。下一篇文章將針對問題A,提出具體的解決方案和思路

 

 

 

大型網站架構系列之二 底層架構概論

 

首先澄清上篇中關於幾個朋友的評論。

  上篇介紹的基於AJAX的攻擊很多人提出疑問,比如不能跨域,減輕負擔之類。Ajax是通過簡單的GET和POST進行資料傳遞的,採用HTTPDEBUGGER,抓取資料,然後採用如下方案,順便寫個示例的攻擊程式碼.比傳統的webform,我們更容易構造一些,其實對於webform和ajax的處理和發包過程是一樣的,ajax資料量相對小,速度也快一些。

  結合SharpPcap和HttpWebRequest我們構造一個合理的正常的IP資料包過去,程式碼很長,我們用虛擬碼簡單的表達一下。

  request.CreateUrl(Ajax處理頁面);

  request.Method=”GetORPost”;

  request.refere=”網頁來源”;

  SharpPcap.SetLinkConnection(偽造IP地址);

  String content = request.GetResponseStream() 如果作為一個多執行緒的應用程式對對方的WEB構成批量發包的話(假如是DEDECMS),足可以把Dedecms的資料庫搞垮

  文入正題:

  對於上回書提到要解決問題A,我們先講解一下電信公司ADSL的佈局方案。機器上沒有裝VISIO,我簡單的用文字描述一下流程。

  Adsl使用者Aè輸入使用者名稱密碼è遠端連線到賬戶資料庫(在天津)è賬戶資料庫連線計費資料庫並返回狀è如果成功,連線PPPOE伺服器,並進一步連線計費資料庫è認證服務並連線。

  這裡沒有什麼特別的地方,但是和qq通訊服務是一樣的,就是採用了統一的使用者驗證伺服器,同時對於使用者驗證的資訊資料庫是隻讀的,我們從其中可以想到什麼嗎?

  以上是個簡單的例子,下面開始談具體的架構策略,首先對於上篇提到的問題A,我們首先以使用者資料庫為例來做解釋和要求。

  首先做使用者量估算需求,假如我們做的是學術社群,那麼這個使用者量不會很大,可能我們不需要考慮這個,對於使用者量的級別,我們暫時把使用者量級別定為三種,百萬級別(M)和千萬界別(S),以及億萬級別(Q),並考慮使用者登入驗證以及查詢常用的操作,對M和S進行擴充以及瞭解。

  眾所周知,在這個情況下,對於使用者資料的負載其實並非可行而不可行的問題,而是如何最大化的保證查詢和更新以及各個伺服器之間的資料同步。這裡我們不再講解如何優化如何索引,只介紹架構初期的方案,下面介紹的方案如果涉及全表查詢,可以採用分割槽檢視的方案,大家可以具體搜尋相關資料。

  對於M級別來說,現有的DBMS經過合理的佈局完全可以滿足需求。我們需要解決的問題的關鍵其實是處理IO方面的問題,處理方案相對簡單一些,對資料庫的FILE檔案分磁碟存貯(不是分割槽,是不同的硬碟),根據負載量大小,我們可以適當的控制硬碟的數量和檔案分割槽的數量。

  對於S級別,上個處理方案已經不能完全滿足需求了,這個時候我們需要對註冊和入庫的流程進行簡單的修改了,解決方案是資料雜湊和分割槽檢視的概念,具體概念大家去google一下,我不詳細說明了。

  我們常用的方案有三種。第一種是等容擴充法,在使用者註冊控制的基礎上,保證每個庫的使用者容量不超過500萬,超過之後入第二個庫,以此類推,這個方案可以保證系統有效的擴充性,但不能保證資料被有效的索引。第二種就是共區索引方案,其實和第一種方案有異曲同工的之說但是講第一種方案進行了合理的優化,按照使用者名稱進行分庫存貯。比如我們可以建立26的資料庫,按照使用者名稱的索引來控制使用者資料入哪個庫。假如使用者名稱是CrazyCoder,那麼就講該使用者名稱的資料存放在使用者表C中,在資料存貯的時候可以很方便的根據使用者名稱進行相應的資料查詢,方案二可以有效的解決資料索引問題。方案三是一個更具模型化的方案,結合方案一和方案二,進行使用者ID的編碼,不是INDENTIFY Cloumn,我們用一種序列化的方案將使用者名稱以編碼的形式存貯,比如使用者名稱是CrazyCoder,我們的編碼方案就是通過演算法進行數字化,將CrazyCoder按照C,R,A,….存貯為數字索引,然後進行分割槽存貯,數字型別的資料在資料庫中可以更有效的被查詢和被更新和共享,結合方案一和方案二這個就是方案三。

  對於Q級別。資料量已經是足夠海量了,這個時候無論用哪種方案都是一個讓人頭大的資料,不能簡單的用查詢的方案來處理了,可以參考S級別的進行處理。但這個時候我們採用的方案是根據使用者活躍度的權值結合資料量進行臨時資料表的存放。如果一個非意外的資料情況下,每天登入的使用者量不會上千萬。這個時候我們需要做的是一個簡單的資料代理程式。一個臨時的使用者驗證資料庫,每天執行一次批處理,將活躍度高的使用者賬戶提取到臨時資料庫中,查詢的時候先查詢臨時庫,如果沒有在進行全庫查詢。這個根據系統的負載情況來估計閾值,不同的系統估算方案也不盡相同。

  上面對於,M,S,Q三種界別進行了簡單的概述,下面介紹一個在其之上更高階的一個查詢方案,資料快取伺服器,我們也可以把它理解為緩衝伺服器,資料做為只讀來使用。

  具體實現方案如下:以為涉及了海量,DBMS常規的快取方案已經不符合我們的要求了,那麼我們需要一個有效的快取方案,這個時候處理的流程其實就是講最常用最直接的資料直接存放在快取伺服器中,而這個快取伺服器定時從主伺服器獲取並更新資訊。這個是一個簡單的查詢,我們還可以更深入的講快取伺服器做二次快取,也就是一次性處理輸入並存放到LIST資料中,作為全域性變數放到記憶體中進行查詢,同時用HASHTABLE或者陣列進行資料組索引(可以是多級),根據查詢分佈到各個變數中。直接從記憶體中讀取資料。

  以筆者的經驗來說的話,對於ITEM資料不超過10K的來說,每個列表最佳的存放範圍是0到6萬之間。

  這裡簡單的介紹了一下DBMS基本架構,裡面具體細節處理的還有很多,這裡只介紹個大概的綱要。有問題請給我發郵件(Heroqst # Gmail.com),請講#替換為@

  這裡只是簡單的介紹了一下DBMS的基本佈局,下章講具體對我們常見的多對多關係資料庫進行具體配置說明。

  首先介紹一下問題的大概,比如對於文章和標籤,每個文章可以有多個標籤,而每個標籤下又會有多個文章,那麼資料量將是文章數乘以標籤數,這個時候如何進行處理並有效的索引,將是下章要介紹的內容。

 

 

 

大型網站架構系列之三 多對多關係的優化設計

 

上篇以使用者資料表為例介紹了基本的資料分割方案以及基本的配置方案。但是在2.0時代,這種簡單的列表索引已經遠遠實現起來是問題的,多對多關 系將是最常見的關係。現在我們針對web2.0資料中廣泛存在的多對多關係進行闡述和具體行為判斷,比如一個很簡單的例子,在2.0時代,好友功能是最常 被用到的,每個使用者會有很多的好友,同時也會是很多人的好友,那麼這個資料量將會是使用者數的平方的級別。同樣,對於文章標籤,每個文章可以有多個標籤,而 每個標籤又可以有多個文章,這又是一個幾何乘積,資料量又會是個天文數字。

  傳統的處理方案有兩種,一種是通過SEARCH的方法來實現,一種是通過另建一個索引表,存貯對應的ID以進行存貯。對於第一種方案,因為要涉 及大量的LIKE查詢,效能不敢恭維,第二種的情況下,資料庫的行的數量也是驚人海量級別的,並且要跨表跨區查詢,還要維護資料的唯一性,資料處理過程相 當的複雜性能也就不言而喻了。

  文入正題,下面對資料多對多關係舉出來具體的解決方案,我們這裡以標籤和文章之間的多對多關係為例來講解,大家可以舉一反三的思考群組和使用者之間,相簿和被圈使用者之間等等複雜的多對多關係。

  首先濾清一下流程,我們以傳統方案的第二種為例,在傳統的資料庫設計中我們是如下走的:當一篇博文釋出的時候並插入標籤的時候一般是三步走(也 可以理解為四步,以為還要判斷標籤是否存在的問題),第一步插入文章資料庫並獲取文章的ID,第二步插入標籤資料庫同時查詢標籤是否存在,如果存在就取出 標籤的ID,否則的話插入新標籤並取出ID,第三部,將文章的ID和標籤的ID插入索引表來建立關聯。如果這個時候在索引表上建立了索引的話就是災難性 的,特別是在資料量大的情況下,儘管它可以有效的提高查詢速度,但是釋出的速度可能就會讓人無法忍受了。

  我們處理的方法也是三部曲,對多對多關係進行進一步的處理。

  用標籤的時候,我們用的最多的就是查詢標籤下的文章和顯示文章的標籤,所以我們實現這例就成了。

  第一步,拋棄索引表。

  對文章做冗餘欄位,加一個TAG列,我們可以講TAG的標籤如下寫[TagID,TagName]| [TagID,TagName]| [TagID,TagName] 同樣 對於TAG表,我們做如下冗餘加個Article欄位,如下內容[ArticleID,Title]| [ArticleID, Title]| [ArticleID, Title],在需要增加的時候我們只要APPEND一下就可以了,至於ARTICLE的結構和TAG的結構可以參考我上一篇文章的介紹。其實根據需要還 可以存貯更多。

  有人會問,為什麼要存貯TagName和ArticleTitle呢,其實是為了避免跨表查詢和INNERJOIN查詢來做的,In查詢和跨表查詢會造成全表遍歷,所以我們在執行的時候In查詢是必須要找到一個有效的替代方法的。

  第二部:非同步載入。

  在設計模式下我們常思考的是單件模式,我們採用另類的單件模式來處理,也就是把文章和標籤之間的索引作為專門的程序來做,非同步的實現。

  為了避免文章在釋出的時候以為要檢查TAG表而造成的執行緒擁堵,我們需要採取延遲載入的方案來做。伺服器應該維護一個程序專業的對標籤和文章地段的查詢和索引,我們在釋出文章的時候應該把標籤同步這一塊託管給另外的一個程式進行處理,並進行索引。

  第三部:標籤快取索引:

  對於頻繁的判斷標籤去或者熱門的標籤我們還可以組織一套有效的索引,比如對於標籤“瘋狂程式碼”和”傲博知識庫”,我們用樹來把它表示出來。對於 瘋狂程式碼我們索引一個瘋,其實用程式表達就是瘋狂程式碼[0],同樣傲博知識庫就是傲博知識庫[0]。而在陣列”瘋”中存貯以瘋開頭的標籤組,以”傲”的數 組中存貯以”傲”開頭的標籤。如果量更大的話還可以再做二級索引。

  這涉及另外一個話題了就是分詞,上面是一個簡單的分詞方案,大家在進行GOOGLE搜尋的時候應該很輸入它的Suggest方法吧,就是這個道理。最終講標籤有效的索引,並提取熱門的作為一個全域性靜態變數,我們就可以繞過資料查詢這一關,對第二部的單件模式又是一個進化。

  以上是對多對多關係的一個簡單的架構說明,肯定有人會問,如果這樣做的話工作量不是太大了嗎,分詞處理什麼的,對每個多對多關係進行處理。

  OK,咱們可以進一步的把它來抽象化,我們用TableA 表示Article表,用TagbleT表示Tag表,我們可以講欄位抽象化出來,也就是一個ID,一個Tag的String 同理對於標籤表也是如此。朋友們應該可以理解我的意思了。

  對,就是做個程式碼生成器把對應的多對多關係給生成出來,這個很好寫的,幾個Append就可以搞定。如果想更方便的處理,那麼把這個東西做成單件的模式抽象化出來,然後再違反一下原則,做成基類,其他關係繼承這個基類。。。。。剩下的應該很簡單了,具體實現大家思考吧。

  請參照第二篇的文章進行進一步優化設計來實現更高的負載效能

  下章接著講述資料分割和雜湊方面的內容

 

 

(未完待續)

 

 

 

 

 

 

 

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述