天天看點

Cassandra 在 360 的實踐與改進

供寬表資料庫選型參考

11月16日在北京,由DataFun和阿裡雲聯合舉辦的首場Cassandra中文社群線下meetup,奇虎360王鋒老師分享了在360的應用,針對HBase和C的選型,C的優缺點及改進方案做了分享,最多時達一萬四千節點,值得細細品讀。

以下文章來源于DataFunTalk ,作者王鋒

導讀:2010年,Dropbox 線上雲存儲在國外被使用者熟知,同時國内如360、金山、百度等各個廠商也都陸續推出了自家的網盤類産品;而在 "360雲盤" 背後的存儲技術支撐之一就是以 Cassandra 為基礎的雲端存儲方案。自此,Cassandra 在360實作技術落地和大規模生産應用,并被持續改進優化,最終形成高峰時期超 10k+ 實體節點的使用規模,成為網際網路公司中 Cassandra 生産環境落地規模最大的公司。

本次分享的主要内容是 Cassandra 在360的落地實踐過程中遇到的問題,以及一些重要的改進和優化,主要包括:

  • Cassandra 的特點簡介
  • Cassandra 在360的選型
  • Cassandra 在360的應用場景
  • Cassandra 在360的技術演進

——Cassandra 的特點簡介——

Cassandra 大緻有以下的特點:

Cassandra 完全無中心化設計使得其具備極高的可用性和可平滑的拓展性,并且具有模式靈活,多資料中心,範圍查詢,清單資料結構,分布式寫操作等優勢:

❶ 由于其架構在中小規模部署時不需要主節點,相較于完全中心化的分布式存儲設計具有更優的成本優勢,從3台實體機開始一直拓展到幾百台實體機,均可完全不停服情況下平滑拓展,整個過程隻需要把拓展節點的程序啟動加入叢集;

❷ 模式靈活使得 Cassandra 可以在系統運作時随意添加或移除字段,這是一個很驚人的效率提升,特别是在大型部署上;

❸ 多資料中心是指可以調整節點布局來避免某一個資料中心失效,一個備用的資料中心将至少有每條記錄的完全複制;

❹ 範圍查詢是指如果你不喜歡全部的鍵值查詢,則可以設定鍵的範圍來查詢,對于每個使用者的索引,這是非常友善的;

❺ 分布式寫操作是指有可以在任何地方任何時間集中讀或寫任何資料,并且不會有任何單點失敗。

除了以上幾點,Cassandra 還有如下的優點:

❶ 海量資料,随時線上,分布式資料庫,性能極優

❷ always online,無中心,無單點故障引發抖動

❸ 節點對等,配置一緻,線性擴充,易于維護

❹ cql/sdk 能力,易用性好,開發者 & DBA 快速上手

❺ 功能強大,主要有以下幾點功能,多 DC 兩地三中心,線上更改 schema,豐富資料結構,豐富的索引,監控及工具。

——Cassandra 在360的選型——

選型之始,我們總結評估了雲存儲的技術需求特征和當時可承載大規模資料的分布式 K-V 資料庫——Cassandra 和 HBase,最終權衡之後,使用 Cassandra 做為主要線上存儲。對于 "網盤/雲盤" 類産品,其主要流量特征為 "寫多讀少",要求服務可靠性和資料安全性極高,基本不可容忍服務中斷和資料丢失的情況。具體選型分析如下:

❶ Cassandra 相較于 HBase,前者是完全無中心設計,而後者 ( 包括依賴的 HDFS ) 整體來看是強中心化設計,是以 Cassandra 與生俱來不存在關鍵單點故障影響服務的問題;

❷ Cassandra 使用最終一緻性政策,而非 HBase 的強一緻性政策,配合讀寫政策的處理,Cassandra 可以在確定資料安全性、可靠性、一緻性的前提下,出現節點當機而不需要恢複時間,叢集讀寫不産生任何停頓,而此場景下,HBase 需要等待 region 重新配置設定過程,而這個過程大概會有數秒至數分鐘的待配置設定 region 不可讀寫;

❸ 從技術細節上,雖然二者均采用了 LSM 的架構,但 Cassandra 直接操作本地磁盤,而 HBase 需要依賴 HDFS 共享存儲,加之上述所說的架構設計差異,同等基礎設施性能的 Cassandra 寫入性能優于 HBase 近乎一個數量級,讀性能基本持平。

綜上所述,Cassandra 可以更好的适用于雲盤線上場景。

