我們開發的頁游General War(http://gw.gamebox.com)上線運營也有半年多了,服務器的開發到運維基本都由我一手包辦,在服務器上線之后我們又招了一個程序員接手后續功能的開發,而我則主要轉到后台工具開發和服務器運維上。說到服務器的運維,我的全部經驗就是維護過幾台小型企業的域控,在linux上部署過幾個web服務,以前做游戲的時候運維都是交給運營方去打點,而這次我是主動承擔了這部分的工作。
由於我們的游戲服務器框架(EasyGame)是基於.net技術開發的,所以選擇windows服務器來部署是比較自然的事情,雖然借助mono也可以在linux上部署,但畢竟不如windows的成熟。而一說到windows服務器,很多人會跟我說windows如何低效運維如何麻煩如何的不專業,我個人認為這只是觀念問題罷了。由於linux的學習曲線比windows的高,過濾掉了一大批小白用戶,所以給人感覺linux的運維更加高效更加專業。但實際上,不管是linux還是windows重要的還是看你如何去用。我個人是不太喜歡命令行方式的,因為使用命令行會帶來記憶的負擔,要記住那么多命令和參數實在是一件麻煩事,命令行的輸出信息缺乏有效的組織和排版,閱讀起來也是低效的。但是windows的圖形管理界面也是讓我想吐槽的地方,大部分系統設置的界面都沒有經過良好的組織和設計從而變得極其難用而且低效(比如注冊表,組策略,服務管理等等),windows的配置修改就像魔法一般的存在,經常讓人摸不着頭腦。因此我自己開發了一套自動化運維部署工具來幫助我管理服務器。
我的部署工具的設計目標是這樣的:
- 支持分布式的服務部署和管理,能夠動態的管理多台宿主服務器
- 不用登陸服務器來進行管理,所有對服務器的操作可以在GUI控制台程序上完成
- 用GUI來降低使用難度,用友好的圖表來組織服務器log數據和監控數據,便於閱讀
- 盡可能的降低配置的復雜度
- 使用腳本來靈活的擴展工具以適應不同的需求
我們的服務器程序本身是分布式的,需要能夠部署在多台服務器上,因此部署工具本身也是分布式的,我們有一個主控服務(ServiceManager)用於管理所有的宿主機以及宿主機上運行的服務,每台宿主機上有一個宿主機守護進程(ServiceHost)來對宿主機進行管理並向ServiceManager注冊,從而組成一個服務器集群,然后用戶通過一個GUI控制程序連接到ServiceManager上就可以管理和操作了。對於服務的配置,我采用的原則是約定優於配置,能不配置的東西盡可能做到免配置,對經常修改的配置和不太需要改動的配置分開處理,分成靜態配置和動態配置。比如后端服務經常需要配置服務端口來暴露他的服務,端口的配置是相當麻煩的,搞不好就會出現端口占用沖突,所以這一塊我們就使用動態端口來進行免配置,服務在ServiceManager上注冊自己所開的端口,別的服務就可以得到服務端口。分布式服務會有多種服務類型,服務之間的互連,動態擴容等如果都通過配置文件來做也會非常麻煩,因為這一塊我們使用服務名字約定來實現免配置,每一種服務使用一套名字約定來命名,比如前端代理服務器(AgentServer)就使用Agent.id來命名,當一個AgentServer在ServiceManager上注冊之后就會廣播給后端服務,后端服務在得到這個消息后決定是否要連接Agent來提供對外服務,一個后端服務在啟動之后也可以查看當前集群中有哪些服務,然后決定是否要去建立連接。這樣整個集群上的服務之間的連接就做到了免配置、啟動順序無關並且可以動態擴容。
對於GUI控制程序來說,GUI是對用戶友好的,但缺點是開發成本較高而且不容易擴展,而命令行是天然的程序接口,對於程序本身十分友好,因此我的目標是要結合2者的優點,實現一個即容易使用又容易擴展的GUI程序。我的設計是這樣的:首先,每個服務程序使用標准輸入來接收運行命令,實現服務的啟動、設置、管理和關閉,使用標准輸出來輸出格式化的log數據,這樣的好處就是我的服務本身不依賴於服務容器,可以在命令行里可以當作一個普通的程序來運行和調試,整個設計是非侵入式的而且十分的KISS。然后,由ServiceHost作為服務容器來運行服務,ServiceHost接管服務的輸入輸出流,這樣控制台程序就可以向服務發送命令了。每個服務所支持的命令及參數都是由服務自己決定的,在控制台程序上我們可以通過一個配置文件來告訴控制台程序這個服務支持哪些命令和參數,然后控制台程序會根據配置自動生成出對應的圖形命令按鈕和參數輸入面板。通過配置就可以生成不同服務的管理控制界面,使得GUI有了很好的靈活性。最后,使用按鈕雖然降低了使用難度,但是不利於批量操作,如果我一次有很多服務需要管理,那么通過點擊按鈕就是低效的,所以我集成了JavaScript來支持自動化腳本,這樣就可以實現自動化的批量操作。
對於服務的更新,我集成了svn來實現資源文件的上傳和分發,對小規模的集群來說,svn分發速度不是問題。如果是大規模集群的話,用svn作為資源分發源就有點捉襟見肘了,可以考慮集成p2p服務來實現資源的分發。服務本身支持多版本管理,在服務發布的時候可以選擇不同的服務版本,來實現AB測試和灰度發布。
最后,整套部署工具的開發只用了不到8000行代碼,2周的時間開發完成。目前我們架設了5台物理服務器來運行近40組游戲服,2台linux服務器裝mysql做存儲,2台做游戲應用服務器,1台做web資源下載和后台游戲管理工具。有了這套部署工具后,停服更新重啟40組服務,最快只需要不到10分鍾,運行也十分穩定,沒有出現過crash事故。游戲從上線到現在,我們基本保持每周發布一個新版本的頻率,這樣高頻率的版本更新導致游戲邏輯上難免存在很多bug,好在有部署工具的幫助使得查詢log非常方便,對我們快速的定位和分析bug起到了很大的幫助。
總體而言,windows服務器的運維管理其實也不難做,懶惰的程序員會讓運維變成一項適合懶人的工作。