必看!網際網路開發模式的經驗之談

qcloud發表於2019-01-10

> 本文由雲 + 社群發表,作者:韓偉

網際網路開發的核心問題

當我 1999 年進入網際網路行業工作的時候,華為剛剛通過了著名的 CMM 認證。當時作為一個小程式設計師,非常向往業界經典的軟體開發模式。因為看上去,如果企業實行了 CMM,我們程式設計師就不用再天天為了老闆一個拍腦袋的主意而加班開發了,各種各樣的奇葩需求和無理變更,也會煙消雲散。但是,在接下來的十幾年,幾乎沒有那個網際網路公司再去通過 CMM 認證。

是否 CMM 這種軟體開發模式,就根本不適合網際網路行業呢?這是一直以來我都在思考的問題。反而是跟隨著網際網路企業的一步步長大,我無意識的體驗了很多現在流行概念的早期實踐:敏捷、重構、持續整合、DevOps,這些實踐一開始都非常的幼稚粗糙,但是卻真正的伴隨著網際網路業務的逐步成長。所以,在討論網際網路服務的開發模式時,我認為必須要先搞清楚網際網路服務開發的核心問題是什麼。

img

本質:服務,而不是產品

軟體到底是 “服務” 還是 “產品”,這個話題一直都非常具有爭議。作為程式開發者,實際上是非常希望軟體能夠是一個產品,因為軟體的後續維護和修改,往往是 “導致” 專案失敗的最常見原因。然而事與願違的是,在網際網路企業中,打多數的軟體專案,表現出來的是典型的 “服務” 特徵:

  • 沒有明確的需求合同。這導致了沒有辦法為軟體設計固定的開發方案,也難以確定長期目標。
  • 沒有預付款和客戶驗收。網際網路服務使用者來了就用,爽了就給錢,不爽了就走,連溝通的機會都不會有。
  • 甚至連明顯的銷售環節都沒有。很多網際網路公司只有市場推广部門,而沒有所謂 “銷售” 部門,因為推廣就幾乎等於銷售,在推廣的同事,就必須把銷售的事情一起做了。

因此,在網際網路行業中,軟體開發更多的是以一種服務的形式存在。這種特徵,在對需求的分析管理;開發技術的選擇;整合與測試;運營和客服四個方面,都導致了不同於 “產品” 型軟體的巨大差異:

  • 對於一項服務來說,需求是持續變化的,你可以找到一些通用的模式,但是必須保持變化。
  • 開發效率是第一重要的,因為市場競爭中,應對需求變化快的單位將獲得更多的客戶。

由於服務必須保持長期的穩定可用,又要具備快速的更新部署能力,所以系統整合的效率和質量要求非常高。所幸的是系統執行的環境大多數都是在可控制的空間裡(比如開發公司自己的機房內)。

服務是公司和客戶的一種持續溝通和互動的過程,並非一個單向的發售行為,所以網際網路服務需要更多細緻的運營和維護的工具,否則難以做到迅速而細緻的滿足海量的網際網路使用者的需求。

img

小米的 MIUI 開發節奏

管理:手段.vs.工具

在各種專案管理的課程裡面,陳述了大量針對人去工作的方法。各種會議、報告、表格、評估、測量多不勝數,然而軟體專案進度的控制,依然是一個難度堪比登月的事情。——對於很多專案經理來說,程式設計師們基本是一個黑盒子,他們自己都不知道一個事情需要多長時間幹完,就更別提別人怎麼去預估和控制。這裡最大的問題,我覺得是:我們往往總是想著怎樣 “控制” 住軟體專案的進度,而忽視瞭如何減少不利於專案進度的因數。實際上影響軟體開發進度的主要因數,一般有一下幾個:

  • 程式設計師的能力水平。有一些專案其中的技術,是程式設計師完全沒接觸過的型別,這裡包含了學習、除錯的時間。
  • 開發過程中的各種修改變更。由於對可行性、需求確認等方面的因數,開發往往會走 “回頭路”。有些專案做到一般會發現技術上不可行,需要修改需求;而另外一些專案是在專案做到一半甚至快完成的時候,需求方發現需要修改產品設計,因為在產品可體驗之前,完全無法想象到最後會是現在的樣子。
  • 各種和開發無關的過程中的事務。這裡包括開會、寫報告、溝通、等待開發電腦編譯、處理開發伺服器故障、各種開發環境和測試環境的問題處理等等……這些事情往往都看起來不是非常 “有技術含量”,但是實際上會嚴重影響開發進度。因為開發工作需要一個穩定、專心的工作環境,頻頻的被各種事務打斷,會讓程式設計師反覆的花費時間去 “進入” 工作狀態——面對成千上萬行程式程式碼,要找到之前寫到哪個部分,其實不是那麼簡單。

