許式偉:作為系統架構師,您一般會從哪些方面來保證網站的高可用性(降低故障時間)?
張宴:很多因素都會導致網站發生故障,從而影響網站的高可用性,比如服務器硬件故障、軟件系統故障、IDC機房故障、程序上線前測試未發現的Bug、遭受分布式攻擊、突發訪問人數劇增等。
一套良好的網站系統架構,應該盡可能地避免只有一台服務器、一個數據庫、一套軟件節點等單點故障的存在。單點故障一旦發生,將直接導致網站服務不可用,恢復正常服務所需的時間也比較長,甚至還可能無法恢復。負載均衡集群、雙節點熱備、分布式處理等都可以用來解決單點故障,比如提供相同業務的Web服務器、MySQL數據庫從庫,都可以構建負載均衡集群。一旦集群中的一台服務器、一個服務出現故障,自動實時摘除,對用戶來說是不可感知的,不會影響到整個網站的訪問,可以為運維工程師留下足夠的時間去排查和解決故障。
對於重要的MySQL數據庫主庫,我們習慣於從硬件層和軟件層來實現熱備,避免單點。越是復雜的設備,發生故障的概率越大。在磁盤沒有損壞的情況下,應用程序導致服務器宕機的概率,遠高於簡單的磁盤陣列宕機的概率。所以,從硬件層解決的話,可以在兩台服務器上安裝相同的數據庫版本、進行相同的配置,用SAS或SCSI線連接一台磁盤陣列,將數據庫數據文件存放到盤陣上。正常情況下用服務器A掛載盤陣分區,啟動MySQL,綁定虛擬IP;如果服務器A宕機,則用服務器B掛載盤陣分區,啟動MySQL,接管虛擬IP。從軟件層解決的話,則可以借助DRBD等軟件做鏡像。(主從同步,負載均衡、高可用、緩存)
IDC機房發生故障的概率較小,但如果發生的話,影響面也是最大的。如果所有服務器都托管在一個IDC機房,一旦該機房遭遇長時間流量攻擊、斷電、斷網、地方政策性封網等,通常只能聯系IDC去處理,除此之外束手無策,解決時間也比較長。如果成本允許,將網站服務器分布在兩個以上的IDC機房,當某個IDC發生故障時,可以臨時切換DNS域名解析來優先恢復服務。
雖然程序代碼上線前,經過了測試人員的嚴格測試,但測試環境和生產環境畢竟有差異,所以一些會急劇影響性能、正常服務的Bug往往在程序上線之后,才會被發現,這就要求我們在發現Bug后,能夠迅速回滾到上一正常版本。我們在SVN的基礎上,開發了Web代碼發布系統,會將每個發布版本之間的文件變更記錄下來,一鍵實現程序代碼在多台Web服務器上的發布和回滾。
遭遇DDOS分布式拒絕服務攻擊,使用防火牆來對付半連接、假IP,還算比較容易。而那種專挑復雜動態應用程序URL進行的分布式CC攻擊,來源為真實IP、真實HTTP請求,具有模擬正規瀏覽器User-Agent、單個IP的每秒請求數不高、有成千上萬個攻擊源等特征,很難與正常訪問區分開,比較難對付。但是,正常通過瀏覽器訪問一個URL,會加載該URL中引入的JavaScript腳本、CSS樣式、圖片等文件。遇到CC攻擊,需要及時分析日志,找出訪問量異常上漲的URL,然后用事先寫好的shell腳本找出哪些IP的請求只訪問了該URL,而不加載該URL引入的文件,對這些IP進行自動封鎖。
系統架構設計時,需要事先考慮到高於目前訪問量多少倍的突發訪問。對於網游站點來說,訪問量受廣告集中時間段投放、線上活動的影響較大,帶寬峰值時間不固定,對於靜態內容,可以使用商業CDN,按實際使用量計費。對於動態內容,如果遇到突發訪問人數劇增,超過現有服務器處理能力,最簡單的臨時處理辦法就是增加服務器。上架新服務器需要時間,但是,同一個IDC機房內,可以借助其他業務的服務器,在不同端口開啟一組新進程,加入到原有負載均衡池中。另外,可以臨時關閉一些Web中的次要功能,來減少服務器消耗。
許式偉:您在任務切分上,有什么經驗分享?您通過哪些手段保證任務的獨立性?
張宴:相信很多人都遇到過這種情況:在一個老項目上修改、增加一些新功能所花費的時間,不比重新來做一個包含所有功能的新項目時間用得少。一個需要長期維護的項目,不可避免地會面臨老員工的離職、新員工的接手,很多時候,項目代碼的可維護性將決定一個項目的生存周期。讓一個新員工在規定開發時間的壓力下,去面對一個文檔不夠詳細、陌生的、功能復雜的龐大項目,短時間弄明白所有功能邏輯不是一件容易的事。所以,任務需要切分,將一個大的任務切分成一個個小模塊之后,各模塊之間可以做到代碼獨立,互不影響,可維護性也大大增強。
關於任務切分,我以本人今年負責的兩個重要項目架構設計為例來介紹一下。在第一個項目:金山游戲官網的《用戶行為分析系統》中,由於數據挖掘計算需要消耗較高的內存、CPU資源,一台服務器的處理能力不夠,而商業的分布式數據倉庫價格又太貴,所以,只有從程序應用中下手,進行任務切分。我們先按需要挖掘的數據指標,將整個數據挖掘任務切分成多個數據挖掘插件,每個插件可以在不同的服務器上運行,多個插件可以同時在多台服務器上。多個數據挖掘插件之間,如果用到相同的某項數據,那么,就將該項數據以冗余方式,復制幾份提供給需要的插件,從而實現插件之間無交互、無關聯,保證了超大數據量下插件的運算速度。
在第二個項目:金山游戲新版運營管理系統中,則將整個任務切分成了PHP Web管理界面、PHP Web API功能接口、C/C++中間件引擎三部分。這是一種分層結構切分,最上層的“PHP Web管理界面”調用“PHP Web API功能接口”,“PHP Web API功能接口”調用運行在游戲服務器端的“C/C++中間件引擎”,“C/C++中間件引擎”與“游戲服務器端進程”通過TCP、UDP二進制協議、信號、命令行等多種方式通信。四者之間相對獨立,代碼無關聯,通過一層層API接口實現交互。“PHP Web管理界面”負責通用界面實現。“PHP Web API功能接口”內部,又按接入的游戲模塊、子功能模塊進行了更細的切分,各功能模塊之間通過內部API交互。“C/C++中間件引擎”大而全,不處理具體指令,但兼容TCP、UDP、HTTP、HTTPS/SSL、信號、命令行等大多數通信方式,負責和各種類型的游戲服務端交互。這是一套完全由API接口驅動的系統架構,一款新游戲接入運營管理系統時,只需在“PHP Web API功能接口”中增加一個模塊;一個游戲新管理功能的增加,只需要在“PHP Web API功能接口”中增加一個子模塊。通過任務切分,將復雜功能簡單化,也將原來接入一款新游戲所需要的幾個月時間,縮短為1~2周。
許式偉:您通過哪些手段,來保障產品的質量?您傾向於多久更新一次您的網站?
張宴:Web產品質量主要體現在架構、功能、性能、安全、代碼唯一性、兼容性等方面。
架構方面,我會先設計一套架構方案,然后讓和項目相關的人員、專家組成員參與進來,一起探討和論證架構的利弊,提出改進意見,保證架構的可行性。所有重要項目的技術方案需要經過專家組的評估。
功能、性能方面,則會由專門的測試人員進行功能測試、壓力測試、安全掃描,測試環境分為線下測試環境、線上准測試環境。
在代碼唯一性方面,我們開發了一個Web配置信息管理平台及相關PHP擴展,提供給系統工程師,用於配置信息的統一管理。在新項目中,PHP程序配置文件中將不再出現MySQL、Memcached等各類IP和端口信息,統一用Web配置信息管理平台給出的變量代替。從“開發環境→線下測試環境→線上測試環境→線上正式環境”,連接的數據庫各不相同,導致PHP開發工程師經常搞混淆或忘了修改,通過Web配置信息管理平台,使得PHP代碼中的配置文件,在四個環境中無須作任何修改,保證了代碼的一致性,降低了出錯率,從而確保了產品質量。
在兼容性方面,我們從操作系統到PHP、MySQL版本,都保持開發環境、測試環境、線上環境的統一,所有的Web服務運行在CentOS Linux系統上。由於大多數PHP程序員習慣於在Windows上編寫代碼,而我們的程序中調用的一些接口、PHP擴展,只能在Linux下運行。為此,我們開發了一個小工具,可以將多名程序員在各自本機Windows上搭建的nginx虛擬主機、編寫的程序文件,映射到一台Linux服務器,用Linux上的php-cgi執行Windows上的PHP代碼。這樣,PHP程序員修改完本機代碼,保存一下,即可調試,多人之間互不影響。自己調試通過后,可以在Windows直接點擊鼠標右鍵,將修改的代碼提交到SVN版本庫。
Web 2.0時代,講究網站更新的實時性,動態網站不用說,靜態網站的內容發布也要保證實時。我們開發了一款名為Sersync的開源軟件(http://code.google.com/p/sersync/),使用Linux 2.6內核的inotify監控Linux文件系統事件,被監聽目錄下如果有文件發生修改,Sersync將通過內核自動捕獲到事件,並將該文件利用rsync同步到CDN源站服務器。Sersync僅僅同步發生增、刪、改事件的單個文件或目錄,不像rsync鏡像同步那樣需要比對雙方服務器整個目錄下數千萬的文件,並且支持多線程同步,因此效率非常高。金山游戲官網的CMS內容發布系統,無論網站編輯通過Web還是FTP上傳圖片、視頻、附件,還是系統工程師直接去CMS發布服務器上增加、修改、刪除文件,干完這些事情后不用做任何處理,Sersync 會自動將發生增、刪、改事件的文件同步到CDN源站服務器,並可以在文件同步完成后,自動調用CDN緩存刷新接口,主動刷新發生修改、刪除的文件的訪問URL。
許式偉:您在面試時,通常關注應聘者的哪些方面?哪些問題經常會問呢?
張宴:第一,需要具備崗位要求的基礎技能知識,這方面我不再詳述。
第二,注重項目經驗與積累,不看重學歷與工作年限。做一個項目,猶如打一場戰役,身經百戰,積累下來的成功經驗可以讓工作更得心應手,失敗經驗可以避免走很多彎路。
第三,能夠在1~2個以上技術領域精通。所謂術業有專攻,能夠在某幾項技術領域做到精通的人,相信對於新的技術領域或者從未有過相關經驗的新項目,也能夠輕松勝任,做到盡善盡美。
第四,關注應聘者的知識廣度。如今的項目,已經告別個人英雄時代,講究團隊的協作。知識面越廣,盡管在非專攻領域的深度可能不夠,但是,知己知彼,可以站在一個更高的角度上看問題,這對於團隊協作開發、項目融合的益處是顯而易見的。
第五,具備良好的領悟能力、思考能力、設計能力、創新能力。基礎技能知識不夠可以學習,經驗不足可以積累,技術不精通可以鑽研,知識面不廣可以開拓,但要培養這四項能力,是一件非常困難的事。要打造一支優秀的團隊,這四項能力不可缺少,它們的重要度甚至超過以上的四方面要求。
我不會經常去問固定的問題,但所問的問題,幾乎都跟以上的這些方面相關。
許式偉:您曾嘗試開放自己的程序代碼嗎?您對中國國內開源社區的現狀有何看法?
張宴:是否開源自己的程序代碼,跟所在公司或部門的性質有着密切的關系。如果是在研發驅動型企業或部門,程序代碼是公司生存的命脈,需要與競爭對手拼技術和保持技術領先的優勢,因此,很難支持開源事業。反之,如果是在運營驅動型企業或部門,技術是用來提高運營質量、運營水平的工具之一。將純粹的技術代碼或產品,從公司的業務產品中提取出來,進行開
源,可以按照開源產品的要求,提高公司內部技術產品的規范化、標准化,還可以引用更廣大用戶的使用、反饋和意見,解決未發現的潛在Bug,改進代碼質量,提升技術水平。對於提高運營質量、運營水平來說,益處多多。我也嘗試開源自己的一些代碼,例如簡單消息隊列服務HTTPSQS(http://code.google.com/p/httpsqs/)、MySQL HTTP/REST客戶端MySQL-UDF-HTTP(http://code.google.com/p/mysql-udf-http/),同時,也鼓勵團隊成員嘗試開源,例如剛才提到的自動同步軟件Sersync。
國內的開源社區在不斷壯大,很多知名互聯網公司都開源了自己的一些產品,但大多數還只停留在開源產品的使用、技術交流、漢化層面,真正參與到開源產品編碼中的人還是較少,很多開源產品最終還是由原作者或原公司團隊維護。國內開源社區的道路仍然漫長。