歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux資訊 >> Linux業界 >> Etsy工程師Sam Haskins談代碼部署,監控與故障處理

Etsy工程師Sam Haskins談代碼部署,監控與故障處理

日期:2017/2/27 17:32:44   编辑:Linux業界
Sam Haskins分享了他在Etsy做DevOps的經驗。Etsy使用Git做代碼管理,平均每天提交的更新數量在30次左右,有時甚至達到70個。在如此高頻率提交代碼的情況下,他們如何進行代碼審查?如何在每次更新之後監控系統性能?如何處理故障?下面,Sam將一一解答。
Sam Haskins目前屬於Etsy的核心平台團隊,該團隊一共有10~15人,整體負責服務器及系統層與應用層的接口,為上層開發特性的工程師們提供服務。Sam於2010年中加入Etsy,他現在主要負責數據庫接入層,也在web框架上做一些東西。核心平台團隊的其他成員還負責開發圖片存儲系統、異步任務管理等功能。Sam畢業於卡內基梅隆大學的數學系。
代碼部署和審計

InfoQ:第一個問題是關於部署系統的。你們使用哪些工具?

Sam:我們使用Git做代碼版本管理,使用Deployinator(我們為自己開發的一個工具)從Git中拿東西出來,並把它放到所有的服務器上。基本上就是文件復制工作,沒有什麼特別的。另外,我們使用Chef做配置管理。就這些了。實際上我們用GitHub。我們有一個內部的GitHub來管理代碼。

關於代碼審計流程,實際上我們沒有很多正式的檢查。只要你的代碼能編譯,能運行,你就可以放到代碼庫上,不需要審計。但是,我們鼓勵大家做代碼復查,而且大家經常這麼做。代碼復查通常是這樣的——你只要把你的補丁發給別人看,他們看過後給你一些點評。大多數人在推送代碼到代碼庫前都會這麼做。

InfoQ:有QA嗎?

Sam: 沒有。我們沒有傳統意義上的QA。因為我們每次的提交都很小,所以發現哪些代碼破壞了系統通常是相當容易的。當然,也有一些人的工作有點兒像QA,他們的工作就是試著破壞我們的系統,然後讓我們知道哪些東西壞了。我們部署做得很多,一天部署50次挺平常的,有時候會更多。在部署前後做全面的測試是不可能的,根本沒有足夠的時間。但是我們有自動化測試,和代碼審查等等,而且我們每次的變更都很小,所以,我們認為我們並不需要有一個大規模的正式的QA過程。

InfoQ:那麼,當你做更新時,你如何做環境控制,保證代碼安全?

Sam:對於我們的工具Deployinator來說,只要你點一下按鈕,它所做的就是從Git中拿出東西,並把它分發下去,僅此而已。

InfoQ:你們部署的是源代碼,而不是打包後的二進制文件?

Sam:是的,我們不打包。它就是把它們放到web服務器的某個目錄下之類的,沒有什麼太復雜的。我們不做太復雜的事兒。

非常簡單,只要幾分鐘就運行完了。 正是因為很容易,所以我們才能部署這麼多次。

InfoQ:那麼一天50次是比較典型的部署頻率嗎?

Sam:差不多。今年的平均值可能是30或33次,算上星期六和星期日。但通常星期六和星期日我們什麼也不做。我想,最多的時候,我們可能在一天裡我們最多部署60或者70次,少的時候也有二、三十次。的確很多,但這也是我們改變了寫代碼的方式,讓它變成合理的事情了。假如我們每次都做很大的變更,這麼做可能就不行啦,一定會變成一種災難。正是因為我們每次只做很小的改更,所以這種方式才能行。

部署的流程與健康監控

InfoQ:由於你們每天部署這麼多次,那麼你們通常在一天中的什麼時間部署?你是部署後,觀察幾分鐘,然後再部署另一次嗎?

Sam:是的,我們有很多度量項,可能成千上萬吧。所以 每次部署後,除了要監控你的變更是否起作用了,我們還有一個標准的部署指示儀表盤,你需要關注。那上面有一堆圖表,你要看著它,並確保儀表盤上的指標沒有異常。

我們還有一個工具,用來讀實時日志,你也要看看那個東西。假如有些東西不正常,那你就需要修復它。但只需要幾分鐘就行,通常是一兩分鐘。但我要看更多一些的圖表數據。 只要沒有什麼問題出現,並且你認為你的修改正常工作了,那就輪到下一組啦。

InfoQ:當部署時,你是先把它部署到測試環境上嗎?

Sam:有一個前提,在你部署之前,你已經自行測試過它了,所以我們是直接部署的。不過,的確也可以說我們已經在測試環境上部署過了,因為我們的試運行環境也是我們的生產環境,是同一個環境,只是版本高一點兒,而且用戶不可能訪問到這些服務器,只有我們才能訪問。

