592
技術社區[雲棲]
映客直播技術實戰:直播平台的數據庫架構演變
摘要:8月24日,阿裏雲數據庫技術峰會到來,本次技術峰會邀請到了阿裏集團和阿裏雲數據庫老司機們,為大家分享了一線數據庫實踐經驗和技術幹貨。在本次峰會上,特邀嘉賓映客直播架構師王振濤分享了映客直播作為創業公司從0至日活千萬的數據庫架構變遷,數據庫在直播中的經典應用場景,數據庫存儲的優化思路,以及如何構建一個高可用數據庫架構。以下內容根據演講嘉賓現場視頻以及PPT整理而成。
本次分享的內容將主要圍繞以下四個部分:
一、映客直播發展曆程
二、直播遇上雲數據庫
三、風口上的數據庫架構變遷
四、直播典型應用場景分析
一、映客直播發展曆程

二、直播遇上雲數據庫
業務起步:映客APP發布
接下來為大家介紹映客直播從開始到現在的架構發展演變過程。當映客APP剛發布的時候,整個後台其實隻有三個人負責,兩個開發和一個運維,這時的架構如下圖所示。起初的架構其實是非常簡單的,後台是由8台虛擬機搭建而成的,其中的6台虛擬機做了服務,而剩下的2台做了存儲,存儲這部分則是使用了自己搭建的MySQL和Redis。在這個起步階段,對於後台係統要求最高的一點就是當出現了產品想法就需要盡快地實現,這樣的架構非常適合在業務起步階段的需求條件下實現一個直播APP,當時第一版本的開發工作隻花費了2周的時間。

業務發展:規模化
而隨著映客直播業務量的提升,從2015年的5月份到10月份,映客的DAU達到了10萬+,到12月份的時候就已經達到了100萬+,此時的業務發展已經達到了規模化的階段,這個階段的整體服務端的架構設計如下圖所示。此時的架構也是分為了接入層、業務層、基礎層以及數據層,但是此時的架構與第一版的架構相比,其整體的框架已經基本成型了,這一版的架構實現了一些業務拆分、數據拆分以及模塊化複用,此時服務的底層仍舊是依賴於Redis和MySQL數據庫的。這個階段最為顯著的變化就是引入了雲,也就是說此時的服務已經上雲了。

對於映客的服務上雲,當時的考慮主要基於以下幾點:
- DDoS,因為雲主機本身是可以防止DDoS攻擊的,這樣就可以將代理層全部都部署到雲上。
- 直播存在一個天然的屬性就是有很多的明星活動以及其他大V的活動,因為這些活動所造成的瞬時壓力是非常大的,如果使用自建機房就需要為這些可能僅僅持續幾個小時的活動而囤積很多台服務器,需要購買很多預留資源。而使用在雲之後,雲主機本身是按照使用量進行收費的,這樣可以將很多核心業務都部署到雲上,在出現瞬時活動需要進行擴容的時候就可以直接進行擴容,當活動結束之後就可以釋放這些多餘的資源,通過這樣的彈性伸縮可以極大地降低直播平台的運營成本。
- 雲主機以及雲數據庫等這些雲資源使用的都采用的是集群模式的部署,而其集群模式往往也是對於用戶透明的,這樣就可以理解成雲本身幫助我們實現了一層高可用。
- 平滑可伸縮,比如現在的數據庫的配置或者性能不能滿足需求了,就可以使用雲上的這些資源進行平滑地擴容,並且雲上的擴容對於服務是沒有任何影響的,而且包括SLB負載均衡器這些對於雲的用戶而言都是比較友好的。
綜合以上四點的考慮,映客直播在業務規模化的階段就使用了雲服務。