針對上面說的幾個問題,很多都可以通過應用更好的開發工具來解決。比如一些新的需求型別,我們可以求助於網際網路上豐富的開源軟體和開源庫;面對需求變更,我們可以使用設計模式、單元測試等工具;開發中的事務問題,更是可以有大量業界先進工具可用:SVN,Git,Jira,Project,IDE,Chef,Docker……

img

與其我們拿著鞭子抽打程式設計師,還不如給程式設計師更好的開發工具,這樣對於專案進度的推動,其實更有好處。

資產:程式碼.vs.流程

網際網路公司是由人組成的,人是會流動的,有一些小型的公司,往往會因為一兩個核心員工的離職,造成整個系統的程式碼無法看懂,無法修改,從而最後導致公司完蛋。這種糟糕的情況,不止一次的出現過。然而,如果我們能有一套完善的開發流程,或者是習慣,以及配合良好的開發環境,加上有一定質量的程式碼,是完全能做到把專案程式碼,在不同程式設計師之間順利交接的。可惜我們很多公司管理者,並不重視程式設計師用什麼工具開發軟體,也不知道如何去提高程式碼的可讀性,所以造成我們的專案特別害怕人員變動。如果我們把人員變動看成是一個必然會發生的事情,那麼我們就會更重視整個程式碼的開發環境和開發過程,從一開始就把開發規範確定下來,規定使用什麼環境,應用何種工具,並且堅持執行,同時在實踐過程中不斷的改進。只有這樣有預備的去做,最後才會保留的住公司真正的資產。

img

一家網際網路公司,我們在評估其開發資產的時候,並不應看他 “擁有” 多少行程式碼,因為這些程式碼是無法直接賣錢的。而網際網路公司的開發速度,以及這個速度背後的能力才是最重要的。

敏捷開發的意義和實踐

敏捷開發是我們現在最常見的一個 “開發模式”,然而很多時候,我們看到 “敏捷” 兩個字,似乎就是讓程式設計師多加點班,或者忽略一些過程加快把程式碼弄出來,而真正理解 “敏捷” 含義的並不多。實際上,敏捷並不會加快單位程式碼的開發速度!敏捷最主要的目標,是應對需求不明確和需求變更,而這兩者正式網際網路服務中最常見的情況。

img

需求變更的原因

在網際網路服務中,由於沒有直接的 “客戶” 下單要求,所以很多需求,都是由公司內部的人 “代表” 的,最典型的就是我們的 “老闆” 們了。正式因為沒有明確的 “下訂單” 的過程,所以很多傳統的需求分析變得沒法做了,因為不管是老闆還是產品經理,都是面對著成千上萬的客戶去猜測他們的需求,如果他們自己能代表客戶還好,如果猜錯了,專案的程式碼肯定要修改。很多網際網路公司都非常重視 “資料”,原因就是這些 “資料” 往往代表了使用者對產品的看法,而這些看法成了網際網路產品設計的唯一客觀標準。然而這些資料本身,會包含了大量複雜性,由於統計方式、產品形態、季節時間等等,都會產生偏差。我們的專案需求,往往就是在這些偏差中確定。這就難免產生需求的變更了。

網際網路的客戶個體多,服務內容豐富,功能變化快,是網際網路專案中需求變更很多的主要原因。因此這也讓敏捷開發,成為網際網路專案開發中最重要的方法。——敏捷強調的是用原型來驗證需求,在網際網路服務裡就是,儘快推出服務,通過資料來驗證想法。如果我們能越頻繁的修正原型,就能越快的接近真正的需求,也就是說,如果我們的網際網路服務能越快的修正各種問題,同時越快的推出新的版本,就能讓使用者越牢固的 “黏在” 這個服務上。

架構設計實體化:單元測試

img

敏捷開發講究要快速的修改程式碼,我們往往會發現,程式碼修改的越頻繁,BUG 越多,這似乎是一個無法解決的矛盾。然而,在敏捷開發方法論中,有一個重要的措施,就是用來防止這種修改造成的 BUG 增加的。這就是——單元測試。 單元測試本質上,充當著自動的 QA 人員的角色,如果我們把所有的設計和需求,都先按單元測試的形式 “固化” 編寫下來,那麼我們在修改程式碼後,就能快速的、自動的、反覆的去驗證我們的程式碼有沒有問題。如果這些測試足夠全面和詳細,那麼我們是不會擔心程式碼修改導致大量的 BUG 的,因為單元測試會自動幫我們支出問題所在。一旦我們知道了問題,修正起來反而變成是最簡單的事情了。

假如一個專案的程式碼丟失了,但全面的單元測試都還在,那麼要重建這個專案並不困難,因為所有的需求,都被蘊含在這些測試程式碼中,程式設計師們幾乎不需要去重新啃文件,談需求,他們只要把程式碼弄成能通過單元測試就好了。這種需求的 “代表物” 不但是程式設計師開發的概念和目標,而且還可以自動的幫程式設計師去驗證他們的實現。所以,如果你要使用敏捷開發,要嘗試頻繁修改原型,就一定要使用 TDD(測試驅動開發),特別是高度重視單元測試的作用。

統一軟體設計思路的重要性

曾幾何時,我們認為,使用什麼語言開發,用結構化程式設計,還是物件導向程式設計……這些一般人難以深入理解的事情,都是程式設計師這夥頑固的傢伙的怪癖,基本屬於私人喜好的範疇。外人既不應該深入干預,也沒辦法去影響,因為如果你不識好歹去在這些事情上冒犯程式設計師,他們隨時可能一言不合就辭職。既然我們只需要可以執行的程式碼,我們為什麼冒風險去激怒程式設計師呢?然而,在網際網路服務的開發過程中,程式碼本身並不是某一個固定的、靜態的東西,它需要不斷的與時俱進,需要跟隨這業務的發展而變化,同時也會從某一個程式設計師手裡,流向整個開發團隊。在這種情況下,軟體開發習慣、程式碼的風格、程式的設計思路,就變成一個非常重要的事情了。

程式碼交流:物件導向

img

確實現在還存在大量的討論,說 “物件導向不是萬能的”。說得對,但是,世界上有什麼東西是萬能的呢?我只能說,在需求變更非常快的情況下,物件導向思想,是現在我們能選擇的最好工具了。在 “資料結構 + 演算法=程式” 的時代,軟體主要是以計算任務為主,電腦是為了代替人腦進行超乎想像的運算任務而存在。而在網際網路時代,軟體主要的任務已經變成了處理這個真實世界的資訊了。資訊的儲存、交換的任務,已經遠遠超過了 “計算” 的任務數量。雖然我們知道,所謂的資訊處理,最底層還是依賴大量的 “計算”,然而,我們的程式設計師們,早已不再需要編寫大量 “計算” 的程式碼,我們面臨的挑戰,是如何用程式碼準確而快速的表達這個世界。

物件導向思想包括分析、設計、編碼三個部分(OOA/OOD/OOP)。這些思想看起來繁文縟節,似乎非常囉嗦。然而,其核心思想卻非常簡單:從表達過程,轉向表達物件。人類的思維中,物件、或物體,是一個個具備自己的資訊特徵的個體,而行為和過程,往往是依附於這些個體的。比如鳥會飛、賬號會鎖定、汽車會死火等等。所以如果我們的程式碼,是以表達物件,把資訊和行為統一起來,是最接近於我們的認識規律的。

在網際網路開發領域,由於網路無處不在,涉及到的領域異常廣泛,如果我們沒有一個能把程式碼世界和現實世界聯絡的紐帶,我們的專案將非常難以理解。——難以理解的專案,就難以變化,從而就失去了網際網路最顯著的特徵。所以我認為,物件導向的思想,是每一個網際網路開發人員都應該理解的,並且應該是面對大部分業務時,首先考慮選擇的。

程式碼架構與重構

我見過無數的程式碼架構圖,裡面畫滿了程式和伺服器的拓撲,各種線條上標註了通訊協議,編碼格式,還有各種流程圖和協作圖,然而,這些架構設計,無一例外的對於需求變更毫無幫助。因為它們描述的是一種現狀,甚至連現狀都不是,只是一種猜測,一種關於現狀的猜測。隨著專案程式碼的不斷變化,程式碼數量和關係都會膨脹,這種程式、通訊級別的結構,除了越來越複雜以外,根本對於指導專案如何應對各種 “程式碼腐化” 毫無用處。

因此我們想到了流行的 “重構”,然而,如果我們只是重構程式的關係,通訊的層次,那些錯綜複雜的程式碼呼叫關係一樣存在。各種回撥、事件、耦合還是讓程式碼無法理解。我們只是在試圖把混亂塞到一些瓶子裡面,並沒有解決混亂本身。所以,我們需要的另外一個思想武器:程式碼結構。只有我們從另外一個角度,另外一個檢視去觀察程式碼,才能把握程式碼之間耦合的情況。正如建築裡的平面圖和立面圖,都是不可或缺的。

img

所以我們應該高度重視 “程式碼架構”,也就是描述程式碼之間的關係的架構,而不是程式之間的關係的架構。在關注程式碼互相呼叫、耦合的關係上,我們能把混亂複雜的程式碼關係理清,整理出一個便於理解,便於修改的程式碼外觀。這些工作看起來完全是針對開發人員的,但是實際上,這些工作是能提高整個開發效率的。它能讓程式碼從難以修改,變得容易修改,從而得以支援快速的業務需求變化,這是對業務、對產品最重要的支援能力。

持續整合的意義和實踐

不管是敏捷開發的快速迭代,還是重構系統,我們都將頻繁的編譯程式碼、部署、測試,也就是所謂的整合。如果我們的系統整合效率太低,那麼快速的迭代可能變成慢速的迭代,重構系統的頻率也會大大降低。有一些專案,每一次整合,都要最少經歷兩三個小時,如果不順利的話,搞一個通宵都未必能完成。“發版本” 是很多程式設計師和運維管理人員的常見加班原因。對於這個問題,很多小型公司開始的時候,並沒有給與足夠的重視,認為這些事情不過是程式設計師或者運維的本分工作之一,也是最日常的工作。真正得到出問題了,才發現重要性。

在任何一個網際網路應用業務中,我們都會需要 “發版”:出新功能、修改 BUG、啟動運營活動、甚至是機房搬遷。所有的這些,如果沒有一套合適的工具來保障,每次發版都會是一場噩夢。所以持續整合(CI),很自然的成為網際網路企業中最流行的、研究最廣泛的技術之一。

所有資產納入版本管理

持續整合的所有東西,都應該來源於版本管理系統(SVN/Git)。除此之外,軟體資產不應該存放在任何其他地方。版本管理系統應該是開發團隊的保險箱和金庫,除了程式碼以外,所有的資料檔案,配置,指令碼,文件,都應該放入這個保險庫。由於版本管理系統可以追溯到任何一個是時間點,這可以讓故障恢復,問題回溯有良好的支援。

