服務器運維的幾重境界


 

標題所說的運維是一個比較寬泛的概念,基本上與游戲本身無關的、程序員(主要針對服務器)又要去做的事情都涵蓋在內,包括版本管理、發布部署、集群管理、服務器容災、服務器擴容、數據備份恢復、監控警報等等。游戲開發這幾年,經歷過兩家公司,算上現在這個總共有5個項目,其實遠不算見多識廣,很多實踐方法是聽同事講的或者招聘的時候打聽來的。我大體整理了一下游戲運維發展脈絡,順便展望一下今后的趨勢。

“雖然我很笨,但是我很勤奮。”

就像愚公移山,最原始的運維靠的是蠻力。愚公的愚主要就體現在做事情太直接,缺乏進一步的思考。
要打版本?新建個目錄把代碼check出來,make一下就編譯好了,再改一下版本號就大功告成。
怎么部署呢?scp拷貝到生產環境,再運行腳本解壓縮重啟一下。
要加新服務器?在新機器上安裝好游戲運行要用的軟件和庫,用vi修改全局配置文件把新機器加上去,再用scp拷貝到每台服務器,最后全重啟一遍。
服務器掛了怎么辦?有備用的空閑機器就可以直接用了,如果沒有還得花時間裝軟件。當然改全局配置再整體重啟是免不了的了。

問題是很顯然的吧。運維人員主要在做重復性的工作,服務器需要24小時值守。時間久了一定會疲憊的,而且各種手動修改操作很容易誤操作帶來不可挽回的損失。

“機器能做的事情交給機器去做,但是關鍵的操作還是得靠人啊!”

到這個階段開始考慮編寫腳本或者引入工具了,目的是為了減少重復性的工作。
打版本使用寫好的自動化腳本,要打版本的時候一行命令版本包就出來了。版本號可能在代碼庫的某個文件里,打版本之前需要手動改一下提交,做的好點的會在腳本里做自去遞增。更進一步會用上可持續集成工具(如jenkins),這樣在網頁上點一下就能出版本,打版本的事情就可以完全交給非技術人員了。
更新部署這類線上操作還是要交給運維人員來手動做,但是會編寫大量的腳本將操作簡化。特別是對於服務器集群的批量操作,通常會在集群中選一台主機作為中控機/跳板機,直接在中控機中使用expect + ssh腳本批量操作遠程主機。需要更新的版本和公用配置也可以從中控機上批量分發出去,可以用腳本,也可以用rsync進行同步。
引入監控系統監控服務器的運行狀態,有異常情況時通過短信電話通知。

通過使用自動化腳本,運維人員大量的日常事務得到了簡化。雖然還是要24小時待命,可能時不時得半夜起床處理線上問題,但至少不用輪流加夜班,可以每天回家睡覺了。

“我們已經不是兩三歲的小孩了。”

運行在服務器上的程序就像沒長大的小孩子,一有風吹草動就又哭又鬧。運維就像是同時照顧幾十個小孩的保姆,一刻不得閑。實際上我們完全可以通過良好的軟件設計來提高程序的可用性。可以使用守護進程保證進程宕了之后能自動重新啟動,最好能注冊為服務在系統重啟后也能恢復服務,如果能做到恢復之前的會話狀態就更好了。相互之間有交互的進程不要設計成強制要求特定啟動順序,也就是說要有進程之間設計自動重連的機制。數據庫要能在故障時自動進行主從庫切換。

對運維友好的程序有了一定的自我修復能力,這樣一來大部分問題就不再是需要立即着手解決的了,我們終於可以睡個安穩覺了!

注:后面介紹的3個工具基本上是我這幾天陸續看來的,這里只是做一下介紹和展望,具體實踐有待后面繼續探索。

“Linux上裝應用也能像蘋果AppStore一樣便捷嗎?”

答案是完全可以,我們要用的 工具是Docker。簡單的說,Docker可以用來把一個程序和這個程序運行所需要的整套環境打包成一個鏡像,這個鏡像可以被分發到任意一個Linux系統中運行,唯一的要求是這個系統中安裝了Docker。
Docker官方提供了一個鏡像發布中心DockerHub,用戶可以自由發布制作好的鏡像供他人使用,也有各種軟件維護者發布的官方鏡像。DockerHub聽起來像是Docker平台上的GitHub,實際上意義遠不止於此,我認為其地位應該相當於Linux界的AppStore。
試想我現在想在某台服務器上運行nginx,我只需要從DockerHub下載nginx鏡像,再docker run啟動一個容器來運行這個鏡像,我不需要規划把nginx安裝到系統的哪個目錄,也不關心這個nginx的版本到底依賴於哪個版本的libc。同樣如果我想要一個apache服務器,那么我就下載一個apache鏡像下來運行,完全不用先准備一套jdk環境。不同應用之間是完全獨立的,即使需要不同的jdk版本也不會產生沖突。
游戲版本的發布過程也將發生深刻變化。我們不再需要在每台服務器上安裝游戲運行的依賴庫,轉而制作一個包含了所有依賴的基礎鏡像。需要發布版本時把編好的程序和配置添加到基礎鏡像中就得到了一個游戲版本鏡像,這個鏡像拷貝到任意裝了Docker的Linux系統上都能一致地運行。
最后我們的服務器集群每台主機上需要安裝的唯一軟件就是Docker,服務器的配置工作大幅簡化。