因此,當部署時,首先會放到試運行環境,然後CI(持續集成服務器)會運行測試,是單元測試。順便說一下,我們使用的是Jenkins。同時,你可以訪問試運行環境,Jenkins運行一系列的測試。之後,一旦推送代碼的人認為試運行環境上的功能沒有問題,他們已經測試過他們的變更,並認為這些變更運行正確的話,那麼只是Jenkins運行完(通常總共需要5分鐘),就可以推送到生產環境了。

InfoQ:你在這裡提到的生產環境,是指所有的機器嗎?

Sam:是的,是所有的機器。

這個工具只有兩個按鈕,一個指向試運行環境,另一個就指向生產環境。

InfoQ:那是否根據服務的不同,分成了不同的集群呢?比如一種服務,使用一類集群?

Sam:算是吧。所有的部署都是同樣的軟件棧。 同樣的web軟件棧。但我們的確有搜索專用的軟件棧和圖片存儲專用的軟件棧,但那些軟件棧也與它相關。我們並沒有太多的Service。我們只有一個代碼庫,所以它也非常大,大約2GB吧。但絕大部分都用同一個軟件棧。

因些,當做部署時,先是web服務器,然後是API服務器。我們有內部的支持系統,異步任務,Gearman,以及類似於運行後台任務(Cron)的機器和相關設施,所有這些都是一次完成的。

InfoQ:那麼你會根據它們的重要程度做分別推送嗎?你要知道,有些部署可能會對用戶產生很大的影響。

Sam:我們非常喜歡現在這種工作方式的原因,就是因為這種方式決定了你說的這種情況不會經常發生。如果真有什麼事情非常重要的話,那麼你可以自己做部署,並確保更順利。但是,通常來說,我們更喜歡鼓勵大家以一種好的方式工作,以避免這種事情的發生。

InfoQ:也就是說,避免一次性做很大的變更,是嗎?

Sam:是這樣的。

InfoQ:所以,你們總是提交很小的變更?

Sam:當我們發布新功能時,我們會使用配置文件對功能進行控制,比如關閉這個功能,打開那個功能,因為很難一點兒一點兒的發布一個新功能。當需要發布某個功能時,我們再把開關打開。這種方法使得發布並不需要太多的精力,並且比較安全,我們可以做到只在公司內部發布,我們也可以做到只發布給屬於beta群組中的用戶,也能做到每次向百分之多少的用戶發布。

所以當做了一點兒改動時,我們常常只發布給1%的用戶,以驗證沒有破壞其它功能,然後再逐步發布給所有的用戶,而不是一次性發布。如果發布的是一個新特性,我們更多的時候只是把開關打開。但有時我們只會將特性發布給一部分用戶,以便觀察用戶在接下來的幾天裡是如何使用它的。我們會持續關注。

InfoQ:是不是說,beta用戶會被導向某個特定的集群?

Sam:節點都是一樣的。我們只是在運行時檢測,比如通過用戶的user ID。

InfoQ:你們是使用自己構建的系統做這件事呢?還是用其它的什麼工具?

Sam:我們自己寫的代碼。它原來的版本是開源的,而這個新版本要比原來那個版本好得太多了,但是還沒有發布,不過即將發布了。

這個項目的名字不怎麼好,好像是叫做Feature Flags之類的。它在我們Github的主頁裡。

這就引出了另一個話題,也是我們開發中使用的方法。我們並不使用Git中的分支。大家並不會在一個分支上工作很長時間。通常一個分支的生命周期很短,很快就會把代碼部署了。

有關故障

InfoQ:你們是如何處理故障的?

Sam:因為大家都被培訓過如何看圖表,如何查日志。通常我們發現故障是非常非常快的,因為一直有人在查看我們的那些度量項,這些度量項的確非常多。大家都非常了解這些度量項正常是應該是什麼樣子的。

InfoQ:那是一分鐘查看一次,還是一秒鐘?

Sam:我們使用Nagios做自動化的檢查。每個檢查的時間周期不同。有一些非常非常頻繁,而有一些則不是。我們不但有很多這種Nagios做的自動化檢查,還有一些人來看圖表,以及對應的模式。這種圖表的更新通常是一秒鐘。

因為一直在不停地部署代碼,所以不得不時刻查看那些圖表。既然經常看著那些圖表,那麼對我們來說,快速地發現問題也就不是什麼難事啦,因為一直不停地在做這件事,所以也就做得好啦。

InfoQ:聽上去感覺好像很依賴人肉啊?

