天天看點

vivo 雲服務海量資料存儲架構演進與實踐

本文介紹了雲服務業務海量資料存儲架構的演進之路,詳細講解了雲服務業務在面對海量資料存儲時采用的分庫分表的實踐政策,同時介紹了雲服務如何另辟蹊徑,在資料庫資料壓縮上的實踐方案。希望能對有大資料量存儲痛點的業務有所啟發與幫助。

一、寫在開頭

vivo 雲服務提供給使用者備份手機上的聯系人、短信、便簽、書簽等資料的能力,底層存儲采用 MySQL 資料庫進行資料存儲。

随着 vivo 雲服務業務發展,雲服務使用者量增長迅速,存儲在雲端的資料量越來越大,海量資料給後端存儲帶來了巨大的挑戰。雲服務業務這幾年最大的痛點,就是如何解決使用者海量資料的存儲問題。

二、面臨挑戰

2017-2018年,雲服務産品核心名額着重于提升使用者量。雲服務在産品政策上做了重大調整,使用者登入 vivo 賬号後預設開啟雲服務資料同步開關。

此産品政策給雲服務使用者量帶來了爆發式的增長,使用者量從百萬級别直接跳躍至千萬級别,後端存儲的資料量也從百億級别飛躍至千億級别。

為了解決海量資料的存儲問題,雲服務将分庫分表的 4 闆斧:水準分表、垂直分表、水準分庫、垂直分庫,全部進行了實踐。

1、水準分表

荊棘之路 1:浏覽器書簽、便簽單庫單表,單表資料量已過億級怎麼辦?

相信了解過分庫分表知識體系的兄弟很快能夠回答:單表資料量過大那就進行分表。我們也是如此做的,将浏覽器書簽、便簽子產品單表拆分至 100 張表。

将浏覽器書簽、便簽單表億級資料量遷移至 100 張分表裡,每張表承載 1000W 的資料量。

這就是大家熟悉的第一闆斧:水準分表。

vivo 雲服務海量資料存儲架構演進與實踐

2、水準分庫

荊棘之路 2:聯系人、短信資料已分表,但是最初隻分了 50 張表,未進行分庫。使用者量爆發式增長後,單庫聯系人總資料量已到達 幾十億,單表資料量已高達5000W ,繼續增長将嚴重影響mysql性能,怎麼辦?

第二闆斧,水準分庫:1個庫支撐不住,那就多分幾個庫。我們将原來單庫拆分成10個庫,并且将原來單庫聯系人、短信50張表擴充至100張表,同樣期間進行了幾十億存量資料的遷移重路由,十分痛苦。

vivo 雲服務海量資料存儲架構演進與實踐

3、垂直分庫、垂直分表

荊棘之路3:最初雲服務各個子產品的資料存儲都冗雜在一起。

當空間存在瓶頸後,我們對各子產品資料的存儲空間分布進行了分析,情況如下:

單庫磁盤容量5T,聯系人資料占用存儲空間2.75T(55%),短信資料占用存儲空間1T(20%),其他所有子產品資料共占用存儲空間500G(5%),剩餘可用空間1T, 聯系人、短信資料即占用了總空間的75%。

 剩餘1T的空間容量是無法支撐使用者資料的持續增長,情況不容樂觀。若空間不足,所有子產品都會因為空間問題導緻不可用,怎麼辦?

(下圖為雲服務當時的資料存儲空間分布圖)

vivo 雲服務海量資料存儲架構演進與實踐

第三、四闆斧,垂直分庫、垂直分表:我們将聯系人資料、短信資料和其他子產品資料進行存儲解耦。将聯系人資料、短信資料都單獨拆分成庫。

vivo 雲服務海量資料存儲架構演進與實踐

至此,雲服務将分庫分表的 4 闆斧全部實踐了一遍,資料該拆的拆,該分的分。

4、基于路由表的動态擴容方案

荊棘之路4:從上述描述得知拆分出來的聯系人資料庫采用固定10個庫的分庫政策,前期評估10庫*100張表是可以滿足業務資料增長需求的,本以為可以高枕無憂,但是聯系人資料增長速率超出了預期。

聯系人資料庫單獨拆分9個月之後,單個庫的存儲空間從35%增長至65%。按照這個增長速度,再支撐6個月,獨立拆分出來的聯系人資料庫将再次面臨空間不足問題。

如何解決?繼續擴容是肯定的,核心點在于采用哪種擴容政策。如果采用正常的擴容方案,那我們将面臨着海量存量資料的遷移重新路由問題,成本太大。

經過技術組溝通讨論,結合雲服務聯系人業務的自身特性(老使用者的聯系人數量基本上是穩定的,不會頻繁的添加大量的聯系人,老使用者聯系人資料增長的速率可控),我們最終采用了基于路由表的動态擴容方案。

以下介紹下此方案特點:

  • 添加使用者路由表,記錄使用者聯系人資料具體路由在哪個庫,哪張表;
  • 新使用者的聯系人資料會路由到新擴容的資料庫裡,不會對原有老庫造成資料存儲壓力。
  • 老使用者的資料不會動,還是儲存在原來的資料庫。
  • 此方案的特點是保證了原有老庫隻需保證老使用者的資料增長即可,新使用者全部由新擴容的庫來承載。
vivo 雲服務海量資料存儲架構演進與實踐

老使用者聯系人的增長速率雖然可控,但我們期望原老庫能預留60%的存儲空間來支撐老使用者的資料增長。目前老庫隻剩餘35%的可用空間,不符合我們的要求。

為了降低老庫資料占用的存儲空間,自然而然我們想到了從資料壓縮層面着手。

三、壓縮方案預研

雲服務對資料庫資料壓縮進行了以下3種方案的預研:

方案1:程式自行實作資料壓縮,壓縮後再儲存至資料庫

優勢:

無需對資料庫進行任何改造,修改完全由程式自己收斂,可以自由控制需要進行壓縮的字段。

劣勢:

存量資料需要開發額外的壓縮任務進行資料壓縮,且存量資料量級過大,靠程式進行資料壓縮耗時不可控。

資料壓縮入庫後,需要從db平台直接進行select查詢字段的内容不再是可讀的,加大了後續定位問題的難度。

方案2:MySQL 資料庫 InnoDB 自帶的資料壓縮能力

利用 InnoDB 已有的能力進行資料壓縮,對于上層程式無需做任何改造,且不影響後續select資料查詢。
适用于資料量較大,讀多寫少的業務場景,且對要求高查詢性能的業務不太合适。

方案3:切換InnoDB 存儲引擎至TokuDB,利用TokuDB引擎天然的資料壓縮能力

TokuDB天然支援資料壓縮,并且支援多種壓縮算法,支援頻繁的資料寫入場景,對于大資料量的存儲有天然的優勢。
MySQL 需要安裝額外的插件對TokuDB引擎進行支援,且公司目前沒有業務有TokuDB成熟的使用經驗,接入後的風險未知,對後續 DBA 的維護也是一項挑戰。

我們經過綜合考慮,最終決定采用第二種壓縮方案:InnoDB自有的壓縮能力。

主要原因有以下幾點:

  • 操作簡單:由dba更改現有innodb資料表的檔案格式,即可對資料進行壓縮;
  • 壓縮速度可控:經過測試,1張2000W的資料表,通過此方式,1-2天内即可完成整張表的資料壓縮;
  • 改造成本低:整個改造過程隻需要dba執行相關SQL,更改資料表的檔案格式,上層的程式代碼無需做任何改動;
  • 比較适合雲服務的業務場景:使用者資料備份、恢複,都不屬于高性能、高QPS的業務場景,且雲服務的資料表大多符合存在大量字元串字段的特征,非常适合進行資料壓縮。

四、壓縮方案驗證

1、InnoDB 壓縮能力介紹

MySQL 5.1.38 版本之前隻有 innodb-base的存儲引擎,預設檔案格式為Antelope,此檔案格式支援2種行格式(ROW_FORMAT):COMPACT和REDUNDANT,這2種都不是資料壓縮類型的行格式。

MySQL 5.1.38後引入innodb-plugin,同時引入了Barracude類型的檔案格式。Barracude完全相容Antelope的檔案格式,同時支援另外2種行格式DYNAMIC、COMPRESSED(支援資料壓縮)。

vivo 雲服務海量資料存儲架構演進與實踐

2、壓縮環境準備

修改資料庫配置:更改資料庫的檔案格式,預設為Antelope ,修改為Barracuda

SET GLOBAL innodb_file_format=Barracuda;

SET GLOBAL innodb_file_format_max=Barracuda;

SET GLOBAL innodb_file_per_table=1

說明:innodb_file_per_table必須設定為1。原因是在InnoDB系統表空間是無法進行壓縮的。系統表空間不僅包含使用者資料,還包含 InnoDB 内部系統資訊,永遠不能被壓縮,是以需要設定不同表不同的表空間來支援壓縮。

設定OK後可以執行SHOW GLOBAL VARIABLES LIKE ‘%file_format%’及SHOW GLOBAL VARIABLES LIKE ‘%file_per%’确認修改是否生效。

vivo 雲服務海量資料存儲架構演進與實踐

(此種設定方式隻對目前會話生效,mysql執行個體重新開機後會失效。若需要永久生效,請在mysql全局配置檔案裡配置)

3、壓縮效果測試驗證

準備1張支援壓縮格式的資料表,1張不支援壓縮的資料表,字段格式全部一樣。

壓縮表:

