開發大型高負載類網站應用的幾個要點

看了一些人的所謂大型項目的方法,我感覺都是沒有說到點子上,有點難受。
我也說說自己的看法.我個人認爲,很難衡量所謂項目是否大型,
即便很簡單的應用在高負載和高增長情況下都是一個挑戰.因此,按照我的想法,姑且說是高負載
高併發或者高增長情況下,需要考慮的問題.這些問題,很多是和程序開發無關,而是和整個系統的
架構密切相關的.

  • 數據庫
     
沒錯,首先是數據庫,這是大多數應用所面臨的首個SPOF。尤其是Web2.0的應用,數據庫的響應是首先要解決的。
一般來說MySQL是最常用的,可能最初是一個mysql主機,當數據增加到100萬以上,
那麼,MySQL的效能急劇下降。常用的優化措施是M-S(主-從)方式進行同步複製,將查詢和操作和分別在不同的
服務器上進行操作。我推薦的是M-M-Slaves方式,2個主Mysql,多個Slaves,需要注意的是,雖然有2個Master,
但是同時只有1個是Active,我們可以在一定時候切換。之所以用2個M,是保證M不會又成爲系統的SPOF。
Slaves可以進一步負載均衡,可以結合LVS,從而將select操作適當的平衡到不同的slaves上。

以上架構可以抗衡到一定量的負載,但是隨着用戶進一步增加,你的用戶表數據超過1千萬,這時那個M變成了
SPOF。你不能任意擴充Slaves,否則複製同步的開銷將直線上升,怎麼辦?我的方法是表分區,
從業務層面上進行分區。最簡單的,以用戶數據爲例。根據一定的切分方式,比如id,切分到不同的數據庫集羣去。
全局數據庫用於meta數據的查詢。缺點是每次查詢,會增加一次,比如你要查一個用戶nightsailer,你首先要到
全局數據庫羣找到nightsailer對應的cluster id,然後再到指定的cluster找到nightsailer的實際數據。
每個cluster可以用m-m方式,或者m-m-slaves方式。
這是一個可以擴展的結構,隨着負載的增加,你可以簡單的增加新的mysql cluster進去。

需要注意的是:
1、禁用全部auto_increment的字段
2、id需要採用通用的算法集中分配
3、要具有比較好的方法來監控mysql主機的負載和服務的運行狀態。如果你有30臺以上的mysql數據庫在跑就明白我的意思了。
4、不要使用持久性鏈接(不要用pconnect),相反,使用sqlrelay這種第三方的數據庫鏈接池,或者乾脆自己做,因爲php4中mysql的
鏈接池經常出問題。
  • 緩存
     
緩存是另一個大問題,我一般用memcached來做緩存集羣,一般來說部署10臺左右就差不多(10g內存池)。需要注意一點,千萬不能用使用
swap,最好關閉linux的swap。
  • 負載均衡/加速
     
可能上面說緩存的時候,有人第一想的是頁面靜態化,所謂的靜態html,我認爲這是常識,不屬於要點了。頁面的靜態化隨之帶來的是靜態服務的
負載均衡和加速。我認爲Lighttped+Squid是最好的方式了。
LVS <------->lighttped====>squid(s) ====lighttpd

上面是我經常用的。注意,我沒有用apache,除非特定的需求,否則我不部署apache,因爲我一般用php-fastcgi配合lighttpd,
性能比apache+mod_php要強很多。

squid的使用可以解決文件的同步等等問題,但是需要注意,你要很好的監控緩存的命中率,儘可能的提高的90%以上。
squid和lighttped也有很多的話題要討論,這裏不贅述。
  • 存儲
     
存儲也是一個大問題,一種是小文件的存儲,比如圖片這類。另一種是大文件的存儲,比如搜索引擎的索引,一般單文件都超過2g以上。
小文件的存儲最簡單的方法是結合lighttpd來進行分佈。或者乾脆使用Redhat的GFS,優點是應用透明,缺點是費用較高。我是指
你購買盤陣的問題。我的項目中,存儲量是2-10Tb,我採用了分佈式存儲。這裏要解決文件的複製和冗餘。
這樣每個文件有不同的冗餘,這方面可以參考google的gfs的論文。
大文件的存儲,可以參考nutch的方案,現在已經獨立爲hadoop子項目。(你可以google it)

其他:
此外,passport等也是考慮的,不過都屬於比較簡單的了。

吃飯了,不寫了,拋磚引玉而已。

 

【回覆】

9tmd :
說了關鍵的幾個部分,還有一些比如squid羣、LVS或者VIP(四層交換)之類的必須考慮,數據庫邏輯分表不需要master裏面查id,可以定期緩存或者程序邏輯上進行控制。
跟大家分享一下我的經驗: http://www.toplee.com/blog/archives/337.html (歡迎討論)
nightsailer
樓上說的很好.
我 再說一下關於爲何要在主表查詢,最主要的因素是考慮到複製和維護的問題。假設按照程序邏輯,用戶nightsailer應該在s1集羣,但是由於種種原 因,我須要將nightsailer的數據從s1集羣轉移到s5集羣或者某些時候,我需要將某幾個集羣的數據合併,此時,我維護的時候只需要更新一下主數 據庫中nightsailer的cluster id從1變成5,,維護的工作可以獨立進行,無需考慮更新應用程序的邏輯。也許程序的id分配邏輯可以考慮到這種情況,但是這樣一來,你的這個邏輯會發散 到各個應用中,產生的代碼的耦合是很高的。相反,採用查表這種方式,只需要在最初的時候進行初始分配,那麼其他的應用是無需考慮這些算法和邏輯的。
當然,我最初提到的增加這次查詢並不是說每次查詢都需要找主數據庫,緩存策略是必定要考慮的。

