可是如今不少團隊在本身的摸索中,已經發現了這12條其中的一部分。而後我也跟不少朋友聊過這個話題,若是是來自大公司的話,他們不少會認爲這12條應該是平常應該作的事情。若是來自創業公司或者小團隊來講,這12條理念會讓開發速度變慢。但其實這12條理念其實能夠很是好的對抗software erosion。 前端
它的本意是隨着時間的流逝被消磨或者腐蝕掉了。前面幾個星期前寫的代碼,如今已經看不太懂,或者說公司有一個系統,你如今有一個新的需求,你要知足這個需求,就是要知足這12條例子最快地實現這個需求。若是如今運行得很好的一個產品,可能一兩年以後操做系統更新了,底層的依賴已經變了,這時你重啓系統,發現已經不能運動了,不知道怎麼回事。這樣的版本由於系統資源不夠了,必需要進行清理。咱們講一下Heroku這個公司,有很厲害的iOS開鎖的做者。這家公司並非很是成功的,由於它在10年被收購的時候,我看了一下它線上只有大概一萬個運用,他們的現金流應該是比較有限的。可是他們有很是強大的工程能力,他們仍是在10年的時候被兩億美金收購掉了。你們可能都回用git去管理代碼,平時部署會很麻煩,可是你只要用git push就能夠完成代碼的版本了。 git
我只要fork一下就能夠了,若是個人生活環境有什麼變化,我能夠直接fork一份。咱們爲何不直接用Heroku去開發呢?由於Heroku比全部的EPS都要貴一點,還有一個最大的問題,其實是很強的問題,部分AT是被牆掉的,因此沒有辦法。其實Heroku有不少的開源能夠去用,可是咱們發現這些克隆的版本都有不少的限制,咱們並非必定要造一個Heroku出來,去作咱們的開發。我只須要在Heroku這個創始人他們在建立Heroku的這個過程當中,學習會了這套理念,把這套理念用到咱們的開發中就能夠了。這邊是具體的12條,根據咱們的實踐下來,就是這12條。 docker
咱們並不須要所有都去應用出來。可是其中的部分,其實仍是挺有價值的。第一條實際上它的原文講的是每個代碼都要用獨立的代碼倉庫去管理,到如今就是microservices的架構。咱們知道Twitter每次公共的API調用都產生超過100次的內部API調用。 數據庫
有利於開發團隊進行協做、下降部署成本,異常快速回滾。這個就是咱們用到的內部的一些私有的倉庫,遵照這條發做的話會有一些好處,好比說一份代碼我只要修改一下定製就能夠了。若是說一個系統沒有辦法用一份代碼存儲的話,說明它必須切分紅多個代碼倉庫。這邊咱們用到三個比較基礎的東西,這個模型層,其實是私有的Ruby的代碼庫。 ruby
它封裝了一些對數據庫的操做,它是獨立成一個代碼倉庫,咱們能夠經過環境變量注入只讀的數據庫,這樣能夠確保它是很乾淨的。還有一個只寫的對外提供APT的接口。在這裏把它分紅不一樣的子系統,咱們能夠用X-Rate-Limit。這樣的好處在於不論是客戶端的問題仍是內部的其餘子系統的問題,或者說是來自外界的惡意攻擊,咱們均可以有辦法把攻擊降到最低。第二點跟剛剛一開始提到的,若是你須要系統遷移或者系統升級,這種狀況下怎麼樣保證系統很容易的進行遷移。須要對依賴作聲明。這邊的話是Gemfile的示例,這個文件會具體的申明用到哪個庫的數據。你能夠保證用到的都是如出一轍的版本。這樣仍是有點抽象,這裏舉個例子,Sidekg和系統默認的版本不一致,若是我用Bundle exec,未來萬一他們是不兼容的,或者代碼遷移到其餘系統,這個系統默認的庫就是不兼容的。 服務器
固然目前特別流行的docker是能夠很容易地知足這個需求,今天就不講這個事情。還有第三點的話,咱們提倡把配置放到Unix的環境變量中。一開始是放在代碼常量裏面,可是代碼常量有個很差的地方,你要修改的話要來回地改動代碼。這樣會影響你在代碼倉庫的一個狀況。若是你在好比說上線前的版本和上線後的版本配置不同的話,你要在代碼倉庫維持兩個分支,確定這樣是不合理的。仍是舉個例子,若是是ruby的話他有一個比較推崇的.ENB。 架構
第四點和第三點關係很大的,咱們對外部系統的依賴,好比說咱們要訪問七牛的API,咱們建議放在穩定變量,包括其餘的子系統。剛剛咱們提到了就是咱們的模型層,咱們會有對外暴露的兩個接口,這兩個接口會注入進來。這邊有個簡單的測試,你永遠不該該把不該該提交的代碼倉庫提交出去。這邊是個簡單的示例,這個腳本是很簡單的執行環境命令。若是咱們用dot enb的話,無論用什麼語音都是很容易實現的。可是它對整個系統的穩定性的幫助是很是大的。 運維
第五點的話其實對於咱們實踐下來,其實感受並非特別的重要,你們看一下就好。 tcp
第六是這樣的,就是應用應該做爲沒有狀態的進程去運行。除了和持久化相關的服務,其餘服務都是應該無狀態的。這麼作有什麼很差的地方?你沒有辦法確保同一個客戶同樣的進程保存在裏面,並且下一次這個客戶的請求也會到其餘的機器上。 ide
咱們剛剛提到了能夠經過環境變量的注入依賴,咱們提倡把每個獨立的應用綁定,就是內嵌HTTP的庫。他們直接對外綁定端口,對外提供服務,而不是依賴外部的服務容器運行。這個綁定的端口它未必以HTTP的協議進行運行。
而且咱們剛剛提到以這樣的方式去申明的話,這些服務就能夠做爲其餘的服務的依賴。高層次的API就能夠基於低層次的API執行了。以這樣的一種方式去作的話,接下去有很是好的應用,就是說咱們在最前端能夠用layer awore tcp proxy進行。若是它get某一個路徑的話,咱們能夠轉化到對應的m point上面。還有相似的作法,以相似的這種TCP的代理方式,咱們能夠很簡單地複製一份流量。我若是要進行系統的性能測試,我確定不能在正常環境下測,可是我若是部署兩份如出一轍的流量,這樣子一是能夠作性能的壓力測試,另外在線若是線上有什麼bug的話,新系統若是要上線,我同樣能夠用這樣的方式測試。相同的流量下來,它會有什麼樣的反應。這種方式在GitHub的應用,它不可能容許DNS的這種方式隨機給你指定某一個機器去響應你的請求。由於每一個推的,每一個往上面push的代碼都是跟我的相關的。可是以這種方式去作的話,就能夠捕捉到Git協議裏面的一段,而後咱們能夠抓出你的用戶名,能夠定向到對應的機器上去。這樣能夠作到很容易的擴容。
第八點,擴容的方式咱們提倡是以多進程的模型進行擴容。
雖然是以多進程的模式擴容的話,並不表明每一個進程是單進程的。由於咱們剛剛提到了,咱們提倡服務都是無狀態的。每一個服務都是無狀態,擴容就很容易。能夠把一樣的進程部署到不一樣的服務器上。後面兩點實際上講述多進程的模式,咱們提供的服務就不該該把本身變成系統的daemon。常見的把一個程序綁在後臺的一種方式,但這幾種方式其實都不太好的。第二個是把代碼放在阿帕奇的容器裏面運行,這樣兩份代碼互相會有衝突,你使用阿帕奇這樣的容器。另外的話像ruby的unicon,這樣子也是不夠好的。都會遇到不少奇怪的問題,若是進程掛掉了怎麼辦?進程異常退出,會飄到其餘的PID上面。若是咱們沒有作好好的環境隔離的話,會有不純淨的環境,額外的環境變量會對系統形成異常的影響。這邊仍是以Ruby爲例子,咱們以procfile示例,對外提供FTTP的服務,這兩個腳本隨時會由於各類緣由退出,若是以這樣的方式導出到upstyle。
第九點是快速啓動,優雅關閉。
第十點的話,咱們仍是但願開發、測試、部署的環境要儘可能接近。
不少公司由於分工很明確,代碼是開發寫的,生產環境和運行是運維的事情。做爲負責開發,要從需求的正確性到日後,整個代碼的正確性都是應該負責的。第二條機器太慢的狀況已經比較少見了,因此咱們儘可能保證開發的環境和運行的環境是同樣的。持續集成很重要,其實不少人,特別是小團隊可能會以爲持續集成,搞測試是一件很煩的事情。其實不是的,你要很簡易的搭一個不斷地跑測試的服務器是很重要的。它會往這個服務發一個HTTP的包,無論成功、失敗會發出來一份文件。整個環境的搭載是很容易的,大概一兩個小時就能夠搭起來了。我一直是寫Ruby的,對於創業公司來講這樣可能會有點過了,由於不少時候大家不知道會作成什麼樣子。這種狀況迴歸測試是很重要的,遇到一個bug,寫一個測試可以重現它。下一次這個測試會直接告訴你怎樣作的,這樣也是回到剛剛的一個主題,未來這個代碼不可維護了。任何的改動破壞到原來的東西,測試都會跑不過。第十點,我以爲是特別重要的一點。若是每一個系統都往文件裏面寫的話,每個日誌都會分攤在不一樣的地方,一旦出了問題,你都不知道該去看哪裏的日誌了。
據我我的得經驗,服務器滿了,都是日誌把磁盤寫滿了。理想的狀況下,應該是把全部的日誌直接標準輸出,再從印象到服務器上,這是理想的情況。
全部的日誌統一分析和處理。我一個朋友他跟我講說這12點其實對他們公司來講都是很正常的作法,可是小團隊的話若是搭這樣一套環境比較困難,咱們如今目前尚未搭本身的日誌服務,如今用的是一個國外的paper trail的服務。
這樣作的另外的好處就在於我能夠作日誌報警,若是出現這樣的一個狀況的話,我必須收到一封郵件。無論裏面多少個子系統,任何一個子系統出現問題,我均可以收到一封郵件。好的,謝謝你們,今天的分享就到這裏。
PS:開發者最佳實踐日·第8期-互聯網產品從設計到上線 北京站