1. 程式人生 > >又拍雲運維總監邵海楊詳解 DevOps “八榮八恥”

又拍雲運維總監邵海楊詳解 DevOps “八榮八恥”

邵海楊老專家在Tech Minds No.5中根據自己10餘年的研發、運維經驗,總結並分享了DevOps的“八榮八恥”、Herku PaaS的12要素宣言。

又拍雲運維總監 邵海楊

以下是分享全文:

今天我講的是DevOps的八榮八恥,和後面Herku PaaS的12要素宣言相呼應,大家可以一起對照的來看,這其實是一個互相印證的過程。

DevOps這個思想提出來已經五六年了,一直都是呼聲很高,落地很難,為什麼呢?

這可能與各個公司的業務情況和技術發展路線有或多或少的關係:

  • 比如說創業的最早技術合夥人是運維出身或者技術出身,但是水平不高,為了公司持續發展,引入新鮮血液時,就會存在技術的先進性跟解決遺留爛攤子的矛盾。
  • 又或者業務本身偏向於使用者,導致技術被邊緣化,產品又沒有好的架構,限制了快速發展等。

所以,DevOps的推進一定要自上而下,憑藉挑戰自我,顛覆傳統的勇氣才能去落實。

好的,下面我正式開始。

DevOps的八榮八恥

一、以可配置為榮,以硬編碼為恥

△ 以可配置為榮,以硬編碼為恥

做過開發的朋友都知道,程式跟變數分離會出現單獨的配置檔案,所以運維要像開發學習,學會把軟體和配置分離。

舉個例子,我們公司第一個版本自動化運維時,把所有的硬引數配置到upyun.cfg,如上圖。它的好處在於,只要編寫一個config函式,就可以把這種文字的執行方式,變成右邊nginx所能執行的格式。

並且可以用同樣一份配置去適用不同的後端軟體,如用haproxy替換nginx,只要重新寫一下config函式即可,運維和開發仍然可以使用同一份引數。

本地配置的文字格式有txt、ini、cfg,但是這些格式都沒有沒有硬性要求,如ini在php裡用的多一點,cfg在mysql裡用的多一些。

一般配置的檔案裡面會包括開關變數,除錯引數、可變引數、權重,以及關聯上下游的引數,這些都可以放在配置裡面,通過程式生成程式的方式完成。

第二代就不再使用它了。我們現在使用Yaml來定義配置檔案,通過它動態生成配置檔案,這兩者的思路是相同的,都是通過程式生成程式。

除此之外,現在也有一些更加流行的技術,比如通過etcd或者是consul來實現服務的自動發現、自動註冊。

 二、以互備為榮,以單點為恥

△ 以互備為榮,以單點為恥

互容互備一直是優良架構的設計重點。

我們早期做架構設計,使用了LVS+Keeplived+VRRP做轉換,這樣可以方便負載均衡,動態升級,隔離故障。現在第二代,已經在部分大節點使用OSPF和Quagga做等價路由的負載均衡和冗餘保障。

Nginx可以加Haproxy或LVS做負載均衡。MySQL可以做主從切換,或者是MMM的高可用成熟解決方案。

我們的訊息佇列之前用rabbitmq做,現在主要是redis和kafka叢集化,其中kafka已經遷到了Mesos容器平臺裡。

服務的自動發現、註冊,我們可以使用consul、etcd、doozer(Heroku公司產品),還有zookeeper。

主要區別是演算法不一樣,zookeeper用的是paxos演算法,而consul用的是raft演算法。目前看來consul比較流行,因為consul的自動發現和自動註冊更加容易使用。

etcd主要是CoreOS在主推,CoreOS本身就是一個滾動釋出的針對分散式部署的作業系統,大家可以去關注一下它。還有一個是hadoop和elk,大資料平臺的可擴充套件性是標配,很容易互備。

上面是舉了一些常見互備的軟體元件的選型,那我們應該如何設計一個無單點的架構呢?主要掌握以下幾點:

1. 無狀態