——Cassandra 在360的應用場景——

Cassandra 在 360 的實踐與改進

基于360雲盤使用 Cassandra,雲盤從15台機器一直到14000+台機器,應用場景主要是個人資料,自己産品中間的圖檔,内部視訊對象等;在2015年,360雲盤轉型為企業雲盤,機器數量就下降了,到2018年,智彙雲又繼續前行,目前機器差不多是3000左右的規模,以上是360的應用場景。

——Cassandra 在360的技術演進——

Cassandra 自2010在360開始調研技術落地;2011年使用 Cassandra 0.7.3作為基礎版本應用于生産環境;2012年完善資料可靠性和安全性,實作不停機和不單純依賴讀修複的資料快速恢複;2013-2014年以節省成本為目的,實作可擦除編碼技術應用于 Cassandra,在確定資料安全和可靠性的前提下實作成本降低60%;2014-2015年面對超大規模叢集的超複雜性問題,實作運維自動化,叢集具備自主自愈、自主風控等自主運維能力 ( 近 1w5 實體節點,89個叢集,兩人運維 );2018年,我們發現 Cassandra 社群版本與360版本相當于是不同場景殊途同歸 ( 社群為輕 Value,360為重 Value ),并且社群很多好的思路非常值得考慮,是以我們重新調整研發政策,與社群共同成長。

Cassandra 是一種無中心的系統,對于消息的廣播,有一些規模的限制,基本單節點到600台的時候就差不多了,當時雲盤的叢集規模,單叢集是600台,Cassandra 叢集規模達到了88個,磁盤使用率達到了90%,主要是為了成本考慮,把磁盤使用率達到了90%。這其中用的是預先劃分 range,畢竟當時沒有 VNode,使用預先劃分首先是使用 RandomPartitioner,使用例如 hash,md5 讓資料随機打到環上,這個是使用最多的;還有一種是 OrdePerservingPartitinoer,這是一種保序的方式,把一些 key 保序的存在環上,檔案 I/O 使用的 standard 跟 Mmapped,Mmapped 理論上是減少記憶體拷貝,對性能很好,但是如果資料量漲到80%到90%的時候,Linux 核心頁表的開銷占用量很大,是以最後放棄了 Mmapped 的方式,使用了 standard 的方式。

對于 Cassandra 的改進,第一個就是進行可靠性的改進,使用 Local Repair 跟 Backup。影響資料可靠性的因素有:

❶ One/Quorum 存在新增副本不足的問題;

❷ 磁盤/扇區故障:檔案損壞、資料丢失 ( 月均故障25-30塊 );

❸ 現有資料恢複機制存在不完善之處。

因素 ❶ 是第三副本是否可以成功寫入的問題,使用非 ALL 政策寫入 Cassandra 時,隻要滿足寫入政策即傳回成功,例如 quorum 級别寫入3副本資料,當兩個節點寫入成功即傳回寫入成功,雖然原始設計為了保障第三副本寫入成功使用 hintedhandoff 機制來保證,但程式設計最多能支撐3小時的時間,雖然該項可配但也受限于接入節點的存儲容量,是以360針對此問題做了優化,研發 proxycheck 功能将未成功寫入打散到全叢集,當故障節點恢複時,基于 proxycheck 會修複殘缺副本;

因素 ❷ 是磁盤故障,雖然小規模磁盤很少見磁盤損壞,但對于極大規模的存儲系統來說,磁盤故障就變得不可忽略了,而 Cassandra 的架構又決定了如果磁盤損壞造成了副本殘缺很難發現,隻能等待讀修複觸發或者 repair 工具修複,但對長時間不讀取的冷資料很顯然存在較大資料風險;

因素 ❸ 是修複機制,無論是因素 ❷ 導緻的還是其他問題造成的資料殘缺都需要恢複機制盡快恢複資料,但 Cassandra 讀修複對冷資料不友好,repair 工具會耗盡整個叢集的資源,對于這些挑戰,除了讀修複,我們實作了一套相當于 RowRepair 的機制。

首先來說一下檔案/磁盤的自動摘除, 存在的問題主要有兩點,一點是讀寫異常,SEEKIOException 影響正常讀寫,另外一點是各種修複機制,Compact 機制執行失效,針對以上的兩點問題,主要采用了基于檔案異常通路次數的統計,摘除故障檔案資料比重,外部發現基于 SmartCtl 規則回報,将以上的問題回報到系統中,就可以精确的知道哪塊磁盤有哪些問題。