img

關於原始碼使用版本管理系統,已經有很長曆史了。但是網際網路服務中,除了程式碼,還有很多其他的資源,比如圖片、資料、指令碼等等。除了產品專案外,我們的很多額外系統,比如運維工具、產品文件等等,都是需要妥善保管的,這些也都應該存放到版本管理系統中。

一般現在的版本管理系統,都有 “分支” 的功能,簡單來說就是類似於 “拷貝” 了一份新的資源出來,在這之上的修改,可以由我們選擇合併到其他分支或者放棄。所以 SVN 的常用方案,是啟動三個型別的分支:trunk/branch/tag,專門針對 “測試”、“開發”、“運營”。如果我們按預定的分支模型來設計版本管理系統的使用,那麼我們的持續整合就可以很細緻的選擇整合哪一個版本的內容。

而在 Git 裡面,每個使用者,都可以擁有自己的資源庫,這對於開發測試可以更加的靈活,但是對於使用者的要求更高一些:在不同的資源庫合併的過程中,需要更好的版本管理策略。持續整合系統可以自己擁有一個或者多個 Git 資源庫,這樣他們可以完全脫離版本管理伺服器來獨立執行。

自動化部署

我們曾經無數次的登入伺服器,無數次的拷貝檔案,無數次的修改配置,無數次的匯入資料到資料庫,無數次的……如果我們對這些重複,而且容易出錯的工作熟視無睹,我們將永遠的被這些本該機器去做的事情困住。 自動化部署,是整個持續整合工作中最重要的步驟。當我們每次發版都要很仔細的修改很多檔案的時候,我們是無法避免在某次倒黴的事故後被挨批的。只有我們能把部署工作,也用我們的開發能力去解決,編寫自動部署工具之後,我們才真正的能提升部署這個事情到一個新的臺階————我們終於可不再擔心發版。

img

和自動化測試一樣,自動部署指令碼,也是把一系列的技術需求,從紙面文件 + 人手處理,改成用程式碼實體化,並且可積累改善的方法。自動化部署工具在開源界也非常熱門,比如 jekins,還有 chef 等等,都是為了解決部署問題而發明的軟體工具。也許對於你來說,自己用 bash 開發一套指令碼才是合乎你的品味,但是不管怎樣,一定要有這樣的工具。就算要花費較長的開發時間,調動專案開發的程式設計師,一起來認真的開發一段時間自動部署功能,都是非常值得的。因為從今以後,你就可以擁有一個自己的部署系統,這個系統不但可以積累你的運營部署經驗,還能加入很多錯誤、故障的自動檢查,讓你不再需要匯出找 “永遠不出錯的” 運維人員。

自動化部署系統中,最核心的部分就是配置管理。擁有一個對現有環境資源集中管理的資料倉儲是非常重要的。如果每個你的指令碼可以識別自己所在的環境,以主動的方式去 “申請” 自己的配置檔案和安裝任務,是非常好的一個模式。因為從一個節點主動去分發程式,比不上多個節點向中心叢集請求部署任務,來的更容易穩定。因為在節點上的部署代理程式,能更準確的知道自己環境的情況,也可以做本地的測試。

自動化整合測試

前面曾經說過,敏捷開發非常依賴於自動化的單元測試。實際上持續整合,也非常依賴於自動化的整合測試。整合測試可以把自動化部署的結果進行檢驗,避免手工進行反覆驗證。如果只有自動化部署,而沒有自動化測試,那麼整合工作,其實還是非常浪費人力的。更重要的是,我們在每次 “發版本” 之後,總會擔心新的修改,導致一些舊的功能失效。這種問題實際上是很常見的,如果無法自動化的做這種迴歸性的測試,那麼我們每次發版還是要忍受漫長的測試工作進度。

img