Sam:是這樣的。但我們也有像Nagios這樣的工具來檢查那些可能出錯的地方。不能及時捕獲故障的情況很少,幾乎總是能馬上發現問題。那些無法用Nagios無法檢查的東西在半夜也不會出問題,因為沒人會在大家都睡覺時去部署代碼。那些出錯的地方通常都是在系統級別上,而通常都是由Nagios來監控的。在白天我們工作時,因為有新的部署,這些地方才有可能出錯。但這時會有人看著,因為他們正在部署代碼。所以那些很難用計算機去監控的東西在晚上不會出錯。

InfoQ:那麼,當出現了一個問題時,你們會采取什麼樣的措施?

Sam:如果某次部署嚴重地影響了網站,我們所做的就是要求大家別再推送代碼,並讓整個生產線停下來,然後無論是誰發現的問題,他都要馬上開始分析,嘗試找出是哪裡出的錯。我們都可以訪問那些日志和圖表數據。當我們確定哪個特性出了問題時,我們會聯系那些做這個特性的人或可能知道這個特性的人。通常情況下,如果與部署有關的話,相關的部署人員都已經就位了,因為我們時刻使用IRC Chat。

大家都在這個聊天室中,所以如果是部署問題,正在做部署和觀察監控的人就知道哪裡出了錯,很可以也已經知道如何修復它了,因為每次部署只做了很小的改動,所以他們可以將代碼回滾,部署原來的那個版本。但對於比較小的缺陷,我們更傾向於推送新的修復代碼,而不是回滾。就是直接修復好缺陷,再次部署。

InfoQ:那會花的時間較長吧。

Sam:是的。所以如果只是小問題,能很快修復,那就提交並部署新的代碼。因為即使回滾的話,你也要再一次推送代碼,總共也需要大約十分鐘的時間。因為先要上試運行環境,然後才是生產環境。所以無論你是提交修復,還是回滾,花的時間差不多。如果你多花五分鐘 能夠正確地修復問題,其實並不賴,甚至可能更好。

所以,通常我們會這麼做。如果問題很嚴重,顯然我們會先回滾,然後再找問題的根本原因。然而經常遇到的情況是你並不能完全確定回滾就是你想要的結果,所以與盲目回滾相比,我們更多的是試圖找到真正的問題所在。

InfoQ:向前修復通常是以什麼樣的方式進行的呢?

Sam:大多數在部署時遇到的問題並不會影響整個網站,它們只是會影響其中的一小部分。如果是向前修復的話,當你在修復這個問題時,其他人還可以繼續推送他們的代碼,繼續做他們原來做的事情。但是,顯然我們做這種決定要基於故障的嚴重程度。

InfoQ:修復不好,怎麼辦?

Sam:如果不立即修復的話,就要開始做回滾操作。

InfoQ:比如說,花了十分鐘以後,你也不能修復故障怎麼辦呢?

Sam:我們並沒有那種嚴格的用於快速決策的規則。但是如果大家不得不在那裡等待你修復你的問題,那通常說明什麼地方出了問題,其他人就不會部署代碼。如果你耽誤其他人部署代碼太長時間的話,那麼我們的做法是采取最快的方式,無論哪種方式都行,讓大家可以部署代碼。所以十分鐘過去了你還沒有找到問題,但你認為回滾會讓工作回到正軌上的話,當然你就要先回滾,然後在你自己的機器上繼續找問題。

InfoQ:能講一下新近的一次故障嗎?

Sam:好。比較典型的情況是,我們只會遇到一些很小的問題。比如,有人正在修改一個頁面,而此時我們網站上的一個賣家正在修改他有多少東西可以賣。我並不能說這是一個現在正在發生的案例,但是,它的確與我們看到的小故障類似。這個開發人員修改的恰好是這個頁面,那麼賣家可能就會看到一個錯誤,但這並不會耽誤大家在網站上賣東西。這時我們會認為,問題並不大。這個開發人員去查看一下,然後修復它就行了。通常由於變更很小,所以直接修復,然後推送部署就行了。但要強調的是,如果問題比較嚴重,那就會回滾。

最近就發生了一個非常嚴重的問題:我們在數據庫中使用完整的IDs,而這些IDs不是自增的。我們沒有讓數據庫來做這種ID自增,因為我們所有的數據庫都是雙主方式(two masters)的,即master-master。所以無法使用自增,因為你不知道哪個master是最近一次做自增操作的。所以我們有另外一個服務器,由它來專門提供這些自增數字。這個服務器也有兩個。其中一個只產生奇數,而另一個只產生偶數。 這就是用戶ID帳戶的來源。

幾個月前,這個服務器的數字超過了231,所以溢出了32位的整數列,但這也不是太大的問題,因為你可以把它保存在一個64位的列中。然而,在代碼中的一些地方並沒有這麼做。但是,大家並沒有意識到為什麼ID突然出現了64位。因此,當ID太大時,一些相關的特性就無法工作了。