“像生態系統一樣會自我修復。”

前面所說程序的自我修復能力,其實只能部分解決軟件方面的缺陷,對硬件故障是無能為力的。在服務器集群的長期運行中,出現硬件故障的概率是100%。主機不再可用時唯一的辦法是換用備機,可問題是服務器列表往往是做一份配置文件分發到每台服務器的,換用備機必須把新的配置重新分發,如果有必要還得一一重啟……
這里要用到的是分布式數據管理工具etcd(類似的還有zookeeper、doozer等)。應用etcd我們可以把服務器共用配置存儲在分布式環境,注意不是存在某台主機上,而是由多台主機共同維護並保證其一致性,這樣一來任何一台主機故障了都不會影響數據的完整性。同時各個游戲組件可以作為觀察者向etcd注冊自己感興趣的配置,於是我們只要通過etcd修改配置,集群中的所有主機都能得到通知並更新自己保存的服務器列表了。
我們甚至可以做得更智能一點,運行一個監控程序監視各個系統組件的運行狀態,如果發現某節點故障了無法提供服務,那么自動先擇備用節點替換之,並通過etcd更新配置。
如此一來,整個故障恢復過程完全是自動化的,我們的集群就像生態系統一樣有了自我修復的能力。

“聰明的程序員善於抽象,卓越的程序員在抽象之上抽象。”

最后順着上面的思路介紹一個工具:fleet。fleet對分布式程序的運行模式作了進一步抽象,把分布式系統分為Service和Machine兩個獨立的部分。
比如游戲中用一個game進程承載一個區的玩家,那么game就是Service,體現為一個Docker鏡像。如果我們要運行5個區,但是只有4台服務器,那么就選其中一個服務器運行兩個game,等到有多出來的服務器的時候再轉一個game過去運行就好了。如果有一台機器突然壞了呢?好說,從所有服務器中找一台空閑點的再運行一個game,順便把這個game的新ip+port通過etcd廣播一下就行了。只要有一個調度機制,這些都可以自動完成,完全不需要人工干預,我們只需要在系統負載過高的時候扔幾台主機進集群完事。
這樣的世界多么美好!

Q&A

手游的服務器,一般都是購買騰訊雲或者阿里雲的,一般不用我們去維護的吧?

用過騰訊雲的話,想必一定經歷過“母機掛掉”導致主機直接沒法使用的情況吧,我們甚至會直接收到騰訊雲的郵件,告知“某部分主機晚上12:00至06:00需要停機維護,請做好備份工作,必要的話請遷移備機”。
在這種情況下,備機的啟用、環境搭建、加入集群、更新配置,這些都是開發者自己的事情,騰訊雲是不管的。
擴容的情況類似,比如游戲開新服,騰訊雲只提供裝好系統的虛擬主機,具體的配置工作還是得我們自己來。
如果使用開放平台提供的存儲服務,數據庫的備份和恢復或許開發者可以不用操心。這個我也不是很了解,鑒於騰訊雲的不靠譜程度,我們之前的數據庫一直都是自己買主機搭建NoSQL服務的。
至於監控,騰訊雲只能提供基礎平台的監控,比如主機掉線、CPU內存占用過高等。應用層面的監控他們是不管的,比如游戲進程掛了,數據庫存盤壓力過大,登錄排隊堆積,這些都是開發者自己需要解決的問題。
總之雲平台提供的是基礎服務,大部分的集群的管理還是得開發者自己來。

Docket中運行其它軟件,會有性能上的損耗嗎?還有,管理進程的方式是不是改變了?

Docker容器運行在與Host隔離的文件系統和網絡環境中,所以性能損耗一定是會有的。 與傳統VM不同的是,Docker並不是采用的硬件虛擬化,而是利用Linux的LXC實現的操作系統層面的隔離,容器中運行的進程實際上還是運行在Host上的,可以直接在Host上通過ps命令看到。 一些資料給出的答案是“性能逼近於直接運行”,我理解的是與直接運行性能上的差異主要體現在啟動過程(通常需要1秒左右),啟動完成后性能上差別應該是可以忽略不計的。

使用Docker后,原本對進程的管理轉變為對容器的管理。 我們通過docker run啟動容器,通過docker ps查看當前運行中的容器,docker stop或docker kill中止容器。 同時Docker還提供了RESTful的Remote API,讓我們可以更便捷地進行遠程管理。

docker 生產環境運行的穩定不?

呃,這幾天剛在看,項目還在研發中,目前並沒有生產環境可以驗證……

轉載自:

http://disksing.com/game-ops


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM