從聽一首歌說起網易雲音樂這3年經歷了使用者量的爆炸式增長,作為一款口碑爆棚的音樂社群APP,在業務快速發展的背景下,後端的架構又經歷了怎樣的發展歷程呢?
本文回顧了一個大型網際網路應用的後端發展歷程,其中涉及到的一些技術內部基本有自研的替代品,出於通用性考慮替換成了相應的開源產品。
本文的讀者物件假設已經具備一定計算機基礎,如果你希望了解一個億級使用者網際網路應用的服務端會涉及到哪些技術,那麼請繼續讀下去吧~
故事從你開啟網易雲音樂的APP,點開一個歌單聽歌開始。那麼為了滿足你聽歌的簡單願望,我們的服務端攻城獅們都做了些啥呢?
你點開歌單,發起了一個HTTP請求,為了響應你的請求,我們搭建了一臺伺服器執行服務端程式,我們選擇免費開源的Linux+Tomcat。
為了編寫服務端程式,需要一種程式語言和服務端程式設計框架,我們選擇了業界流行的Java+Spring/SpringBoot。
我撐不住了伺服器有了,程式碼也寫好了,現在我們可以開始服務不同使用者的各種請求了。有一天你發現突然歌單打不開了,歌也聽不了了,看上去伺服器掛了。我們的工程師緊急聯絡PE發現伺服器的load很高,CPU、記憶體、網絡卡都吃緊,看上去是我們的熱心使用者太多,伺服器容量已經撐不住了。
經過這件事之後,大家一致覺得只有一臺機器太不靠譜了,晚上都沒法踏實睡覺。單臺伺服器無法支撐日益增長的業務請求,CPU、記憶體、網絡卡都到了瓶頸,而且一旦掛了就形成單點故障,影響服務的可用率,這時我們又添了幾臺機器搭建成叢集,通過分散式叢集來實現業務的平滑擴充套件。
太費資源了吧伺服器越來越多,如果一個物理機只執行一個服務端程序,資源無法得到充分利用,這時我們引入虛擬化技術(KVM,Docker)在一臺物理機上執行多臺虛擬機器,每個虛擬機器共享底層的物理機資源(CPU、記憶體、網絡卡、硬碟),將物理資源進行虛擬化按需分配,這就是雲端計算。
業務穩步增長,機器越來越多,我們發現每天中午和晚上是使用者活躍的高峰期,機器的load會隨著升高,其他時間段則是低谷,機器則比較空閒。不同的請求量對伺服器的資源配置提出了不同的要求,如果高峰期可以自動擴容,低峰期自動縮容,就可以實現資源的最大化利用,避免浪費,這時我們需要生產級別的容器編排系統(K8S)。
負載均衡使用者操作客戶端時實際上是向指定的域名(music.163.com)發起HTTP呼叫,這個時候需要去DNS伺服器查詢域名對應的伺服器IP,為了對外暴露統一的IP,實現後端伺服器的負載均衡,我們在客戶端和後端伺服器間加入了一層反向代理(Nginx),如此一來所有的服務端API都通過Nginx來轉發,服務的擴容可以只用修改Nginx增加內網機器IP就行。
業務快速發展,介面爆炸式增長,每次上線都配置Nginx不僅繁瑣,而且容易帶來穩定性隱患,此時迫切需要一個API閘道器來統一收攏所有的API註冊和露出。
資料存哪兒?使用者開始使用我們的服務之後,儲存使用者的各種資料需要資料庫,除了關係型資料庫(Mysql),還有各種NoSQL資料庫(Hbase,MongoDB)。隨著資料容量的不斷增長,單機資料庫已經無法滿足需求,這時自帶分庫分表的分散式資料庫就開始派上用場了。
寫資料庫的增刪改查程式碼比較繁瑣,需要一個ORM框架(Mybatis)來實現物件和關係型資料庫之間的對映,這樣讀取資料的時候,每一行資料都可以對映成記憶體中的一個物件,儲存資料的時候每個物件又可以對映成資料庫的一行資料。
使用者量增加後,大量日常的檔案儲存(如使用者頭像、朋友圈圖片)需要一個統一的檔案儲存中心,這時我們用上了分散式物件儲存平臺。
效能不行?快取來湊開放數字專輯售賣功能之後,我們發現使用者的購買熱情非常高,為了應對高併發大流量,減輕資料庫的壓力,我們引入分散式快取(Memcache,Redis)來抗一部分流量,避免資料庫宕機。
解耦神器,非你莫屬
為了避免業務的上游和下游強耦合,實現呼叫非同步化,或者應對突發流量,實現業務的削峰填谷,我們用到了訊息佇列(Kafka,RabitMQ,RocketMQ),將上游業務訊息快取到佇列中,由下游業務非同步消費。
分解巨無霸業務快速發展,團隊也在擴張,原有的巨無霸單點應用部署已經越來越制約業務的快速迭代和多人協同開發。為了避免單點,實現業務模組的去耦合和故障隔離,我們開始了服務化拆分程序。
我們將原本部署在一個程序中的程式碼拆分到多個程序放到不同的叢集中執行。服務化拆分之後相互之間呼叫不再是一個程序內呼叫,而是需要跨程序網路呼叫,這時需要註冊中心和RPC框架來實現服務的註冊、發現及跨程序呼叫。引入RPC框架之後,為了方便監控和線上調整執行緒池引數,又開發了RPC管控平臺實現動態管控。
排查問題隨著服務拆分的深入,使用者的一個請求可能會經過幾個甚至幾十個服務,如何定位問題出現在哪個服務,以及檢視各個服務的鏈路耗時,這時需要一個鏈路跟蹤系統。服務拆分之後,根據重要程度對服務進行定級(P級),為了保障核心應用的穩定性和可用性,引入了限流熔斷降級框架,可以實現應用閘道器層的全侷限流和單機限流和降級。
線上服務越來越多,機器越來越多,日誌分散,可檢索性差,為了統一的日誌查詢,方便及時定位問題,需要一套日誌平臺(ELK)。
團隊開發業務越來越複雜,團隊開始爆炸增長,需求迭代相互交織,開發、迴歸、預發、線上環境管理越來越複雜,此時迫切需要一個持續整合平臺管理環境和機器的自動分配、任務排期和釋出計劃。
為了實現前後端同步開發,介面的定義要優先於介面的開發,這時我們開發了一個介面管理平臺來達到事前約束的目的。前後端開發可以愉快地協同開發了。測試同學也可以利用平臺管理測試用例,介面覆蓋率得到了極大的提升。
看好你的報警線上介面越來越多,各種異常滿天飛,有些需要關注,有些可以忽略,這時我們需要一個異常報警平臺,根據服務將報警通過各種渠道通知到負責人。
隨著業務模型越來越複雜,老舊的架構開始腐化,鏈路也變得越來越脆弱,線上事故頻發,9999的可用率無法得到保證,這時我們需要進行架構梳理和全鏈路壓測,針對性地進行故障注入,全鏈路壓測平臺和故障注入平臺應運而生。
終極之路隨著使用者量的數量級升級,單個機房的叢集部署穩定性風險越來越高,可能光纖被挖斷或者機房斷電之後,服務就全部掛了,帶來的損失不可估量。這時,同城雙機房和異地多活單元化就提上了議事日程。
終於,服務的穩定性得到了極大提升,你可以放心地聽歌了。好了,不多說了,我又來了一沓新需求。
下面是一張時間軸,展示了後端基礎設施發展的整個歷程,囊括了企業基礎設施、基礎運維設施、研發提效設施、中介軟體基礎設施、測試基礎設施、大資料基礎設施等六大基礎設施。
後記:本文中涉及到的絕大部分技術方案都已經在內部落地,有一些還在進展中,不過相信很快就可以應用到生產環境。學無止境,勉勵自己在後端技術之路能越走越遠,成為一個懂業務的技術專家。
最近利用空餘時間整理了一些精選Java架構學習視訊和大廠專案底層知識點,需要的同學歡迎私信我發給你~一起學習進步!有任何問題也歡迎交流~