至於說爲什麼要禁用auto_increment,我想也清楚了,數據的合併和分隔,肯定是不能用auto_increment的。
在閒扯一下,PHP的優化可以有很多,主要的措施:
1、使用FCGI方式,配合lighttpd,Zeus.
我個人比較喜歡Zeus,簡單可靠。不過,需要¥¥¥。
lighty也不錯,配置文件也很簡單,比較清爽。最新的1.5,雖然不穩定,但是配合linux的aio,性能的提升
非常明顯。即便現在的穩定版,使用2.6的epoll可以得到的性能是非常高。當然,lighty比zeus缺點是對於smp
的支持很有限,所以可以採用多服務器負載,或者乾脆起不同的進程服務監聽不同的端口。
2、專門的PHP FCGI服務器。
好處多多,在這個服務器上,就跑php的fcgi服務,你可以把一些緩存加上,比如xcache,我個人喜歡這個。
還有別的,套用大腕的話,把能裝的都裝上,呵呵。
另外,最主要的是,你可以只維護一個php的環境,這個環境能夠被apache,zeus,lighttpd同時share,
前提是這些都使用php的fcgi模式,而且,xcache可以充分發揮!
3、apache+mod_fastcgi
apache並非無用,有時候也需要。比如我用php做了一個web_dav的服務器,在其他有問題,只能跑apache.
那麼,apache安裝一下mod_fastcgi,通過使用externl server,使用2配置的php fastcgi。
4、優化編譯
ICC是我的首選,就是intel的編譯器啦,用icc重新編譯php,mysql,lighty,能編的都編,會有不小的收穫的。尤其是你用
intel的cpu的話。
5、php4的64位需要patch
好像沒有人在linux x86_64上編譯過php4吧,我曾經googleit
,別說國內了,連老外都很少用。
這裏就做個提醒把,如果用php官方下載的(包括最新的php-4.4.4),統統無法編譯通過。問題是出在autoconf上,需要
手工修改config.m4,一般是在mysql,gd,ldap等一些關鍵的extension上,還有phpize的腳本。把/usr/lib64加入到
config.m4中相關搜索的path中。
不過我估計很少人像我這樣死用php4不防,呵呵。php5就沒有問題。
我也考慮正在遷移到php5.2,寫代碼太方便了,一直忍着呢。
QUOTE:
原帖由 wuexp 於 2007-1-3 17:01 發表
分表會使操作數據(更改,刪除,查詢)邊的很複雜,特別是遇到排序的時候就更麻煩了.
曾經考慮根據用戶id哈希一下,插入到相應的分表裏

明白你的意思。

不過我們可能討論的不完全一樣,呵呵。
我所說的分表要依據不同的業務情況來劃分的,

1、可以是垂直劃分,
比如依據業務實體切分,比如用戶a的blog貼子,用戶的tag,用戶的評論都在a數據庫u,甚者是完整的一套數據結構(這種情況下應該說是分數據庫)

2、也可以水平劃分,
一個表的數據分在不同的數據庫上。
比如message表,你可能分爲daily_message,history_message,
dialy_meesage可能是hot對象,week_message是warm,2個月以前的帖子
可能屬於cold對象了。這些對象依據訪問頻度不同會劃分到不同的數據庫羣上。

3、二者結合

不過,不論如何,更改、刪除並不複雜,和未分區的表沒有區別。

至於查詢和排序,不可能僅僅是通過select,order吧?
而是應該產生類似摘要表,索引表,參考表。。。
另外,要根據業務具體分析減少垃圾數據,有些時候,只需要最初的1萬條記錄,那麼所有表
數據的排序就不需要了。很多傳統的業務,比如零售,流水錶很大,但是報表的數據
並非實時生成的,扎報表應該不陌生。

也可以參考很多網站的做法,比如technorati啊,flickr之類的。


所謂的麻煩是你設計系統的結構的時候要考慮到,在設計數據庫的時候更要注意,
因此只要項目的framework最初設計比較完備,那麼可以說大部分對開發人員是透明的。
前提是,你一定要設計好,而不是讓程序員邊寫代碼邊設計,那會是噩夢。


我寫這麼多廢話,並非僅僅是對程序員來說,也許對設計者更有用。
 
9tmd 
程序邏輯上控制表拆分只需要維護一個數據庫訪問的配置文件即可,對於開發來說,完全透明,可以不用關心訪問的是哪裏,而只需要調用通用的接口即可,曾經做過的系統裏面,這樣的應用經常遇到,尤其在全網passport、社區帖子等方面的處理上應用最多。

原來在yahoo工作和後來mop工作都使用了這樣的架構,整體感覺來說還是值得信賴的,單表畢竟存在面對極限數據量的風險。

 

9tmd 
前 面老是有人問auto_increment的問題,其實這是MySQL官方專門針對M/S的Replication做過的說明,因爲MySQL的同步是依 靠同步MySQL的SQL日誌來實現的,事實上單向的Master->Slave使用auto_increment是沒有問題的,而雙向的M/M模 式就會存在問題了,稍微一思考就知道怎麼回事了。官方文檔: 
http://dev.mysql.com/tech-resour ... ql-replication.html
http://dev.mysql.com/doc/refman/ ... auto-increment.html

另 外,在使用MySQL的同步時,需要注意在自己的代碼裏面,寫SQL的時候不要使用MySQL自己提供的類似 NOW()之類的函數,而應該使用php程序裏面計算的時間帶入SQL語句裏面,否則同步的時候也可能導致值不相等,這個道理可以牽涉出另外一些類似的問 題,大家可以考慮一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章