修複磁盤故障摘除,此處針對的是全量資料的磁盤故障摘除,使用全盤資料掃描恢複的目的主要有兩點,一是用來解決全量檔案,因磁盤故障/檔案損壞等原因帶來的副本不足的情況,二是檔案/目錄/磁盤摘除,觸發背景主動副本修複。全盤資料掃描修複,從 Range 的開始,三個節點都讀資料,如果資料存在沖突,就使用另外兩個節點去解決資料沖突,最後把資料恢複。每個節點都會附一個 range,range 的主要作用就是從三個節點上把資料取過來進行比對,然後把解決沖突的資料恢複掉,另外一種方式使用 KeyScan+Read-All,使用 KeyScan 拿到的是一些 key,對于大量的插入,像雲盤使用者是大量的插入比較多,删除的操作很少,這種場景下資料存儲使用的是 key-value 的資料格式存儲,這種情況下,如果節點上丢掉了哪些資料,可以直接使用 key 來修複這些丢掉的資料。通過這兩種方式可以解決檔案丢失或者損壞的問題。

解決了全量資料,接着解決增量資料的檢查修複問題。增量資料檢查修複主要存在以下三個問題:

❶ 如何保證新寫入的資料副本是足夠的 ( 拒絕/逾時 )

❷ 如何彌補 Hinted handoff 的缺點 ( 時間視窗 )

❸ Quorum 寫存在 W

針對以上問題,Hinted handoff 對于 i/o 負載或者 i/o 假死沒有考慮到,這種情況下,Hintedhandoff 沒有去把出問題的東西記下來,時間視窗存在的問題是如果逾時了,丢失的資料可能就記錄不下來,是以需要把這兩種情況記錄下來,以便更好的解決增量資料存在的問題。其原理是:如果提供兩種方式,第一種如果 proxycheck 把 value 記錄進來以後,資料有問題,可以直接使用另外的副本進行資料修複,還有一種如果不記錄的話,可以使用 all 級别讀修複來對資料進行恢複。使用 Proxy 節點負責記錄副本不全的 row,逾時拒絕導緻的三個副本可能隻寫成功了兩個,這種情況也需要記錄下來,這種情況下,實時的去做資料的恢複或者副本的補全,使用 proxycheck 表來存儲輔助的 Keyspace,把所有檢測到的副本不足的資料都記錄到這張表中,Proxy 節點還用于記錄資料的修複,把資料存儲,proxycheck 用了兩副本,這樣做會加大系統的開銷,但是資料的可靠性得到保證。

Cassandra 在 360 的實踐與改進

資料的恢複,涉及到存儲,同時,還需要用到資料的備份。當時沒有所謂的多 DC 方式,都是自研的備份系統,當時 Cassandra 的叢集數量有88個,如果采用 Cassandra+Cassandra 的主備模式,那将又是88個叢集,這是對運維和成本的巨大挑戰;是以我們選擇了在極大規模場景下擴充更好的 HBase 作為備份存儲,使用 Cassandra ( 主 ) +HBase ( 備 ) 方案,這樣全球88個叢集資料備份集中至四大備份中心。大量的資料備份,經常使用的方式就是消息隊列,資料的彙聚會增加運維的成本以及資料的落地然後再去做,這樣操作的話,延時會比較高。是以在 Cassandra 中做了一個機制,每個節點負責自己的 range 管理,可以記錄到自己的緩存表中,從緩沖表取出來備份到資料中心,使用 Thirft 接口,HBase 跟 Cassandra 的接口完全是相容的,這樣設計 HBase 備份中心就相當于一個 Cassandra 的資料中心了,如果資料大量丢失,或者資料出現大量的錯誤問題,可以直接無縫切換到 HBase 上提供服務,然後再使用 HBase 備份的資料慢慢恢複丢失的資料,使用者完全不會感覺到服務異常,提高了使用者的體驗。

Cassandra 在 360 的實踐與改進

前面介紹的是資料方面的問題,下面介紹下如何提高磁盤的使用率也就是降低成本。主要是利用虛拟目錄來提高磁盤的使用率,磁盤的使用率提高主要問題存在兩點:

❶ 節點數量大,SSTable 檔案多,磁盤空間導緻無法做 major 消重;

❷ SSTable 檔案數多,Scan 操作導緻 CPU 消耗嚴重。