而使用雲服務之後首先需要麵對的一個問題就是:整體遷移。對於整體遷移而言,雲服務本身也提供了一些工具可以實現對於存儲進行實時地同步以及在最後進行切換,對於雲服務本身可以實現隔離以及製作鏡像之後就可以打包發布到雲上去。映客直播當時的業務量也不是太大,所以整體而言遷移上雲的過程還是比較順利的。但是任何事情可能都不隻會有好的一麵,當使用了雲服務之後同時也會遇到一些問題,映客在上雲的過程中也遇到了一些不可控的因素,也就是“水土不服”。比如當時的雲服務的MySQL連接數是有上限為2000的限製的,而映客當時采用的很多服務框架都是屬於多進程的框架,這樣就非常容易造成連接數不夠用的情況;並且當時外網帶寬限製是200M,很容易就跑滿了,而且內網帶寬也是一樣的情況;另外,在使用雲主機的時候也會出現一些資源搶占或者宕機的情況。綜上所述,在上雲之後有好的一麵,也存在著不是特別舒服的一麵。在這個過程中,映客不再僅僅是一個雲服務的用戶了,也演變成為雲服務的產品經理或者QA,映客與阿裏雲也是從開始的接觸、了解到後來的“相愛相殺”,並且一起來推進雲服務的優化,一直到雙方都達到比較好的狀態。
業務爆發:千萬日活
其實雲服務本身是作為基礎設施的,它可以為我們提供高質量的運維。但是當業務的日活、流量還在爆發性增長的時候,單單依靠雲服務這種基礎設施的能力還是不夠的,所以映客的服務框架也在不斷地迭代中。如下圖所示的架構框架是在映客上雲之後,進行了一次比較大的改造之後的框架,這個框架就已經實現了一些分層,主要分為了用戶層、應用層以及數據層,並且在雲服務基礎設施上實現了很多服務化的重構、存儲的優化等的一些技術中間件,做了方方麵麵的工作來保障當業務爆發達到千萬日活的時候,服務還依舊能夠支撐住,這樣的框架本身的穩定性也還是比較不錯的。近期,映客在做的一件事情就是在目前體量已經非常大的情況下,如何去保證資源的獨占和安全,目前也正在基於雲服務設施進行VPC的部署,而且這項工作目前推進得也還不錯。

雲上架構
其實大家可以看到,映客的整體架構是構建在雲服務基礎設施之上的。目前映客已經達到今天千萬日活這樣的體量還在使用雲服務其實主要基於以下幾個方麵的考慮:首先,我們認為在現階段,雲服務的發展已經相對比較成熟了,並且也是比較安全的,雲服務在內部可以保障一些高可用的支撐;另外,用戶使用的所有服務基本上都是集群化的,並且是支持平滑伸縮的,這些對於有活動運營需求的直播平台而言都是非常有價值的;並且雲服務的用戶也不需要預留太多資源來支撐可伸縮的容量;除此之外,如果使用自建機房,那麼運維團隊需要足夠了解每一個環節,需要能夠支撐從硬件設施到監控以及上線等各個方麵,這對於一個快速迭代的公司的運維團隊而言則是非常困難的,而使用雲服務則可以保障基礎設施的高質量運維。以上這些就是映客直播到目前千萬日活的體量依舊選擇在雲上架構未來的很重要的原因。


三、風口上的數據庫架構變遷
接下來為大家分享映客從0到千萬日活過程中數據庫架構變遷的曆程。談到數據庫,無論是像Oracle、MySQL這樣的關係型數據庫,還是像MongoDB這樣的NoSQL的數據庫,大家想到的第一點就是數據庫的性能。而數據庫主機的性能主要和以下的這幾個方麵相關:CPU、存儲、索引、IO、鎖、內存以及內部的線程模型等,這些都是確保數據庫設計本身性能非常關鍵的方麵。



在數據庫架構演變過程中,無論是MySQL、Redis還是MongoDB這些數據庫層麵的服務都經曆如下圖所示的變化,從單主機的模式到後來獨立主機,到後來的主從讀寫分離,再後來根據用戶、房間、資料等維度進行垂直拆分,而在維度已經很大比如像關係數據已經到達千億量級的時候還進行了水平拆分。