自動化整合測試也有很多開源的工具可供選擇,特別是基於 B/S 模式開發的 WEB 程式,但如果是手機 APP 的專案,或者客戶端 C/S 程式(比如網路遊戲),對於這類伺服器系統的整合測試,往往需要我們自己根據業務來編寫測試程式。對於伺服器系統來說,一般我們針對其通訊協議編寫測試程式即可,而對於客戶端系統,如果是 GUI 系統的,我們還可以根據 GUI 的內部排程命令(安卓就有這樣的套件)來測試,但如果是類似遊戲這類業務,就只能用圖形識別技術了。

在持續整合的流程中,整合測試往往是最後一步的檢驗關口。如果整合測試失敗,應該給所有關注整合的人員傳送警報(實際上,如果成功也應該報告)。現在企業往往會用郵件、IM、微信、簡訊或者別的一些東西接收這種訊息。

DevOps 的意義和實踐

在網際網路企業初始的階段,運維工作往往是伺服器端開發人員兼任的。當我在承擔這種既是開發又是運維的工作時,往往非常羨慕那些 “開發、運維分離” 的公司。因為作為開發人員,沒有三班倒的值班備份人力,往往是 7X24 小時的待命狀態,工作壓力非常大。然而,當我自己參與到一些真正開發、運維分離的專案的時候,卻發現,專案運營事故中,最少有 70% 的事故,是由運維的原因造成的。

除了常見的硬體、網路故障,作業系統配置出錯,日誌清理出問題,部署配置搞錯,程式不小心殺掉等等都出現過。看來伺服器端開發和運維還真是難解難分,而 DevOps 的思想,就是為了努力解決這種矛盾。我們不應該再把開發和運維對立起來,而應該認識到,運維是開發的一種延續,運維的需求也是伺服器端系統的功能需求;運維是開發的目地,便利的、通用的運維工具,本身是能提高開發效率的一種專業產品。

運維與開發的一體性:運維、運營、QA

img

可以把 DevOps 看作開發(軟體工程)、技術運營和質量保障(QA)三者的交集

一個網際網路軟體的上線運營,往往是由開發人員編寫出來,然後經過 QA 人員測試,最後放在運營環境裡進行運營。這個過程並非是單向的過程,基於前文說的,網際網路服務都是在反覆修改迭代中完善的,所以專案本身,一定是由多個版本,反覆在開發、QA、運維之間迴圈交接。舉例來說,一個網路遊戲,在第一次開發出來後,都會經過比較仔細的 QA 測試,然後通過運維人員進行上線部署,最後由運營推廣人員進行宣傳,同時也要配合這些宣傳開啟遊戲內部的一些功能,客服人員也會在開始運營後參與進來,除了提供客戶諮詢外,抓作弊玩家和封帳號也會持續進行。而作為開發人員的遊戲策劃,立刻會關注遊戲系統的各種統計資料,以期在下一個版本中改善遊戲設計。這個過程,可以看到在產品開發出來之後,整個團隊幾乎都還是需要以各種方式 “使用” 此伺服器端系統的。所以我們在開發網際網路服務的時候,不能僅僅面向網際網路上的一般使用者,同時也需要考慮整個開發團隊的使用需求。

現代的網際網路軟體系統往往都帶有伺服器端部分。而這些伺服器程式需要 7X24 執行,因此產生了兩類非常明顯的需求:

  • 運維需求:這類需求往往表現為非功能性需求,它要求伺服器程式能夠適應大規模使用者訪問和持續穩定執行。
  • 運營需求:這裡需求通常是功能性需求,因為產品上線後,產品和運營、客服、測試人員,還需要持續不斷的使用這個系統,和網際網路的海量使用者進行互動。

運營:客服、活動

在網際網路服務中,運營是一個非常重要的環節。客戶除了直接使用網際網路軟體的功能外,背後其實往往還有大量的從業人員在通過這個軟體提供服務。