無狀態意味著沒有競爭,很容易做負載均衡,負載均衡的方式有很多種,F5,LVS,Haproxy,總能找到一種適合你的方式。

2. 無共享

以前我們很喜歡用記憶體來保持臨時資訊,如程序間的交換,這種方式雖然效率很高,但是對程式的擴充套件性沒什麼好處,尤其是現在的網際網路體量,光靠單機或者高效能機器是明顯玩不轉的。

所以我們現在就需要使用類似訊息佇列的元件,把資料共享出去,利用多臺機器把負載給承擔下來。

3. 鬆耦合/非同步處理

以前我們用Gearman這樣的任務框架。大家可以把任務丟進任務池裡,生成多個消費者去取任務。當我的消費不夠用時,可以平滑增加我的work資源,讓他從更快的去拿任務。運維平臺這邊以python/celery的組合使用更多。

4. 分散式/叢集協作

像Hadoop這樣的天生大資料/資料倉庫解決方案,由於先前設計比較成熟,一般都是通過很多臺機器擴容來實現map/reduce的擴充套件計算能力。

三、以隨時重啟為榮,以不能遷移為恥

△ 以隨時重啟為榮,以不能遷移為恥

關於這個點,我們講三個方面:

1. Pet到Cow觀念的轉變

以前我們說機器是pet,也就是寵物模式,然後花了幾萬塊錢去買的伺服器,當寶一般供奉。但事實上卻並不是這樣,任何電子裝置、伺服器只要一上線,便開始了一個衰老的過程。

你根本不知道在執行過程中會發生什麼事,比如說質量差的電容會老化爆漿,電子元器件在機房的惡劣環境裡會加速損壞,這些變化都是我們無法參與控制的,所以無論我們怎麼努力,都無法保障機器有多麼的牢靠。

谷歌指出的Cow模式就是指農場模式。就是要把機器發生故障當做常態,打個比方,比如說這頭牛死了,那我就不要了,因為我有很多這樣的牛,或者是再拉一頭新的牛。這就是我們軟體開發和運維需要做的轉變,去適應這種變化。

2. OpenStack虛擬機器的編排

虛擬化是個好東西,通過OpenStack我們很容易就可以做出一些儲存或者遷移的操作,但是在實施的過程中,也是一波三折的。

我們從2014年開始在內部推動OpenStack,當然我們也踩過OpenStack網路的坑。

那時候我們用雙千兆的卡做內網通訊,因為使用OpenStack實現虛擬化後,一切都變成了檔案,在網路上傳輸的話,對網路的壓力會非常大,結果就導致部分服務響應緩慢。

因為本身就是實驗性質,所以在硬體上沒有足夠投入,內測時也沒有推廣,所以影響不大。

2015年我們再上的OpenStack,全部都用雙萬兆的網絡卡做bonding,交換機也是做了埠聚合和堆疊。目前來說,只有雲端儲存沒有上線,其它雲處理,雲網絡的使用還是能夠滿足要求。

3. Docker的匯入匯出

Docker是更輕量級的資源隔離和複用技術,從2016年開始,又拍雲同時也在嘗試使用Mesos/Docker來實現雲處理的業務遷移。

四、以整體交付為榮,以部分交付為恥


△ 以整體交付為榮,以部分交付為恥

以往開發運維要安裝一個機器,首先要去申請採購,購買完了還要等待運輸,在運輸中要花去一天的時間,之後還需要配交換機和網路。

在這個過程中你會發現,簡單的給開發配臺機器,光上架就涉及到運維的很多環節,更不要說系統安裝,優化,軟體配置等剩餘工作了,所以大多數情況下你只能做到部分交付。

要如何解決這些問題?

通過OpenStack可以做到雲端計算、雲網絡、雲端儲存這三塊搭建完成之後,進行整體交付。

根據一些經驗總結,在整個雲平臺當中,雲端儲存的坑最多,雲端計算、雲網絡相對來說比較成熟。現在雲端計算的硬體基本上是基於英特爾CPU的虛擬化技術來硬體指令穿透的,損耗大概2%~5%,這是可以接受的。