對于這兩個問題,當時磁盤的使用率達到50%就無法再提高使用率,繼而我們采用了分而治之的思想,把一個大 range 使用 Daily—Compact 完成資料 SubRange,切分為幾個小 range,每個 range 代表一個目錄,由于切分以後,資料量變小,每個 range 都可以做自己的 major,可以把重複的部分都清除掉 ( 但是如果在磁盤使用率90%以上,做一次 major 就很消耗 CPU 性能 ) ,這樣做以後,對于 Scan 請求定位 SSTable 打開的檔案會更少,效率就會更高,速度也會更快。

Cassandra 在 360 的實踐與改進

避免寫放大的問題。對于如何減少寫放大問題,主要存在以下兩個問題:

❶ 原有的 Compaction 機制 ( SizeTiered/Leveled ) 較難避免資料重複參與 Compaction 的問題;

❷ 尤其在 SizeTiered 按檔案大小分組 Compaction,插入删除頻繁的業務難以消重。

針對上述問題,我們采用給 SSTable 增加 level 概念。正常的是給每層的資料從 level 0 -> level 2,到 level 2 後,compaction 就不會參加,也就說最多做兩次。360對于這一塊做了如下的改進:讓每層的 compaction 結合虛拟目錄,在 level 0 做 compaction 的時候,分成各種各樣的虛拟目錄進行 subrange,subrange 裡邊再去做 compaction,這樣的話,就相當于虛拟目錄沒有重複的資料出現,控制檔案參與 compaction 的次數,通過這兩種方式,使磁盤的使用率達到了90%左右。

Cassandra 在 360 的實踐與改進

成本壓力。基于成本的考量,使用了 EC 的方式,讓3副本變成了1.4個副本,在較少副本數量的同時保證資料的可靠性,同時從資料可用性上考慮的話,資料可用性基本保持以下兩點就可以:

❶ 副本方式,也就是連續3節點磁盤故障,資料必丢失;

❷ 條帶方式,相鄰的14節點故障任意4個資料仍可修複。

對于這個内容,EC 是把原有的資料進行塊切分,算出校驗塊,然後校驗塊打散到整個叢集中,如果丢失了幾個塊,可以用其他的10個塊進行修複,再把分散的塊 key 存儲到 cfindex 的表中。對于前邊的條帶方式,主要使用切分 value,value 采用的是 512k 切成等份的4等份,可以得到4個校驗塊,需要全部打散到不同的資料塊上,比如下圖中的 k13,k14 不能放到一台機器上,這樣才有意義,一旦資料丢失了,還可以友善恢複,如果四個塊在一台機器上,壞了兩台機器就沒法恢複了,key 的資料有兩部分,一個是中繼資料,一個是條帶資料。中繼資料還是保持多副本的形式,但是算出來的條帶資料實際上是按環分布,分成單副本的方式去存儲,這樣其實就可以達到三副本到1.4副本,編碼可以線上調整,還可以使用指令集加速,通過指令集對 EC 進行加速,這塊比較難的問題是如何把 Key 值分散在整個環上,而且還在不同的機器上,如果使用 Md5 算出來 value 值當作 key 值,還是有可能 Key 值存儲在一台機器上,是以還是采用了 OrderPreservingPartitioner 保序的方式去存儲。

Cassandra 在 360 的實踐與改進

接着做了一個 Keyspace 級别的 Patition 政策,以前的 key 存在以下問題:

❶ RandomPartition 可以解決大部分 Key 随機分布的問題;

❷ key 存儲有序問題,OrderPreservingPartitioner;

❸ 是條帶資料散布的需要,Keyspace 級别的 Partitioner 設定。

前面說 key 存儲用到了 OrderPreservingPartitioner,這樣在一套系統裡需要兩套不同的 partition 機制,如果進行資料互動,就需要既要保持 RandomPartition 的結構,還要保持 OrderPreservingPartitioner 的結構。這樣的話,資料交換會變的異常的複雜,是以做了一個消息傳遞,過程中還是使用 LongToken 去存,在使用時,還是需要維護兩套,當撤出或者加入環中時,都要進行轉化,是以系統會看到兩套内容。

Cassandra 在 360 的實踐與改進

其他的改進點如下:

❶ Hinted handoff :外部工具,解決當機時間過長,超過 Hinted 時間視窗;

❷ MemTable Flush 選盤政策:避免并發 dump MemTable 帶來的 CPU 開銷,避免小檔案的産生;

❸ Cassandra 叢集管控,配置自動加載,磁盤自動下線報修。