這些地方的代碼無法得到合理的ID,但仍舊試圖把它保存到數據庫上,但數據庫無法保存它。當這個問題發生時,我們立刻要求大家不要再推送代碼了。我們只花了大約一分鐘就找到了這個故障的原因,因為在日志裡有很多錯誤信息,這些信息中能看到那些數字。如果之前你看到過這樣的數字,你會就發現這個問題。你能想像得到當看到這樣的數字時,那種不祥的感覺。

我們看到後,我們就立刻停止推送,是我們的團隊(core platform team)發現它的。盡管我們知道這是一個嚴重的問題,但我們並不知道有多少數據庫表使用了它,因為沒有地方可以看到這樣的信息。我們召集大家,包括一些運維工程師和我們團隊的一些人,到會議裡來討論如何處理這個問題。最後決定相看所有的表,看看到底哪些數據庫表的列寬不足。

在數據庫裡,代碼中,以及寫的schemas中都可能有相關的信息。所以我們只能查看所有的代碼,來判斷有多少schemas中存在這個問題。有些只是代碼中有問題,有些只是在數據庫中有問題。有些地方則是兩方面都有問題。同時,其他人來判斷哪些特性受到了牽連。我們從錯誤日志中有可能發現這些受牽連的特性,也可能從圖表上發現。只要發現了,就可以找以相應的配置文件,把這些特性關掉。

一旦我們修改好所有的地方,我們就可以在數據庫上運行這些變更,將那些字段改成64位,再把關掉的特性開關打開,然後馬上監控,看哪些數據還會出異常。整個過程只持續了幾個小時,而且只有幾個比較小的特性受到了影響。但直到把全部問題都修復了,我們才能知道到底有多少特性受到了影響。因為很多影響不是顯而易見的。

InfoQ:這是一個相當快的修復了。

Sam:是的,這是最糟糕的故障之一。我想,在過去的幾年裡我們並沒有出現太多的問題。在過去的幾年只,可能停機的時間不超過三小時,停機事件也很少發生。如果真發生了,那絕對是很糟糕的事情。

監控

InfoQ:你們如何做服務器監控?我是指網絡性能監控和應用程序的監控。

Sam:對於網絡性能,我們用Cacti,以及我們自己寫的一個工具,叫做FITB,在Github上開源了。他會監控所有的switch,並保持那些度量項數據比較少。它有點兒像Cacti。但我不記得到底區別在哪裡了,因為我很少處理網絡度量數據。我們用這兩個工具監控不同端口上switch的性能。我們在這方面很少遇到問題。網絡幾乎沒有給我們帶來任何麻煩。我們的容量目前是足夠的。

InfoQ:那麼,系統常見的瓶頸在哪裡呢?

Sam:更多的是數據庫和memcache。最近,我們在memcache上遇到了問題,而且與網絡相關。有很多特別關鍵的數據保存在memcache中,很多人都需要用。最近,在美國,我們的流量陡增。好象是在Cyber Monday(譯者注:感恩節假期之後的第一個上班日的網購促銷活動),流量非常高,有一個關鍵數據被訪問了很多次,其中的一個memcache服務器占滿了網絡連接。而對這個問題的修復方法只是不再把這個數據放在memcache中了。因為根本不需要放在那裡,所以我們就把它從那裡刪除了。但這個修復並不合理,因為直到網卡飽和了,我們才發現。

我們用Cacti,但我並不知道它的監控頻度是多少,也不知道其他人隔多長時間來看一下數據。當然,我們用Nagios來監控這個數據,判斷事情是否出了問題。

對於客戶端數據,我們有自己的一套信號器,記錄用戶在網站上的操作,這些信息會保存到我們的大數據棧上。對於用戶行為的監控,我們使用Hadoop集群,來處理分析這些信號量,比如我加載了主頁,點擊了一個物品,並買下了它。我們會觀察分析這類的操作模式。我們也會將前端JavaScript的錯誤記錄到後台。我們既有服務器端的性能測試,也有web頁面的測試,並經常運行它們。我們有一個web頁面測試集群,用它來判斷性能是否達到許可水平。

我們也會將應用程序的度量數據與用戶的行為做關聯。所以我們會度量有多少人在網站上查詢買品列表,以便來衡量用戶是如何使用我們的網站的。如果這樣的操作不再發生了,那麼也許我們應該在用戶體驗方面要改點兒什麼東西了。我們也會保存我們幫助論壇的那些圖片。這樣的話,如果越來越多的人在幫助論壇中請求幫助的話,那麼很可能我們破壞了什麼功能。當然,還有來自客服的信息,我們常常和他們溝通來嘗試判斷用戶遇到的問題。
Copyright © Linux教程網 All Rights Reserved