竟然是講運維,好在有一個人乾貨不少,在此記錄下所得。簡單追溯了一下這個DevOps才發現並不是一個新的概念,早在2010年就能看到有相關的人在追捧這個概念了。DevOps 就是開發(Development)和運維(Operations)這兩個領域的合併。(如果沒錯的話,DevOps還包括產品管理、QA、*winces* 甚至銷售等領域)。這種理念和現如今流行的微服務架構以及分佈式特性的相關理念不謀而合。
DevOps的八榮八恥
DevOps這個思想提出來已經五六年了,一直都是呼聲很高,落地很難,為什麼呢?這可能與各個公司的業務情況和技術發展路線有或多或少的關係,比如説創業的最早技術合夥人是運維出身或者技術出身,但是水平不高,為了公司持續發展,引入新鮮血液時,就會存在技術的先進性跟解決遺留爛攤子的矛盾。又或者業務本身偏向於用户,導致技術被邊緣化,產品又沒有好的架構,限制了快速發展等;所以,DevOps的推進一定要自上而下,憑藉挑戰自我,顛覆傳統的勇氣才能去落實。
DevOps的八榮八恥
以可配置為榮,以硬編碼為恥
△ 以可配置為榮,以硬編碼為恥
hardcoding一時爽,真正要做改動時,需要定位代碼,做出調整,甚至可能會破壞功能。以下可以説是配置的一個進化史
• 本地配置,程序⽣生成 (txt/ini/cfg)
• 集中配置, 動態⽣生成(Yaml/Json)
• 環境變量量(代碼⽆無侵⼊入&語⾔言⽆無關性)
• 服務⾃自動發現,⾃自動註冊(zookeeper/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的挑戰,掌握了新技能後,就可以隨取隨用。