其中最常見的就是客服服務。客服往往最需要的是查詢功能————能夠查到系統中特定使用者的使用資料,從而協助客戶解決問題。客服的另外一個主要工作,是封帳號和封 IP。現在網際網路黑色產業鏈非常龐大,網際網路企業保護自己的手段其實不多,而客服是其中一個重要的環節,避免黑色產業侵襲自己的利益,就需要網際網路服務系統有人工干預其資料的能力。

運營網際網路服務另外一個常見的行為就是 “活動”,也就是開放一些限時的服務。就和超市一樣,網際網路服務也要定時或不定時的加入或關閉一些特別的服務。這些工作非常細緻和瑣碎,需要伺服器系統能夠提供人工參與或者機器定時啟動的一些功能。在《魔獸世界》這個網遊中,大部分的活動都是自動的和定時的,可以從遊戲裡的一個日曆功能查到。而在國產的網際網路產品中,的很多是臨時加入,需要人工維護的,如 “雙十一購物節” 這種。這些對於伺服器系統的版本更新,功能修改,都提出了更高的要求。

img

因此一般我們在設計網際網路服務系統的時候,就應該一開始就把運營需求,也作為版本目標納入開發計劃中。一些比較好的團隊,會抽象和總結同類網際網路專案(比如遊戲、電商型別)在客服、運營活動上的共性,形成一套標準的服務規範以及實現這個規範的介面。由網際網路服務開發團隊去實現這些規範的介面,提供功能上的支援,而另外一個運營開發小組,則負責根據這個介面,開發供運營團隊人員使用的介面、內部管理系統等。比如遊戲的運營規範會要求遊戲提供查詢角色區服、帳號的名字、等級等資料,提供介面在遊戲中釋出任務;電商系統的運營規範會要求網店提供本店銷售排行查詢、優惠券折扣介面等等。

運維:部署 (虛擬機器)、監控、統計

作為非功能性的需求來說,部署需求是第一位的。頻繁的部署是網際網路服務快速演變的基礎能力。另外,網際網路使用者的增加(和消退)也是非常迅速的,這導致了我們可能需要快速的進行伺服器擴容,或者縮容。這種情況都需要涉及到部署。所以我們在開發伺服器系統的時候,部署需求是第一個需要考慮。加上如果我們希望實行持續整合,那麼就更加需要重視部署的能力。作為伺服器端系統,如果被設計成帶有非常複雜的程式種類和程式通訊關係的話,要做好部署就會變得更加複雜。加上可能部署的環境還不統一,可能出現的問題就更復雜了。所以現在有大量的技術嘗試改善這個方面。首先被大家廣泛接受的是虛擬機器技術,也就是所謂雲伺服器(IAAS),這種技術能讓你無需直接操作硬體,不用扛機器到機房來進行部署,是一種巨大的進步。

而後現在我們有了 Docker 這種基於 Linux 容器技術的工具,這可以把伺服器作業系統層的差異環境,都統一成一個個 image 檔案,部署的時候只要執行 image 檔案即可。但是這些依然無法簡化錯綜複雜的伺服器程式關係,所以現在有了各種 “佇列服務” 技術,比如 Kafka,RabbitMQ, ActiveMQ 等等,這些佇列服務把程式間通訊簡化成專門的服務,減少了部署的複雜性。而 ZooKeeper 的廣泛使用,讓我們在多程式間協調和監控有了更多的手段。在具體部署工具方面,Chef 這一類軟體做了各種有益的嘗試,這些都是能讓我們優化部署需求功能的工具。

img

網際網路服務的 24X7 持續服務能力,實際上會收到各種挑戰,除了版本釋出可能導致的問題外,在大量機器硬體裡面,硬體故障率是一個固定的比例。網路抖動,機房線路故障也常常會出現。更容易出現的是異常的使用者訪問波動:一大波使用者洶湧而來,但是也有可能是 DDOS 攻擊。不管怎樣,你都需要隨時掌握伺服器系統的工作狀態。這時你就需要一個監控系統,但如果產品上線才發現要做,那往往已經很遲了。因為一個系統是否有問題,並不是簡單的從記憶體、CPU、網路卡流量就能看出端倪的,我們往往需要在服務開發之初,就定義好各種需要監控的指標,傳統常見的指標有:每秒主迴圈的次數、每秒處理業務包的次數、伺服器中快取的會話數等等……一些做的好的系統,還會有很多業務層面的監控指標,比如某個特定服務的處理效率、處理成功率等等。