至於雲網絡,剛才胡凱(B站運維總監)提到內網包轉發效率,我做過一個測試,在OpenStack的內網中,如果MTU預設是1500,萬兆網絡卡的轉發率大概為6.7xxGbps。

後來我在優化的過程中,也翻查一些文件,看到的資料是可以達到9.5xxGbps,通過不斷的摸索,對比測試後發現,如果把內網的MTU搞成大包,如9000時,萬兆網絡卡的儲存量直接達到了9.72Gbps左右的。

不過,這個MTU需要提前在宿主機上調整好,需要重啟生效。所以,這個問題發現得越早越好,這樣就可以做到統一排程,分配資源。

Docker的好處是可以做到Build、Shipand Run,一氣呵成。無論是對開發,測試,還是運維來說,Docker都是同一份Dockerfile清單,所以使用Docker在公司裡的推動就很順暢。

雖然OpenStack也可以一站式交付,整體交付,使用時非常方便。但是對開發來說,他還是拿到一臺機器,還是需要去安裝軟體環境,配置,上線,執行,除了得到機器快一些,對上線服務沒有什麼大的幫助。

所以我們現在的Openstack叢集一般對內申請開發測試用,外網生產環境還是以Docker容器化部署為主,這也是大家都喜聞樂見的方式。

但前提是開發那邊能夠適應編寫Dockerfile(目前是我在內部推動這種變革,如新的專案就強制要求用docker)。

五、以無狀態為榮,以有狀態為恥

△ 以無狀態為榮,以有狀態為恥

有狀態的服務真的很麻煩,無論是存在資料庫、磁碟開銷,還有各種鎖等資源的競爭,橫向擴充套件也很差,不能重啟,也不能互備。

所以,有狀態的服務對於擴充套件原則來說,就是一場惡夢。如何解決我們說的這個問題,那就要使用解耦和負載均衡的方法去解決問題。

1. 使用可靠的中介軟體

中介軟體其實最早出現在金融公司、證券公司,後來隨著網際網路行業不斷壯大以後,就出現了一些高可靠性的號稱工業級的訊息隊列出現,如RabbitMQ,一出來以後,就把中介軟體拉下神壇。

隨著中介軟體民用化,網際網路蓬勃發展,是可以把一些服務變成無狀態,方便擴充套件。

2. 公共資源池

我們可以通過各種雲,容器雲、彈性雲,做計算單元的彈性擴充套件。

3. 能夠被計算

如果你不想存狀態,那也可以被計算,比如說Ceph儲存,它的創新在於每個資料塊都是可計算出來的,這就類似無狀態的,每次都算,反正現在的cpu都這麼強悍了。

所以,無狀態是一個命題,在做架構的時候,你腦海裡一定要有這個意念,然後再看你用什麼樣的方式開動腦筋,預先的跟開發,運維溝通好,把應用拆分成一種無狀態的最佳組合。

六、以標準化為榮,以特殊化為恥

△ 以標準化為榮,以特殊化為恥

在標準化方面,我們在這幾個方面改良:

1. 統一輸入輸出

統一入口是我加入公司後做的第一件事情,我們用一個統一的文字,到現在也在用,然後推送到所有的邊緣,伺服器上面的元件,要用到的引數,都能從配置裡讀出來。

程式碼管理方面我們也使用git,git wiki,批量部署我們用ansible(早在2012年,我做了一些比較後,就在公司裡推行ansible,看來還是很明智的決定)。

2. 統一的流程管理

運維中使用python最多,所以我們使用了yaml和playbook。我們有自己的跳板機,通過VPN登陸,目前我們也在試用一個帶有審計功能的堡壘機,可以把每個人的操作錄製下來,然後再去回放觀察,改進我們的工作流程。

3. 抽象底層設計和複用元件

如果是開發者的話,就會寫很多的複用函式,對於優秀的運維人員來說,也要有優秀的抽象業務的能力,也要去做一些重複工作的複用準備,如頻繁的,繁瑣易出錯的手工操作抽象成若干運維的指令碼化。