vivo 雲服務海量資料存儲架構演進與實踐

說明:row_format=compressed,指定行格式為compressed。推薦key_block_size=8。key_block_size預設為16,可選值有16、8、4代表的是 InnoDB 資料頁大小,值越小壓縮力度越大。基于CPU、壓縮率綜合考慮,線上推薦設定為8。

非壓縮表:

vivo 雲服務海量資料存儲架構演進與實踐

準備資料:使用存儲過程同時向t_nocompress表和t_compress表插入10W條相同的資料。2張表占用空間大小如下圖:

vivo 雲服務海量資料存儲架構演進與實踐

t_compress表資料占用10M,t_nocompress表資料占用20M,壓縮率50%。

說明:壓縮效果取決于表的字段的類型,典型資料通常具有重複值,是以能夠有效壓縮。CHAR,VARCHAR,TEXT、BLOB這類。

字元串類型的資料通常能夠很好地壓縮。而二進制資料(整數或浮點數字)、已經經過壓縮的資料(JPEG 或 PNG 圖像)通常起不到壓縮效果。

五、線上實踐

從上述測試驗證來看,壓縮率若能達到50%,那麼聯系人老庫占用空間從65%壓縮至33%,預留60%的剩餘空間是能夠達成的。

但是對線上的資料我們需要保持敬畏之心,線上實踐之前,需要線下先進行方案驗證,同時我們還需要考慮以下問題:

1、資料壓縮,解壓操作是否對db伺服器的性能造成影響?

我們采用性能壓測的方式來評估壓縮前後對資料庫伺服器CPU的影響。以下是壓縮前後db伺服器的CPU對比圖:

聯系人單表資料量已有2000W的前提下,對此表進行資料插入。

壓縮前:一次性插入50個聯系人,并發量200,持續10分鐘 ,TPS 150,CPU33%

vivo 雲服務海量資料存儲架構演進與實踐

壓縮後:一次性插入50個聯系人,并發量200,持續10分鐘,TPS 140,CPU43%

vivo 雲服務海量資料存儲架構演進與實踐

資料表壓縮後,頻繁資料插入資料庫CPU确實會增高,但是TPS未受太大影響。經過反複壓測,資料庫伺服器CPU基本穩定在40%左右,是業務可以接受的範圍。

2、變更資料表檔案格式是否會對業務SQL讀寫造成影響,影響正常的業務功能?

我們主要做了線下驗證和線上驗證:

線下驗證:測試環境将聯系人資料表全部調整為壓縮格式,安排測試工程師協助點檢了聯系人的全量功能,最終功能全部正常。

預上線環境按照測試環境的步驟再走一遍,功能點檢無異常。

線上驗證:選取對于使用者不敏感的通話記錄子產品的資料表進行壓縮,選擇壓縮1個庫裡的1張表,關注此張表的資料讀寫情況,留意使用者投訴。

持續觀察了1周後,此張表的通話記錄資料能正常進行讀寫,期間未收到任何使用者的異常回報。

3、線上聯系人聯系人資料量龐大,怎麼保障壓縮時服務的穩定?

我們主要是按照以下思路來進行權衡:

  • 選取1張聯系人資料表進行壓縮,評估單張表花費的時間。
  • 選擇單庫,進行多表并發壓縮,觀察CPU占用情況。DBA權衡CPU最高值不能超過55%,以這個标準逐漸調整壓縮并發數,保證CPU穩定在55%左右,最終得到單庫最多支援多少張表同時進行壓縮。
  • 結合第一步和第二步我們可以計算出所有庫全部資料表壓縮完畢大緻花費的時間,同步至項目組及相關責任人後,按照步驟實施壓縮工作即可。

最終線上聯系人資料庫進行資料壓縮的效果如下:

vivo 雲服務海量資料存儲架構演進與實踐

六、寫在最後

本文介紹了雲服務随着業務發展,海量資料存儲所帶來的挑戰,以及雲服務在分庫分表、資料庫資料壓縮上的一些經驗,希望能提供借鑒意義。

InnoDB 資料壓縮适用于以下場景:

  • 業務資料量較大,且資料庫磁盤有空間壓力的業務;
  • 适用于讀多寫少的業務場景,對性能、QPS有高要求的業務不太适用;
  • 适用于業務資料表結構中存在大量字元串類型的資料,這種類型的資料表通常能夠進行有效的壓縮。

最後:

  • 業務在分庫分表選型時,一定要做好資料量增長的充分預估,後續資料庫擴容帶來的資料遷移工作會傷筋動骨。
  • 對線上資料要保持敬畏之心,方案一定是經過線下反複驗證之後才能應用到線上。
作者:vivo 平台産品開發團隊

分享 vivo 網際網路技術幹貨與沙龍活動,推薦最新行業動态與熱門會議。

繼續閱讀