從應用到平臺,雲服務架構的演進過程
前言
MaxLeap早期是一家研發、運營移動應用和手機遊戲公司,發展過程中積累了很多通用元件。這些元件很大程度幫公司在移動研發過程中節省了時間和成本,有沒有可能以雲服務的方式開放出去,創造更大的價值?延續這個思路,公司成立了雲服務部門,嘗試服務的商業化。
從對內提供介面服務到對外提供雲服務,經歷了三個階段發展:1.0時代,定位對內服務,為公司研發的幾十款應用提供服務端功能,推送、統一使用者管理等API介面,可以說是非常普通的介面服務;2.0時代,定位對外服務,除了支撐公司的移動研發以外,同時對外開放服務,提供更多的功能介面,也參考了行業的通用做法,形成了針對移動研發加速和提高運營效率的BaaS雲平臺;3.0時代,定位基礎研發平臺,工具鏈逐漸完整,從研發、上線、運維到運營,提供應用管理、支付、IM、推送等SaaS功能,也提供託管、釋出、監控、日誌等PaaS功能,逐步形成SaaS + PaaS的研發平臺。
雲服務概念
常見的雲服務有幾種方式:
1. IaaS(Infrastructure as a Service),基礎設施即服務。提供雲端的基礎設施為主,比如提供主機、儲存、網路、CDN、域名解析等功能,知名廠商有阿里雲、AWS、Azure等;
2. PaaS(Platform),平臺即服務。提供雲端的釋出、資料庫服務、檔案儲存、快取服務、容器管理等基礎儲存和管理元件,自動化了程式的配置、釋出、管理,有Heroku、Google App Engine、Force.com等;
3. SaaS(Software as a Service),軟體即服務。提供雲端的應用服務,ERP、HR、CRM等線上系統,每個賬戶或者每家公司有獨立的資料儲存,通過賬戶進行許可權和訪問隔離,知名廠商有Salesforce、Successfactor、Zendesk等;
4. BaaS(Backen as a Service),後端即服務,起初專指標對移動端研發提供的雲服務,降低移動研發的複雜度,讓開發者關注與移動端開發即可。流行的服務有幾大類:綜合類:Parse、Kinvey;分析類:友盟、TalkingData、神策資料;支付類:Beecloud、Ping++;IM類:環信、網易;訊息類:極光、個推等。
我們在2.0時代把自己定位於BaaS,隨著功能的不斷演進3.0著眼於PaaS和SaaS。
1.0 單應用架構
背景
當時公司有幾十款App需要研發和運營,每個應用功能各異,種類包括瀏覽器、音視訊工具、社交工具、清理大師、圖片儲存類和手遊等,門類很多、很雜。如何提高研發效率,實現一套統一的研發、管理和運營體系,是當時的主要訴求。對主要功能進行梳理之後發現,各類應用共同需要依賴的元件包括,使用者體系、雲引數體系、推送服務、資料儲存和廣告服務。
需求基本明確後,目標是快速上線,然後小版本迭代。
設計
當時4個後端研發人員,Java出身,人少但是技術精幹。結合團隊情況和產品需求,決定採用如下架構,簡單但給力。
典型的Web應用架構方式,使用Nginx做反向代理和負載均衡,後面跟了多個JVM例項。每個JVM例項由Jetty作為應用伺服器,提供REST介面,服務層實現具體的邏輯。DAL層對DB和快取進行封裝,提供統一的資料訪問介面。Redis作為快取方案,支援多個shard水平擴容,TPS高、效能好。Cassandra作為資料儲存引擎,無中心、可水平擴充套件、易維護,沒有專門的運維人員,對研發人員非常友好,由於沒有事務場景,NoSQL完全滿足當時的需求。RabbitMQ作為訊息中介軟體方案,不同程序間通訊,支援HA,支援持久化。Zookeeper用於儲存基礎配置資訊。
小結
這種簡單的設計,有效支援了公司幾十款應用的執行,日訪問量達數十億級別。統一後臺基礎服務和移動端SDK後,提高了移動應用的研發和上線速度,研發了使用者管理、推送這些基礎功能,在移動端幾行程式碼搞定。通過控制檯,能有效管理應用和配置資訊。其實對於多數十多個研發人員的公司來講,這樣的單應用架構價效比最高,解決商業上的問題才是關鍵。
也有不少需要改進的地方,Cassandra作為業務資料的儲存,查詢非常不靈活,依賴設計時對row key和composit key的精確把握,擴充套件非常困難,再加上對翻頁、排序等支援有限,在資料層做了很多特殊處理。整個系統沒有脫單,Redis、Nginx還有單點問題,脫單是高可用系統中首要需要解決的問題。所有服務部署在一起,出問題時相互影響,專案耦合度高,擴充套件困難。同時,開發效率低,釋出新功能時相互依賴等,這些都是單用架構設計最明顯的問題。
2.0 服務化架構
背景
隨著業務不斷髮展以及新的產品定位,單應用架構的弊端不斷暴露出來,要求我們在新的規劃中,重新設計整個後端架構。
新的需求如下:
- 定位公有云,服務標準化;
- 多租戶支援,使用者資料需要隔離,每個公司都有自己的後臺管理和賬號管理,不同工作人員區分許可權職責,允許同時有多款應用,應用在邏輯上相互獨立,每個應用可以使用所有服務;
- 更靈活的儲存和查詢服務;
- 提供基礎資料分析功能,提供程式碼託管等更多雲服務。
設計
服務規模擴大後,大家解決單應用弊端的方法也都類似,以獨立執行的業務為單位,對服務縱向拆分,提高單個服務的聚合程度,降低服務間的相互依賴,從而解決降低研發、測試、上線過程中各個服務相互依賴、相互影響的問題。
除此以外,我們對資料儲存和網路層也進行了改進。平臺所支援的兩類服務,分別是雲服務和雲端計算。在新的設計中,雲服務部分的重點是重構、支援在新架構上快速研發新服務,雲端計算部分的重點是,構建起來一個穩定、可靠、高效的基礎架構。
雲服務部分
網路,最外層增加了ELB,IP地址直接暴露在公網是非常危險的方式,通過DNS配置CNAME指向域名,降低了被DDOS的風險,提高了Nginx的可用性。ELB本身會在訪問增加時,自動伸縮,配合IaaS廠商提供的AutoScalling服務,可以抵禦多數DDOS攻擊。通過Nginx作為反向代理和負載均衡,不同服務指向不同的upstram地址和埠。服務間禁止相互依賴。
容器,每個服務都執行在Docker中,服務之間環境和資源隔離,能夠快速遷移和部署,統一了交付和釋出流程。每個容器無狀態,服務遷移、擴容、宕機等問題迎刃而解,在服務化過程中起到很關鍵的作用。
資料,NoSQL部分主要依賴MongoDB,Wired Tiger + SSD,由於MongoDB的Schema-less特性,開發者可以根據自己的需求隨時調整實體的定義。天生為分散式設計,支援複製集高可用方案,支援多Shard水平擴充套件。關係型資料庫採用MySQL,用於實現支付、訂單、配置資訊等需要事務支援的業務,我們基於MHA實現MySQL的高可用和讀寫分離。不同服務所依賴的庫必須分離,從資料著手保障使用者資源的隔離。
儲存/快取,塊資料依賴AWS的S3,許可權控制、分桶策略比較實用,可用性有保障;快取依然使用Redis,為了解決單點問題,對原有版本進行了升級,採用官方的3.0叢集方案,支援分片和高可用,當然也有其它方案可選,比如codis等代理的方案。
雲端計算部分
資料收集部分採用REST + Kafka方式,其中很重要的一部分是DataTransform,用於資料標準化、過濾、流控等用途,基於vert.x實現。
計算部分參考Lambda架構實現,分為Speed Layer、Batch Layer、Serving Layer三層。
Speed Layer,基於Storm實現,引擎監聽Kafka中收集到的新資料,把一些對實時性要求高的指標計算完成,寫入展示層。Batch Layer,基於Hadoop生態實現,通過開源專案Camus,把Kafka中監聽到的資料儲存在HDFS中,然後通過HIVE或者M/R的Job,計算各種指標,工作流通過oozie來排程,最終結果也寫入展示層,並且覆蓋掉實時計算的結果。結果資料根據不同指標,按天、周、月分別儲存在Cassandra中,有很高的寫速度,無限水平擴充套件。展示層,資料同時用antlr4j實現了SQL解析,訪問Cassandra中的計算結果。
小結
相比較1.0時期,架構上更合理,擴充套件性、維護性、魯棒性都有很明顯提升。功能上,完成移動應用研發大部分元件(統計分析、支付、IM、社交、線上引數、推送、營銷、雲資料、雲端儲存、雲程式碼)。應用的研發、上線、運維、運營形成閉環,順利完成從對內服務到公共BaaS平臺的升級。團隊上,1-3人一個服務的研發,測試、上線的節奏可以自己把控。
當然,業務在演進,也有新的問題需要去解決。從功能角度,Nginx只能支援靜態方式設定反向代理,然後reload,而平臺有服務對應的後端服務和埠是有動態調整需求。從架構角度,在相對成熟的系統中,日誌、監控這些基礎元件需要統一收集、管理、處理。資料訪問層、RPC等基礎服務也要標準化。
3.0 平臺化
背景
對於創業公司而言,業務隨時會有調整,作為技術人員,需要能夠應對這種變化,架構上為這些變化做準備。產品向3.0演進由新的業務需求和架構自身的調整需求共同推動。新的業務需要支撐一個全網營銷的SaaS產品線,產品支援配置操作生成App+微信商城+手機網站,以及營銷,就是需要本來專注於移動端研發定位的BaaS,向PaaS化和SaaS前進。架構上是基礎元件需要進行升級,資料訪問層、RPC、日誌、監控系統等。於是我們提出一個目標,就是平臺化,資料訪問的元件以PaaS形式提供給開發者和內部團隊,標準化API閘道器、日誌、監控系統。
設計
設計上依然延續穩定、成熟、解決問題的思路。閘道器服務作為所有請求的入口,穩定、效能、水平擴充套件是考慮的要素。資料訪問層,就像一個專案的大動脈,所有的訪問壓力、瓶頸、安全問題會在這裡匯合,如何構建一條資料訪問的高速公路是我們的目標。日誌和監控,雖然沒有業務系統那麼核心,但是關鍵時刻出現問題需要排查時他們很大程度會影響解決問題的效率,好的監控系統能第一時間把正確的訊號通知到正確的人,而爛的監控只會為運維帶來困擾。
閘道器
我們設計閘道器的初衷是替代掉Nginx,在自研的閘道器上控制規則轉發、主機註冊、容器狀態檢查、負載均衡、服務拒絕、限速等功能。Nginx是非常優秀的一個軟體,也滿足一部分閘道器的功能,但是無法滿足我們不斷進化的需求。
整個網關係統由規則控制組件和容器管理元件兩部分組成。後的服務在啟動後,向Hydra-容器管理元件,註冊自己的服務、IP地址和埠資訊,Hydra隨後接管容器的生命週期管理,進行健康檢查,Failover處理,並把相關的資訊儲存在Zookeeper和MySQL中。規則控制組件在請求到達後,進行規制匹配、路由轉發、限制、限速等處理。
目前閘道器用在了大多數服務中,下步計劃是所有服務統一由閘道器進行管理,下圖是網關係統的最終形態。
資料訪問
結構化的業務資料主要儲存在MySQL和MongoDB中,設計上我們增加了資料代理層,代理層完全相容MySQL和MongoDB的資料訪問協議,讓開發人員對代理完全無感,表面上是在訪問特定的資料庫,實際上連線上資料代理後,由代理對資料操作做解析和路由。
當然,如果是僅僅實現代理的功能,有很多開源專案可以使用比如MyCat、MySQL Proxy等,我們對代理有這些需求,資料訪問路由和配置變更,資料訪問鑑權和處理,日誌採集傳送,流控和服務拒絕。
日誌系統
設計之初也有考慮自己研發,通過調研後發現ElasticSearch+Logstash+Kibana完全滿足我們的需求,並且ES的生態和社群非常活躍。通過早期幾個服務的試水,最終決定整個平臺基於ELK構建日誌系統。
我們是這樣做的,在每臺主機上部署Logstash Angent採集格式化的日誌資料,向Logstash Server傳送日誌。為了降低運維成本,我們把Logstash Forward做成Docker映象,通過Salt來管理所有的Agent。Logstash Server在拿到日誌資訊後,不做任何規則上的處理,將資料儲存在ES中。其實Logstash Server自身有日誌解析和格式化的功能,但這樣做會嚴重影響它的吞吐量,於是我們的方案是把日誌標準的流程控制在源頭。接下來,在Kibana中建立各種服務的面板和檢視,便可以進行瀏覽和檢索了,還可以週期對日誌進行rotate、分析。
監控系統
基於日誌系統的基礎架構,不同服務將Metrics輸出到檔案系統,通過LogStash和ES收集。在Kibana中定義檢視,Kibana使用ES作為自己的儲存引擎。比如新增一個檢視後,Kibana會在ES的.kibana這個索引中建立一份檢視的定義。
有了Metrics資料和檢視的展示,下一步是報警。利用Nagios的報警機制,基於JNRPE實現報警的邏輯。報警邏輯通過讀取ES中.kibana某一個檢視的定義,和對應的閾值設定,通過比較當前值和閾值,返回某一個服務對應特定指標的監控狀態。Nagios拿到狀態後,決定是否報警。
小結
相比較2.0時期,統一了主要的基礎元件,降低了不同服務之間重複勞動部分。通過日誌系統也提升了定位問題的效率,接下來還會考慮實現一套自己的請求trace系統,希望能夠跟蹤整個請求的生命週期,為尋找問題和定位效能瓶頸做參考。
總結
從應用到平臺,公司業務和產品定位在不斷的演進,架構也隨之發生了天翻地覆的變化。有一點是我們研發人員時刻要提醒自己的,不能脫離業務去談技術,滿足業務是原動力,一切拋開業務去空談架構的做法都是耍流氓。
成熟簡單的技術就是最合適的,踩坑在所難免,但是如何把有限的資源用於做對的事情,不僅對商業和產品適合,對研發也同樣適合。網際網路公司多數都有由小團隊、小想法、小產品,一步步發展起來的,在這個過程中能夠通過設計和決策,在正確的時間做正確的事情,讓產品能夠快速迭代,快速上線,才是架構人員最需要考慮的事情。