最後是巧妙的利用虛擬化、容器服務、server-less微服務,這些服務是可以被備份,還原的,可以保持一個相對穩定的狀態,我們要拒絕多的特殊管理操作。

夏農-資訊熵理論裡說,變數的不確定性越大,熵就越大,把它搞清楚所需要的資訊量也就越大。理論上來說,如果是一個孤立的系統,他就會變得越來越亂。

七、以自動化工具為榮,以手動和人肉為恥


△ 以自動化工具為榮,以手動和人肉為恥

公司早期,用的是bash、sed、awk,因為我之前有搞嵌入式的背景和經驗,對一個十幾兆的嵌入式系統來說,上面是不可能有python/perl/nodejs等環境。

所以我們把伺服器批量安裝,部署,上線,做成了嵌入式的系統後,只要點亮以後,執行一個硬體檢測的程式,會把機器的CPU、記憶體、硬碟大小等都打印出來,供貨商截圖給我看,這個機器是否合格。

合格的機器可以直接發到機房去,在機器到了機房通上網線以後會有一個ansibleplaybook的推動。

自從用了這種方法以後,我們在公司裡面基本上沒有見到伺服器,一般直接產線上檢測通過後發到機房。

然後我們運維人員就可以連上去遠端管理,在過去的三年裡我們伺服器平均每年翻了三倍,節點翻了六倍多,但是人手並沒有增加。

關於tgz、rpm、pkg的打包部署,我們用的是tgz的打包及docker映象。優勢在於,我們自有CDN網路,軟體通過推動到CDN網路下可以加速下發。

關於整合測試、自動測試的釋出,像ELK集中日誌的分析、大資料的分析,我們現在使用ELK以後,只要有基礎的運維技術知識便可看懂,不需要高深的運維知識和指令碼編輯知識,大多數人都可以完成這份工作,好處就是你多了好多眼睛幫你一起來發現問題,定位問題。

最後是不要圖形,不要互動,不要終端。一旦有了圖形以後,很難實現自動化。原則就是,不要手工hack,最好是用程式生成程式的方式去完成這個步驟。

八、以無人值守為榮,以人工介入為恥


△ 以無人值守為榮,以人工介入為恥

運維部門要做的事情有三件:

1. 運維自動化

要有一定的業務抽象能力,要有標準化的流程。沒有好的自動化,就很難把運維的工作效率提升了,只要做好這些,就可以節省時間,從容應對業務增長。

而且運維自動化的另一個好處就是運維不會因為人的喜怒哀樂而受到影響穩定性,比如說我今天心情不好,你讓我裝一臺機器我還可以忍,你讓我裝十臺一百臺就不行了。但如果公司有了運維自動化的流程,這個事情就可以避免,因為誰做都一樣。

2. 監控要常態

2016年年初,我們特別成立大資料分析部門,我們把日誌做了取樣收集和過濾,通過大資料平臺做日誌的同構資料分析,重點關注4xx/5xx/2xx比例,響應時間分析如100毫秒、200毫秒、500毫秒,還有區域性的速率分佈,講真,這真是一個好東西。

3. 效能視覺化

資料的有效展示。現在ELK對我們的幫助很大,從監控圖上來看相關的資料指標,一目瞭然。這裡就不反覆贅述了。

DevOps的本質

最後,我們談一談DevOps的本質。

1. 彈性

像亞馬遜推雲時,那個單詞叫elastic,意思是,你要能夠擴充套件,如橫向擴充套件;你要能負載均衡,如果你是基於openstack/docker資源池,你的資源就可以複用,可以編排回滾。

比如說OpenStack有模板,我打一個映象包,稍微重了一點,Docker的就輕一點,Docker可以做一個滾動釋出,可以保留原來的程式、原來的容器,你可以做快速切換,這也是一種變化的彈性。

2. 無關性

