本文由雲+社區發表,作者:韓偉 互聯網開發的核心問題 當我1999年進入互聯網行業工作的時候,華為剛剛通過了著名的CMM認證。當時作為一個小程式員,非常嚮往業界經典的軟體開發模式。因為看上去,如果企業實行了CMM,我們程式員就不用再天天為了老闆一個拍腦袋的主意而加班開發了,各種各樣的奇葩需求和無理變 ...
本文由雲+社區發表,作者:韓偉
互聯網開發的核心問題
當我1999年進入互聯網行業工作的時候,華為剛剛通過了著名的CMM認證。當時作為一個小程式員,非常嚮往業界經典的軟體開發模式。因為看上去,如果企業實行了CMM,我們程式員就不用再天天為了老闆一個拍腦袋的主意而加班開發了,各種各樣的奇葩需求和無理變更,也會煙消雲散。但是,在接下來的十幾年,幾乎沒有那個互聯網公司再去通過CMM認證。
是否CMM這種軟體開發模式,就根本不適合互聯網行業呢?這是一直以來我都在思考的問題。反而是跟隨著互聯網企業的一步步長大,我無意識的體驗了很多現在流行概念的早期實踐:敏捷、重構、持續集成、DevOps,這些實踐一開始都非常的幼稚粗糙,但是卻真正的伴隨著互聯網業務的逐步成長。所以,在討論互聯網服務的開發模式時,我認為必須要先搞清楚互聯網服務開發的核心問題是什麼。
本質:服務,而不是產品
軟體到底是“服務”還是“產品”,這個話題一直都非常具有爭議。作為程式開發者,實際上是非常希望軟體能夠是一個產品,因為軟體的後續維護和修改,往往是“導致”項目失敗的最常見原因。然而事與願違的是,在互聯網企業中,打多數的軟體項目,表現出來的是典型的“服務”特征:
- 沒有明確的需求合同。這導致了沒有辦法為軟體設計固定的開發方案,也難以確定長期目標。
- 沒有預付款和客戶驗收。互聯網服務用戶來了就用,爽了就給錢,不爽了就走,連溝通的機會都不會有。
- 甚至連明顯的銷售環節都沒有。很多互聯網公司只有市場推廣部門,而沒有所謂“銷售”部門,因為推廣就幾乎等於銷售,在推廣的同事,就必須把銷售的事情一起做了。
因此,在互聯網行業中,軟體開發更多的是以一種服務的形式存在。這種特征,在對需求的分析管理;開發技術的選擇;集成與測試;運營和客服四個方面,都導致了不同於“產品”型軟體的巨大差異:
- 對於一項服務來說,需求是持續變化的,你可以找到一些通用的模式,但是必須保持變化。
- 開發效率是第一重要的,因為市場競爭中,應對需求變化快的單位將獲得更多的客戶。
由於服務必須保持長期的穩定可用,又要具備快速的更新部署能力,所以系統集成的效率和質量要求非常高。所幸的是系統運行的環境大多數都是在可控制的空間里(比如開發公司自己的機房內)。
服務是公司和客戶的一種持續溝通和交互的過程,並非一個單向的發售行為,所以互聯網服務需要更多細緻的運營和維護的工具,否則難以做到迅速而細緻的滿足海量的互聯網用戶的需求。
小米的MIUI開發節奏
管理:手段.vs.工具
在各種項目管理的課程裡面,陳述了大量針對人去工作的方法。各種會議、報告、表格、評估、測量多不勝數,然而軟體項目進度的控制,依然是一個難度堪比登月的事情。——對於很多項目經理來說,程式員們基本是一個黑盒子,他們自己都不知道一個事情需要多長時間幹完,就更別提別人怎麼去預估和控制。這裡最大的問題,我覺得是:我們往往總是想著怎樣“控制”住軟體項目的進度,而忽視瞭如何減少不利於項目進度的因數。實際上影響軟體開發進度的主要因數,一般有一下幾個:
- 程式員的能力水平。有一些項目其中的技術,是程式員完全沒接觸過的類型,這裡包含了學習、調試的時間。
- 開發過程中的各種修改變更。由於對可行性、需求確認等方面的因數,開發往往會走“回頭路”。有些項目做到一般會發現技術上不可行,需要修改需求;而另外一些項目是在項目做到一半甚至快完成的時候,需求方發現需要修改產品設計,因為在產品可體驗之前,完全無法想象到最後會是現在的樣子。
- 各種和開發無關的過程中的事務。這裡包括開會、寫報告、溝通、等待開發電腦編譯、處理開發伺服器故障、各種開發環境和測試環境的問題處理等等……這些事情往往都看起來不是非常“有技術含量”,但是實際上會嚴重影響開發進度。因為開發工作需要一個穩定、專心的工作環境,頻頻的被各種事務打斷,會讓程式員反覆的花費時間去“進入”工作狀態——面對成千上萬行程式代碼,要找到之前寫到哪個部分,其實不是那麼簡單。
針對上面說的幾個問題,很多都可以通過應用更好的開發工具來解決。比如一些新的需求類型,我們可以求助於互聯網上豐富的開源軟體和開源庫;面對需求變更,我們可以使用設計模式、單元測試等工具;開發中的事務問題,更是可以有大量業界先進工具可用:SVN,Git,Jira,Project,IDE,Chef,Docker……
與其我們拿著鞭子抽打程式員,還不如給程式員更好的開發工具,這樣對於項目進度的推動,其實更有好處。
資產:代碼.vs.流程
互聯網公司是由人組成的,人是會流動的,有一些小型的公司,往往會因為一兩個核心員工的離職,造成整個系統的代碼無法看懂,無法修改,從而最後導致公司完蛋。這種糟糕的情況,不止一次的出現過。然而,如果我們能有一套完善的開發流程,或者是習慣,以及配合良好的開發環境,加上有一定質量的代碼,是完全能做到把項目代碼,在不同程式員之間順利交接的。可惜我們很多公司管理者,並不重視程式員用什麼工具開發軟體,也不知道如何去提高代碼的可讀性,所以造成我們的項目特別害怕人員變動。如果我們把人員變動看成是一個必然會發生的事情,那麼我們就會更重視整個代碼的開發環境和開發過程,從一開始就把開發規範確定下來,規定使用什麼環境,應用何種工具,並且堅持執行,同時在實踐過程中不斷的改進。只有這樣有預備的去做,最後才會保留的住公司真正的資產。
一家互聯網公司,我們在評估其開發資產的時候,並不應看他“擁有”多少行代碼,因為這些代碼是無法直接賣錢的。而互聯網公司的開發速度,以及這個速度背後的能力才是最重要的。
敏捷開發的意義和實踐
敏捷開發是我們現在最常見的一個“開發模式”,然而很多時候,我們看到“敏捷”兩個字,似乎就是讓程式員多加點班,或者忽略一些過程加快把代碼弄出來,而真正理解“敏捷”含義的並不多。實際上,敏捷並不會加快單位代碼的開發速度!敏捷最主要的目標,是應對需求不明確和需求變更,而這兩者正式互聯網服務中最常見的情況。
需求變更的原因
在互聯網服務中,由於沒有直接的“客戶”下單要求,所以很多需求,都是由公司內部的人“代表”的,最典型的就是我們的“老闆”們了。正式因為沒有明確的“下訂單”的過程,所以很多傳統的需求分析變得沒法做了,因為不管是老闆還是產品經理,都是面對著成千上萬的客戶去猜測他們的需求,如果他們自己能代表客戶還好,如果猜錯了,項目的代碼肯定要修改。很多互聯網公司都非常重視“數據”,原因就是這些“數據”往往代表了用戶對產品的看法,而這些看法成了互聯網產品設計的唯一客觀標準。然而這些數據本身,會包含了大量複雜性,由於統計方式、產品形態、季節時間等等,都會產生偏差。我們的項目需求,往往就是在這些偏差中確定。這就難免產生需求的變更了。
互聯網的客戶個體多,服務內容豐富,功能變化快,是互聯網項目中需求變更很多的主要原因。因此這也讓敏捷開發,成為互聯網項目開發中最重要的方法。——敏捷強調的是用原型來驗證需求,在互聯網服務里就是,儘快推出服務,通過數據來驗證想法。如果我們能越頻繁的修正原型,就能越快的接近真正的需求,也就是說,如果我們的互聯網服務能越快的修正各種問題,同時越快的推出新的版本,就能讓用戶越牢固的“黏在”這個服務上。
架構設計實體化:單元測試
敏捷開發講究要快速的修改代碼,我們往往會發現,代碼修改的越頻繁,BUG越多,這似乎是一個無法解決的矛盾。然而,在敏捷開發方法論中,有一個重要的措施,就是用來防止這種修改造成的BUG增加的。這就是——單元測試。 單元測試本質上,充當著自動的QA人員的角色,如果我們把所有的設計和需求,都先按單元測試的形式“固化”編寫下來,那麼我們在修改代碼後,就能快速的、自動的、反覆的去驗證我們的代碼有沒有問題。如果這些測試足夠全面和詳細,那麼我們是不會擔心代碼修改導致大量的BUG的,因為單元測試會自動幫我們支出問題所在。一旦我們知道了問題,修正起來反而變成是最簡單的事情了。
假如一個項目的代碼丟失了,但全面的單元測試都還在,那麼要重建這個項目並不困難,因為所有的需求,都被蘊含在這些測試代碼中,程式員們幾乎不需要去重新啃文檔,談需求,他們只要把代碼弄成能通過單元測試就好了。這種需求的“代表物”不但是程式員開發的概念和目標,而且還可以自動的幫程式員去驗證他們的實現。所以,如果你要使用敏捷開發,要嘗試頻繁修改原型,就一定要使用TDD(測試驅動開發),特別是高度重視單元測試的作用。
統一軟體設計思路的重要性
曾幾何時,我們認為,使用什麼語言開發,用結構化編程,還是面向對象編程……這些一般人難以深入理解的事情,都是程式員這夥頑固的家伙的怪癖,基本屬於私人喜好的範疇。外人既不應該深入干預,也沒辦法去影響,因為如果你不識好歹去在這些事情上冒犯程式員,他們隨時可能一言不合就辭職。既然我們只需要可以運行的代碼,我們為什麼冒風險去激怒程式員呢?然而,在互聯網服務的開發過程中,代碼本身並不是某一個固定的、靜態的東西,它需要不斷的與時俱進,需要跟隨這業務的發展而變化,同時也會從某一個程式員手裡,流向整個開發團隊。在這種情況下,軟體開發習慣、代碼的風格、程式的設計思路,就變成一個非常重要的事情了。
代碼交流:面向對象
確實現在還存在大量的討論,說“面向對象不是萬能的”。說得對,但是,世界上有什麼東西是萬能的呢?我只能說,在需求變更非常快的情況下,面向對象思想,是現在我們能選擇的最好工具了。在“數據結構+演算法=程式”的時代,軟體主要是以計算任務為主,電腦是為了代替人腦進行超乎想像的運算任務而存在。而在互聯網時代,軟體主要的任務已經變成了處理這個真實世界的信息了。信息的存儲、交換的任務,已經遠遠超過了“計算”的任務數量。雖然我們知道,所謂的信息處理,最底層還是依賴大量的“計算”,然而,我們的程式員們,早已不再需要編寫大量“計算”的代碼,我們面臨的挑戰,是如何用代碼準確而快速的表達這個世界。
面向對象思想包括分析、設計、編碼三個部分(OOA/OOD/OOP)。這些思想看起來繁文縟節,似乎非常啰嗦。然而,其核心思想卻非常簡單:從表達過程,轉向表達對象。人類的思維中,對象、或物體,是一個個具備自己的信息特征的個體,而行為和過程,往往是依附於這些個體的。比如鳥會飛、賬號會鎖定、汽車會死火等等。所以如果我們的代碼,是以表達對象,把信息和行為統一起來,是最接近於我們的認識規律的。
在互聯網開發領域,由於網路無處不在,涉及到的領域異常廣泛,如果我們沒有一個能把代碼世界和現實世界聯繫的紐帶,我們的項目將非常難以理解。——難以理解的項目,就難以變化,從而就失去了互聯網最顯著的特征。所以我認為,面向對象的思想,是每一個互聯網開發人員都應該理解的,並且應該是面對大部分業務時,首先考慮選擇的。
代碼架構與重構
我見過無數的代碼架構圖,裡面畫滿了進程和伺服器的拓撲,各種線條上標註了通訊協議,編碼格式,還有各種流程圖和協作圖,然而,這些架構設計,無一例外的對於需求變更毫無幫助。因為它們描述的是一種現狀,甚至連現狀都不是,只是一種猜測,一種關於現狀的猜測。隨著項目代碼的不斷變化,代碼數量和關係都會膨脹,這種進程、通訊級別的結構,除了越來越複雜以外,根本對於指導項目如何應對各種“代碼腐化”毫無用處。
因此我們想到了流行的“重構”,然而,如果我們只是重構進程的關係,通信的層次,那些錯綜複雜的代碼調用關係一樣存在。各種回調、事件、耦合還是讓代碼無法理解。我們只是在試圖把混亂塞到一些瓶子裡面,並沒有解決混亂本身。所以,我們需要的另外一個思想武器:代碼結構。只有我們從另外一個角度,另外一個視圖去觀察代碼,才能把握代碼之間耦合的情況。正如建築里的平面圖和立面圖,都是不可或缺的。
所以我們應該高度重視“代碼架構”,也就是描述代碼之間的關係的架構,而不是進程之間的關係的架構。在關註代碼互相調用、耦合的關係上,我們能把混亂複雜的代碼關係理清,整理出一個便於理解,便於修改的代碼外觀。這些工作看起來完全是針對開發人員的,但是實際上,這些工作是能提高整個開發效率的。它能讓代碼從難以修改,變得容易修改,從而得以支持快速的業務需求變化,這是對業務、對產品最重要的支持能力。
持續集成的意義和實踐
不管是敏捷開發的快速迭代,還是重構系統,我們都將頻繁的編譯代碼、部署、測試,也就是所謂的集成。如果我們的系統集成效率太低,那麼快速的迭代可能變成慢速的迭代,重構系統的頻率也會大大降低。有一些項目,每一次集成,都要最少經歷兩三個小時,如果不順利的話,搞一個通宵都未必能完成。“發版本”是很多程式員和運維管理人員的常見加班原因。對於這個問題,很多小型公司開始的時候,並沒有給與足夠的重視,認為這些事情不過是程式員或者運維的本分工作之一,也是最日常的工作。真正得到出問題了,才發現重要性。
在任何一個互聯網應用業務中,我們都會需要“發版”:出新功能、修改BUG、啟動運營活動、甚至是機房搬遷。所有的這些,如果沒有一套合適的工具來保障,每次發版都會是一場噩夢。所以持續集成(CI),很自然的成為互聯網企業中最流行的、研究最廣泛的技術之一。
所有資產納入版本管理
持續集成的所有東西,都應該來源於版本管理系統(SVN/Git)。除此之外,軟體資產不應該存放在任何其他地方。版本管理系統應該是開發團隊的保險箱和金庫,除了代碼以外,所有的數據文件,配置,腳本,文檔,都應該放入這個保險庫。由於版本管理系統可以追溯到任何一個是時間點,這可以讓故障恢復,問題回溯有良好的支持。
關於源代碼使用版本管理系統,已經有很長歷史了。但是互聯網服務中,除了代碼,還有很多其他的資源,比如圖片、數據、腳本等等。除了產品項目外,我們的很多額外系統,比如運維工具、產品文檔等等,都是需要妥善保管的,這些也都應該存放到版本管理系統中。
一般現在的版本管理系統,都有“分支”的功能,簡單來說就是類似於“拷貝”了一份新的資源出來,在這之上的修改,可以由我們選擇合併到其他分支或者放棄。所以SVN的常用方案,是啟動三個類型的分支:trunk/branch/tag,專門針對“測試”、“開發”、“運營”。如果我們按預定的分支模型來設計版本管理系統的使用,那麼我們的持續集成就可以很細緻的選擇集成哪一個版本的內容。
而在Git裡面,每個使用者,都可以擁有自己的資源庫,這對於開發測試可以更加的靈活,但是對於使用者的要求更高一些:在不同的資源庫合併的過程中,需要更好的版本管理策略。持續集成系統可以自己擁有一個或者多個Git資源庫,這樣他們可以完全脫離版本管理伺服器來獨立運行。
自動化部署
我們曾經無數次的登錄伺服器,無數次的拷貝文件,無數次的修改配置,無數次的導入數據到資料庫,無數次的……如果我們對這些重覆,而且容易出錯的工作熟視無睹,我們將永遠的被這些本該機器去做的事情困住。 自動化部署,是整個持續集成工作中最重要的步驟。當我們每次發版都要很仔細的修改很多文件的時候,我們是無法避免在某次倒霉的事故後被挨批的。只有我們能把部署工作,也用我們的開發能力去解決,編寫自動部署工具之後,我們才真正的能提升部署這個事情到一個新的臺階————我們終於可不再擔心發版。
和自動化測試一樣,自動部署腳本,也是把一系列的技術需求,從紙面文檔+人手處理,改成用代碼實體化,並且可積累改善的方法。自動化部署工具在開源界也非常熱門,比如jekins,還有chef等等,都是為瞭解決部署問題而發明的軟體工具。也許對於你來說,自己用bash開發一套腳本才是合乎你的品味,但是不管怎樣,一定要有這樣的工具。就算要花費較長的開發時間,調動項目開發的程式員,一起來認真的開發一段時間自動部署功能,都是非常值得的。因為從今以後,你就可以擁有一個自己的部署系統,這個系統不但可以積累你的運營部署經驗,還能加入很多錯誤、故障的自動檢查,讓你不再需要導出找“永遠不出錯的”運維人員。
自動化部署系統中,最核心的部分就是配置管理。擁有一個對現有環境資源集中管理的數據倉庫是非常重要的。如果每個你的腳本可以識別自己所在的環境,以主動的方式去“申請”自己的配置文件和安裝任務,是非常好的一個模式。因為從一個節點主動去分發程式,比不上多個節點向中心集群請求部署任務,來的更容易穩定。因為在節點上的部署代理程式,能更準確的知道自己環境的情況,也可以做本地的測試。
自動化集成測試
前面曾經說過,敏捷開發非常依賴於自動化的單元測試。實際上持續集成,也非常依賴於自動化的集成測試。集成測試可以把自動化部署的結果進行檢驗,避免手工進行反覆驗證。如果只有自動化部署,而沒有自動化測試,那麼集成工作,其實還是非常浪費人力的。更重要的是,我們在每次“發版本”之後,總會擔心新的修改,導致一些舊的功能失效。這種問題實際上是很常見的,如果無法自動化的做這種回歸性的測試,那麼我們每次發版還是要忍受漫長的測試工作進度。
自動化集成測試也有很多開源的工具可供選擇,特別是基於B/S模式開發的WEB程式,但如果是手機APP的項目,或者客戶端C/S程式(比如網路游戲),對於這類伺服器系統的集成測試,往往需要我們自己根據業務來編寫測試程式。對於伺服器系統來說,一般我們針對其通信協議編寫測試程式即可,而對於客戶端系統,如果是GUI系統的,我們還可以根據GUI的內部調度命令(安卓就有這樣的套件)來測試,但如果是類似游戲這類業務,就只能用圖形識別技術了。
在持續集成的流程中,集成測試往往是最後一步的檢驗關口。如果集成測試失敗,應該給所有關註集成的人員發送警報(實際上,如果成功也應該報告)。現在企業往往會用郵件、IM、微信、簡訊或者別的一些東西接收這種消息。
DevOps的意義和實踐
在互聯網企業初始的階段,運維工作往往是伺服器端開發人員兼任的。當我在承擔這種既是開發又是運維的工作時,往往非常羡慕那些“開發、運維分離”的公司。因為作為開發人員,沒有三班倒的值班備份人力,往往是7X24小時的待命狀態,工作壓力非常大。然而,當我自己參與到一些真正開發、運維分離的項目的時候,卻發現,項目運營事故中,最少有70%的事故,是由運維的原因造成的。
除了常見的硬體、網路故障,操作系統配置出錯,日誌清理出問題,部署配置搞錯,進程不小心殺掉等等都出現過。看來伺服器端開發和運維還真是難解難分,而DevOps的思想,就是為了努力解決這種矛盾。我們不應該再把開發和運維對立起來,而應該認識到,運維是開發的一種延續,運維的需求也是伺服器端系統的功能需求;運維是開發的目地,便利的、通用的運維工具,本身是能提高開發效率的一種專業產品。
運維與開發的一體性:運維、運營、QA
可以把DevOps看作開發(軟體工程)、技術運營和質量保障(QA)三者的交集
一個互聯網軟體的上線運營,往往是由開發人員編寫出來,然後經過QA人員測試,最後放在運營環境里進行運營。這個過程並非是單向的過程,基於前文說的,互聯網服務都是在反覆修改迭代中完善的,所以項目本身,一定是由多個版本,反覆在開發、QA、運維之間迴圈交接。舉例來說,一個網路游戲,在第一次開發出來後,都會經過比較仔細的QA測試,然後通過運維人員進行上線部署,最後由運營推廣人員進行宣傳,同時也要配合這些宣傳開啟游戲內部的一些功能,客服人員也會在開始運營後參與進來,除了提供客戶咨詢外,抓作弊玩家和封帳號也會持續進行。而作為開發人員的游戲策劃,立刻會關註游戲系統的各種統計數據,以期在下一個版本中改善游戲設計。這個過程,可以看到在產品開發出來之後,整個團隊幾乎都還是需要以各種方式“使用”此伺服器端系統的。所以我們在開發互聯網服務的時候,不能僅僅面向互聯網上的一般用戶,同時也需要考慮整個開發團隊的使用需求。
現代的互聯網軟體系統往往都帶有伺服器端部分。而這些伺服器程式需要7X24運行,因此產生了兩類非常明顯的需求:
- 運維需求:這類需求往往表現為非功能性需求,它要求伺服器程式能夠適應大規模用戶訪問和持續穩定運行。
- 運營需求:這裡需求通常是功能性需求,因為產品上線後,產品和運營、客服、測試人員,還需要持續不斷的使用這個系統,和互聯網的海量用戶進行互動。
運營:客服、活動
在互聯網服務中,運營是一個非常重要的環節。客戶除了直接使用互聯網軟體的功能外,背後其實往往還有大量的從業人員在通過這個軟體提供服務。
其中最常見的就是客服服務。客服往往最需要的是查詢功能————能夠查到系統中特定用戶的使用數據,從而協助客戶解決問題。客服的另外一個主要工作,是封帳號和封IP。現在互聯網黑色產業鏈非常龐大,互聯網企業保護自己的手段其實不多,而客服是其中一個重要的環節,避免黑色產業侵襲自己的利益,就需要互聯網服務系統有人工干預其數據的能力。
運營互聯網服務另外一個常見的行為就是“活動”,也就是開放一些限時的服務。就和超市一樣,互聯網服務也要定時或不定時的加入或關閉一些特別的服務。這些工作非常細緻和瑣碎,需要伺服器系統能夠提供人工參與或者機器定時啟動的一些功能。在《魔獸世界》這個網游中,大部分的活動都是自動的和定時的,可以從游戲里的一個日曆功能查到。而在國產的互聯網產品中,的很多是臨時加入,需要人工維護的,如“雙十一購物節”這種。這些對於伺服器系統的版本更新,功能修改,都提出了更高的要求。
因此一般我們在設計互聯網服務系統的時候,就應該一開始就把運營需求,也作為版本目標納入開發計劃中。一些比較好的團隊,會抽象和總結同類互聯網項目(比如游戲、電商類型)在客服、運營活動上的共性,形成一套標準的服務規範以及實現這個規範的介面。由互聯網服務開發團隊去實現這些規範的介面,提供功能上的支持,而另外一個運營開發小組,則負責根據這個介面,開發供運營團隊人員使用的界面、內部管理系統等。比如游戲的運營規範會要求游戲提供查詢角色區服、帳號的名字、等級等數據,提供介面在游戲中發佈任務;電商系統的運營規範會要求網店提供本店銷售排行查詢、優惠券折扣介面等等。
運維:部署(虛擬機)、監控、統計
作為非功能性的需求來說,部署需求是第一位的。頻繁的部署是互聯網服務快速演變的基礎能力。另外,互聯網用戶的增加(和消退)也是非常迅速的,這導致了我們可能需要快速的進行伺服器擴容,或者縮容。這種情況都需要涉及到部署。所以我們在開發伺服器系統的時候,部署需求是第一個需要考慮。加上如果我們希望實行持續集成,那麼就更加需要重視部署的能力。作為伺服器端系統,如果被設計成帶有非常複雜的進程種類和進程通訊關係的話,要做好部署就會變得更加複雜。加上可能部署的環境還不統一,可能出現的問題就更複雜了。所以現在有大量的技術嘗試改善這個方面。首先被大家廣泛接受的是虛擬機技術,也就是所謂雲伺服器(IAAS),這種技術能讓你無需直接操作硬體,不用扛機器到機房來進行部署,是一種巨大的進步。
而後現在我們有了Docker這種基於Linux容器技術的工具,這可以把伺服器操作系統層的差異環境,都統一成一個個image文件,部署的時候只要運行image文件即可。但是這些依然無法簡化錯綜複雜的伺服器進程關係,所以現在有了各種“隊列服務”技術,比如Kafka,RabbitMQ, ActiveMQ等等,這些隊列服務把進程間通訊簡化成專門的服務,減少了部署的複雜性。而ZooKeeper的廣泛使用,讓我們在多進程間協調和監控有了更多的手段。在具體部署工具方面,Chef這一類軟體做了各種有益的嘗試,這些都是能讓我們優化部署需求功能的工具。
互聯網服務的24X7持續服務能力,實際上會收到各種挑戰,除了版本發佈可能導致的問題外,在大量機器硬體裡面,硬體故障率是一個固定的比例。網路抖動,機房線路故障也常常會出現。更容易出現的是異常的用戶訪問波動:一大波用戶洶涌而來,但是也有可能是DDOS攻擊。不管怎樣,你都需要隨時掌握伺服器系統的工作狀態。這時你就需要一個監控系統,但如果產品上線才發現要做,那往往已經很遲了。因為一個系統是否有問題,並不是簡單的從記憶體、CPU、網卡流量就能看出端倪的,我們往往需要在服務開發之初,就定義好各種需要監控的指標,傳統常見的指標有:每秒主迴圈的次數、每秒處理業務包的次數、伺服器中緩存的會話數等等……一些做的好的系統,還會有很多業務層面的監控指標,比如某個特定服務的處理效率、處理成功率等等。
既然一個系統有大量的監控指標,就涉及如何生成和管理這些數據的問題。傳統的做法是在系統中“埋入”這些監控程式,系統一邊運行一邊統計這些指標,然後定時生成日誌或者通過網路上報給某個監控系統。但是這種做法的缺點是:如果你需要更多的指標,或者修改指標的統計方法,你就被迫要修改代碼,重啟服務,這樣會影響正在運行的服務。現在另外一個做法是,由系統把運行的原始信息記錄成日誌,然後把日誌集中上報到一個監控系統中,這個監控系統一般都帶有分散式的文件存儲系統和分散式計算統計能力。在搜集到大量實時日誌的同時,這個系統根據預設的指標統計方法,不停的進行日誌統計,一旦發現統計結果有問題,就會報警。而這種統計由於是在大數據處理能力的平臺上生成的,所以往往發現問題的時間差能縮小到分鐘級甚至秒級。這種做法由於搜集的是原始日誌記錄,所以就可以靈活的在系統運行時定製很多統計和報警的策略,但完全不會增加服務系統的壓力,也不需要修改服務系統的代碼。
最後說說統計,任何一個互聯網系統,都是在用戶的使用中不斷優化的,這個優化的依據,最重要的客觀依據,就是統計數據。而統計數據,一般由兩部分構成:
- 用戶的行為數據。比如登錄行為,就可以給系統留下用戶的IP、登錄時間、登出時間等數據;購買行為,就可以留下購買商品,購買價格,購買時間這些數據。
- 根據用戶的行為的關聯,統計出來的數據。比如根據登錄行為,我們可以統計出用戶的線上時長,用戶重覆登錄的次數,用戶重覆登錄的間隔,還有什麼次日存留、七天存留等等……;根據購買行為,我們更是可以整理出用戶的購買商品傾向,ARPU值,甚至同類用戶的購買共性,這些也是所謂大數據做商品統計的主要方向。
根據上面的分析,我們可以發現,實際上統計系統也是應該分兩個部分設計,一個是儘量記錄用戶行為的基礎數據,第二個是以複雜多變的統計條件,去挖掘這些用戶行為數據中包含的規律。對於第一部分,一個可以存放海量日誌數據的分散式存儲系統非常重要;對於第二部分,分散式的統計運算系統是必不可少的。對於這個體系,Google的Hadoop提供了業界的示範。但是如果你願意,也可以使用這個思路自己來建設自己的統計系統,也許你的數據量無需要用到Hadoop那麼複雜。
總結
互聯網開發模式,是針對於互聯網本質上是一個“服務”而發展起來的。因為是“服務”而不是產品,所以應對快速變化的能力是最高的技術標準。我們傾向採用更適合表達需求的軟體開發技術、自動化程度更高的開發工具,來提高我們的開發效率,而不是靠單純的“激勵主觀能動性”來做管理。
因此我們在基於自動化測試、自動化部署等持續集成工具的平臺上,使用重視原型迭代的方法來開發項目,在反覆以原型確認需求,以及適應需求變化的過程中,逐步的完善整個開發生產線。並且把開發和運營視為一個整體,在服務的運營過程中,不斷的完善互聯網服務的運營工具,讓開發和運營在同一個生命周期里生長。
此文已由作者授權騰訊雲+社區在各渠道發佈
獲取更多新鮮技術乾貨,可以關註我們騰訊雲技術社區-雲加社區官方號及知乎機構號