關鍵技術點-數據遷移工具
在數據庫架構演變過程中涉及到一些技術點,在這裏可以與大家分享一下。在數據遷移工具這部分在數據庫架構演變過程一直都扮演者極為重要的角色。對於同構數據的遷移而言,其實有比較成熟的方案,同構數據遷移相當於上圖中的從單主機一直到垂直拆分這部分,這部分由於所涉及到數據表的結構以及數據的拆分策略都沒有什麼變化,所以這部分工作直接依賴雲數據庫的遷移工具,就可以實現數據的平滑遷移,並且業務上基本是無感知的。這部分適用的場景就是服務器級別、實例級別的擴容或者讀寫分離以及業務的垂直拆分等。但是當體量已經足夠大到需要做很多水平層麵的拆分的時候,很多現有的成熟的工具就已經不太適用了。這個過程中,映客直播的技術團隊就基於binlog等日誌層麵的東西開發了自己的一套異構數據遷移中間件,這個中間件比較適用於異構數據庫或者是做分庫分表的遷移。因為在分庫分表的過程中要想做到業務的盡量的無感知還是比較困難的,特別是在一開始是單庫單表,需要分成1000張表,在分完成1000張表之後是很難再回退過去的,這個成本是非常大的。如果在這個過程中異構數據遷移組件做的足夠好,就可以將風險降到很低。

關鍵技術點-分庫分表中間件
第二個關鍵技術點就涉及到訪問分庫分表數據的問題。在實現這部分時,我們也調研了很多業界的方案。目前業界比較成熟的方案主要有兩種,分別是基於Client的和基於Proxy的,映客技術團隊對於這兩種方案在不同的時期也都實現過,但是總的宗旨是實現分庫分表的透明化。首先,對於業務而言,不需要關心SQL到底執行到哪一個庫表上,也不需要關心分庫分表的策略是什麼。第二個就是數據庫本身配置的統一管理,這部分就是對於線上數據的統一切換以及配置都是非常有用的。第三個就是需要提供統一的監控。第四點,既然使用了這個分庫分表中間件,就相當於所有的業務都是依賴於這個中間件的,其高可用設計就是非常關鍵的。另外,分庫分表中間件的設計本身是一個集群模式,所以需要做好中間件和數據庫中間鏈接的管理,通過一些連接池的模型將鏈接更好的管理起來。包括後麵的負載均衡以及更好的擴展能力等都是在實現分庫分表中間件時需要考慮的。

關鍵技術點-分布式事務
第三個關鍵技術點就是分布式事務,在之前可能所有的業務在一個數據庫上通過一個本地事務就可以解決問題。而現在已經按照水平拆分和垂直拆分之後分成了很多個庫表以及很多個維度的模塊,這時候就涉及到了數據一致性的管理。而在這一方麵,從業務層麵來說業務可能處理的比較多的有兩種分布式事務,第一類就是預占資源型,預占資源型就是比如是A要給B送禮或者A給B轉賬的時候,對於A而言需要扣錢,這部分是需要預先將錢扣掉的,然後再給B加上,這個過程對於A而言就是預占資源型。預占資源型有什麼特點呢?其實就是如果想要給B加錢,那麼就一定需要確保A的錢已經被扣掉了,而且這個操作如果在最終沒有成功,那麼對於A而言是非常容易回滾的。相當於預占資源型的分布式事務的要求是實時的、同步的、並且能夠保證可回滾。這一部分現在業界使用的比較多的模型就是基於補償的,也就是tcc的分布式事務框架,這種框架模型也是電商以及金融相關的業務中使用的比較多的。

以上這些就是在實現了數據庫架構演變之後,映客技術團隊在分布式事務這部分所麵臨的問題以及所做的事情。
四、直播典型應用場景分析
任何脫離了實際應用場景的架構都很難說它是一個好的架構,所以還是需要去分析架構的應用場景,根據其應用場景來分析究竟應該選擇什麼樣的架構模型。接下來就與大家分享在直播這個應用場景之下,與數據庫相關的技術點以及如何進行數據庫架構的設計和迭代。
下圖中展現的是一個直播大V,直播大V的特點就是其粉絲會非常多,下圖中的大V有156萬粉絲,而最多的粉絲量可能會達到千萬級別。而粉絲量比較多所帶來的問題就是無論是推送量還是關注度,還是在直播間中的活躍度都會非常高。而且本身而言,大V的直播也會比較頻繁。此時對於平台考驗最大的就是關係係統,所以關係係統必須能夠支撐高並發、大容量,並且對於關係係統的實時性以及一致性的要求也是比較高的。如果A關注了B,而到最後沒有關注成功或者並沒有收到B直播的推送信息,那麼這就是一個故障。所以這對於關係係統的壓力是非常大的,因為任意用戶之間都可以建立相互的關係本身就是笛卡爾積的形式。