如果是虛擬化資源,一切都可以在模板裡面設定,可以把底層的硬體、系統、網路撫平差異,比如說不管物理磁碟是1T(市面上缺貨)/4T/6T的盤,都可以劃分100G容量,所以當把一切變成按需申請的服務,無論是開發還是運維,工作都會比較簡單,因為它的無關性。

3. 不可變的基礎設施

這個對傳統運維可能是一種打擊,因為基礎映象可能已經做的足夠安全,足夠完美,足夠精幹,不需要基礎運維過多的人工參與。

但我認為恰恰能幫助傳統運維減輕工作量,反而有更多的精力去迎接虛擬化、容器化,SDN的挑戰,掌握了新技能後,就可以隨取隨用。

我現在是用比較開放的心態去接受這些變革,比如說像CoreOS這個作業系統,你到裡面去看一下,真的沒什麼各種元件,除了最基礎的就只有docker/RKT執行環境。

當然,這個是很極端的例子,但是我覺得當底層的作業系統,他可以做到自我更新,足夠安全的時候,確實不需要你去操心這個事情。這跟我們用小U盤做整體升級的思路是一樣的,但是它那個更先進,更徹底,更值得我們去學習。

Heroku PaaS的12要素宣言

Heroku是業內知名的雲應用平臺,從對外提供服務以來,他們已經有上百萬應用的託管和運營經驗。前不久,創始人AdamWiggins根據這些經驗,釋出了一個“十二要素應用宣言(TheTwelve-Factor App)”

1. 基準程式碼

一份基準程式碼多處部署,這個就是剛才講的標準化,還有複用元件,這些是吻合的。

2. 顯式宣告依賴關係

比如說像nodejs、go、maven,在提供的配置檔案上,要標明上下游的關係,標明可配引數。

3. 必須要在環境中儲存配置

這一點我覺得可以保留,雖然文字檔案也適用但環境變數有它的好處,一是語言無侵害性,二是程式碼無關性。比如說OpenStack裡也有環境變數,它是會匯入環境變數的那份檔案。

4. 要把後端服務當做一個附加資源

這就是我們一直在強調的鬆耦合,要把後端服務變成一個url去呼叫,像Mysql,或者是通過訊息佇列或任務框架。或者更加智慧一點,做自動的服務發現、服務註冊,把後端服務剝離開去。

這樣做的還有一個好處,就是能夠區分運維工作中哪些是重點資源,哪些是需要更多的人去監控後端的服務,當知道這是重中之重的時候,就可以把有限的運維力量投到上面去。

5. 構建、釋出和執行

用了Docker以後就很容易實現這個標準,關鍵是統一性、標準化和模板或容器格式。

6. 程序必須是無狀態而且無共享

任何需要持久化的資料都要儲存在後端服務裡。

7. 要做埠繫結

要通過埠繫結來服務,你可以基於Restful,也可以基於rpc或者是http,這樣的好處是鬆耦合和方便負載均衡,做水平擴充套件。

8. 併發

要通過程序模型進行擴充套件,方便擴充套件。

9. 易處理

快速啟動和優雅終止可最大化健壯性。參考雅虎原則。

對雅虎來說,如果開發需要上線服務,就必須向運維提供start、stop、status、reload/restart這幾個開關,如果你不提供這些開關的話,雅虎的運維是不允許這個服務上線的。

因為能提供stop,那就說明服務是能被隨時重啟的最好證明。

10. 開發環境與線上環境等價

儘可能保持開發、預釋出和線上環境相同。用了Docker以後,這個事情就不是個事情。

11. 把日誌當做一個事件流

我們現在用logstash和heka去做一些處理。對雲服務來說,我們現在發現,日誌越來越重要,日誌收集對我們來說價值非常大。

通過大資料分析平臺,可以做到秒級分析,秒級監控報警,秒級定位問題,甚至我們可以比客戶更早發現問題,我覺得這是一件非常有意義,值得我們投入精力去做的事情。

12. 管理程序

後臺管理任務可以當做一次性的程序執行,相當於微服務。