既然一個系統有大量的監控指標,就涉及如何生成和管理這些資料的問題。傳統的做法是在系統中 “埋入” 這些監控程式,系統一邊執行一邊統計這些指標,然後定時生成日誌或者通過網路上報給某個監控系統。但是這種做法的缺點是:如果你需要更多的指標,或者修改指標的統計方法,你就被迫要修改程式碼,重啟服務,這樣會影響正在執行的服務。現在另外一個做法是,由系統把執行的原始資訊記錄成日誌,然後把日誌集中上報到一個監控系統中,這個監控系統一般都帶有分散式的檔案儲存系統和分散式計算統計能力。在蒐集到大量實時日誌的同時,這個系統根據預設的指標統計方法,不停的進行日誌統計,一旦發現統計結果有問題,就會報警。而這種統計由於是在大資料處理能力的平臺上生成的,所以往往發現問題的時間差能縮小到分鐘級甚至秒級。這種做法由於蒐集的是原始日誌記錄,所以就可以靈活的在系統執行時定製很多統計和報警的策略,但完全不會增加服務系統的壓力,也不需要修改服務系統的程式碼。

img

最後說說統計,任何一個網際網路系統,都是在使用者的使用中不斷優化的,這個優化的依據,最重要的客觀依據,就是統計資料。而統計資料,一般由兩部分構成:

  1. 使用者的行為資料。比如登入行為,就可以給系統留下使用者的 IP、登入時間、登出時間等資料;購買行為,就可以留下購買商品,購買價格,購買時間這些資料。
  2. 根據使用者的行為的關聯,統計出來的資料。比如根據登入行為,我們可以統計出使用者的線上時長,使用者重複登入的次數,使用者重複登入的間隔,還有什麼次日存留、七天存留等等……;根據購買行為,我們更是可以整理出使用者的購買商品傾向,ARPU 值,甚至同類使用者的購買共性,這些也是所謂大資料做商品統計的主要方向。

根據上面的分析,我們可以發現,實際上統計系統也是應該分兩個部分設計,一個是儘量記錄使用者行為的基礎資料,第二個是以複雜多變的統計條件,去挖掘這些使用者行為資料中包含的規律。對於第一部分,一個可以存放海量日誌資料的分散式儲存系統非常重要;對於第二部分,分散式的統計運算系統是必不可少的。對於這個體系,Google 的 Hadoop 提供了業界的示範。但是如果你願意,也可以使用這個思路自己來建設自己的統計系統,也許你的資料量無需要用到 Hadoop 那麼複雜。

總結

網際網路開發模式,是針對於網際網路本質上是一個 “服務” 而發展起來的。因為是 “服務” 而不是產品,所以應對快速變化的能力是最高的技術標準。我們傾向採用更適合表達需求的軟體開發技術、自動化程度更高的開發工具,來提高我們的開發效率,而不是靠單純的 “激勵主觀能動性” 來做管理。

因此我們在基於自動化測試、自動化部署等持續整合工具的平臺上,使用重視原型迭代的方法來開發專案,在反覆以原型確認需求,以及適應需求變化的過程中,逐步的完善整個開發生產線。並且把開發和運營視為一個整體,在服務的運營過程中,不斷的完善網際網路服務的運營工具,讓開發和運營在同一個生命週期裡生長。

此文已由作者授權騰訊雲 + 社群在各渠道釋出

獲取更多新鮮技術乾貨,可以關注我們騰訊雲技術社群-雲加社群官方號及知乎機構號

更多原創文章乾貨分享,請關注公眾號
  • 必看!網際網路開發模式的經驗之談
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章