通過下圖大家可以看到,在關係係統的主關係服務上有很多異步化的優化。首先,要想實現這些優化需要確保關係服務本身以及關係數據本身是收攏的,有統一的入口。在這之後就可以統一地把控這個入口,然後確保關鍵路徑寫成功,其他非關鍵路徑都可以通過消息隊列分發出去,並組建一些異構的數據源或者不同類型的需要做很多Cache優化、異構數據構建等的工作。

下圖展現的也是映客平台的一個大主播,在日榜中,這個主播一天收獲到了四千多萬的映票,而一個映票相當於一毛錢。每個用戶可以一個小禮物、一個映票地去送,並且可以連送。這樣就會造成這一個問題,因為這四千多萬的映票在一天之內,甚至在一個小時或者半個小時內都送給這個主播,勢必會對於數據庫造成很大的壓力,如果主播的數據在數據庫中僅為一條數據,那麼會涉及到很多次更新操作。所以基於這樣送禮的高並發場景,映客也做了很多層麵的優化,首先支撐送禮這個場景的金融屬性中的強一致性,雖然一個映票隻有一毛錢,禮物的價值雖小但是仍舊是一個金融屬性,如果這一毛錢沒有到主播賬戶上,這將會成為一個金融故障,其影響將會是非常大的。而且粉絲無論在什麼時候送給主播一個映票,都需要看到主播的映票數量是在實時地增長的,如果在短時間內主播的映票數沒有增長,用戶可能就來投訴了,所以在這個場景下對於實時性的要求也是非常高的。除了需要保證金融數據的強一致性以及實時性的前提,還需要保證在多個粉絲同時向主播送禮時的高並發特性,這對於金幣係統的壓力也是非常大的。

映客直播金幣係統
映客的金幣係統在初始時的架構如下圖所示,也是依賴於RDS的MySQL集群,一開始是單主機的,後來進行了獨立實例的優化,在這之後還進行了讀寫的分離,實現了讀寫分離之後其實業務包括送禮、支付和體現還是可以直接操作數據庫的。這個時候即便是金幣數據庫能夠支撐的量再大,穩定性再高,當遇到剛才提到的主播一天收到四千萬映票的情況時,數據庫所產生的延遲也是無法接受的。


送禮邏輯解析
這裏為大家分享一個業務中比較核心的送禮邏輯。之前也提到送禮操作和收禮操作需要分為兩塊,並且每個部分需要采用不同的策略,一種是分庫分表的策略,另外一種是使用異步化的策略來解決。

總結
其實,數據庫本身而言是一個基礎設施。那麼作為基礎設施,我們主要可以依賴數據庫的穩定性以及基本的性能。而雲為數據庫提供了專家級的運維,這一點也是比較好的方麵。但是雲數據庫也不是萬能的,在前麵提到的場景中的很多情況下必須在架構層麵以及具體的業務場景層麵進行具體的架構梳理和優化。在數據庫架構方麵,我們一直都在路上,並且將會一直努力前行。

最後更新:2017-09-02 01:33:51
上一篇:
少時誦詩書所所所所所所所所所所所所
下一篇:
如何避免數據庫“勒索事件”和“從刪庫到跑路”的尷尬
螞蟻區塊鏈團隊資訊簡報20170508-0514
Java常用類庫--StringBuffer:append、insert、reverse、replace、subString、delete、indexOf
殺手SQL- 一條關於 'Not in' SQL 的優化案例
使用CheckBox控件實現全選與全不選
在iOS11中使用Core ML 和TensorFlow對手勢進行智能識別
RHEL (Red Hat Enterprise Linux,紅帽企業級 Linux) 7.3 安裝指南
蘭溪市智慧城管中心:“平安蘭溪”你我共同參與
Cmd IIS 重啟
中文女和程序員的愛情奇遇
gcc如何生成預編譯頭文件(.gch)