郭超:阿里雲Cassandra背後的故事

DataStax發表於2020-08-03

大家好,我是阿里雲資料庫產品事業部的玄陵,真名郭超。

本次的分享大概分三個部分:Cassandra雲資料庫簡介、Cassandra雲資料庫特性以及Q&A。

我們先了解一下Cassandra雲資料庫在阿里雲上的部署和架構。首先這個架構主要反映了三個方向:​

  • 安全保障和VPC隔離:在阿里雲上,Cassandra資料庫的不同使用者有不同的VPC。通過VPC隔離和白名單,可以保證在阿里雲上使用者之間的資料是相對安全的。因為每個使用者有自己的VPC環境,在自己的VPC環境下只能訪問自己的VPC資料。不同的VPC之間是不可以互相訪問與之無關的VPC賬號的資料的。在同VPC下,可以實現單DC或多DC容災的部署。
  • 高可用:阿里雲上Cassandra的高可用性分為單DC之內replica級別的高可用以及DC之間容災的高可用。
  • 功能豐富:具有備份和遷移等功能。每個VPC環境下的使用者的叢集可以通過我們自己實現的系統備份到OSS上面。阿里雲OSS可以提供極致的資料可靠性的服務。

接下來我們深入瞭解一下單個DC和叢集的情況。

  • 運維自動化可以提供自主運維。我們自己實現的Cassandra-mate的服務可以實現一些運維的自動化,比如compaction的調優、節點擴容和增加節點、以及監控和報警。
  • 為了追求高效能,我們在核心定製以及效能增強方面做了一些相關的改進。
  • 靈活易用,我們的雲服務是百分百相容Apache Cassandra CQL的協議。

除此之外,我們其它的架構和Apache Cassandra幾乎是一樣的。

接下來我們介紹一下Cassandra雲資料庫的特性:

  • 開箱即用:免除運維煩惱
  • 彈性伸縮、線性擴充套件:在雲環境下,利用雲的資源可以進行快速的擴容和縮容,這點非常符合Cassandra現有的特性。
  • 高可用、多活:多副本、持續可寫、就近讀取,這個是Cassandra自帶的。
  • 備份恢復:在Cassandra的基礎上我們做了一些配置,比如全量和增量備份和恢復,從而保證相當高的資料可靠性,以防DBA的誤操作(比如刪庫)造成資料不可用。
  • 細粒度監控:能讓效能資料一目瞭然。

即將上線的服務包括:

  • 安全加固:SSL+TDE全鏈路加密
  • 審計日誌:訪問記錄、有據可查
  • CloudDBA:自動診斷、智慧優化

接下來,我們介紹一些我們在功能上做的優化。由於時間關係,我們只能重點介紹一部分功能優化。

第一點,我們做了一些自動化運維手段。

這個事情的背景是由於Cassandra是一個去中心化的資料庫,社群建議使用者做repair,目的主要是保證Cassandra三個或多個副本之間的一致性。Repair能夠把副本上的資料做一個修復或者補齊,保證副本的資料是一致的。Repair是必須要做的,然而在我們的使用場景中,repair會引入一些問題:

  • 擴容縮容會增加運維難度:在目前阿里雲的部署環境下,一個使用者對應一個或多個cluster,當使用者增多,需要管理的叢集規模或數量就非常多,這會給我們repair的運維帶來比較大的困難。
  • 當某個叢集擴容或縮容時,我們需要對repair做一些相應的調整,這也會增大運維的難度。Repair的過程會產生極大的資源開銷,會影響我們線上的一些服務。
  • Repair是一個同步過程,當資料量很大或副本之間資料差異很多時,repair耗時較多。Repair時間越久,就越容易出現意想不到的問題。

 

在介紹我們的改進措施之前,我先來大概介紹一下repair的機制:在圖中我們可以看到三個副本ABC,第一步repair會在三個副本上構建全量的Merkle Tree,第二步會比較ABC副本的Merkle Tree之間資料的差異,第三步再通過一個類似於Steaming的過程把資料補齊。

 

我們改進的目的是什麼呢?

我們希望我們repair的過程是自動化的,不需要引入人工干預。這樣當我們雲上的叢集越來越多或者使用者擴容縮容的時候,我們不需要人工的干預,這樣可以降低雲上運維的複雜性,大大釋放了人力資源。第二個目的是希望整個repair的過程是一個開銷較小的過程,這樣可以保證repair對線上服務的影響很小。

那麼我們repair的大概原理是這樣的:我們可以在圖上看到ABC三個副本,每個副本節點上都會有一個primary range主範圍。我們會把primary range切分成很小的組。每個node只會負責修復自己primary range的資料,它不會去管別的資料。比如說B這個節點,它有一個primary range是A到B,除此之外它也會有C到A的副本資料,但是這個部分節點B不管,它只管A到B的資料的修復。這樣會降低我們修復的資料量。

 

節點B只管A到B的primary range,我們會把primary range切分成很小的段,這個部分是為了我們後面做斷點續傳。我們會針對每一個sub_range做修復。這個服務是在Cassandra的kernel裡面,它是一個獨立的修復模組。當Cassandra程式啟動後,這個服務會首先會將primary range切分成sub_range。每一個sub_range會有一個自己的task,然後這些task會進行排列。這之後,我們會對所有的sub_ range從開頭到結尾進行輪詢scan。每次scan會把sub_range裡的資料拿出來,現在我們設定的是每一次拿10條資料。我們獨立實現的repair的module的讀寫鏈路和正常的讀寫鏈路是分開的,這樣的好處是repair不會影響正常的讀寫鏈路。

除此之外,官方建議,一輪repair應該在gc_grace_seconds範圍之內做完。那麼我們可以通過流控控制每一個primary range修復的時間,也可以控制每一次服務對線上的影響。每一個sub-range做完之後,我們會在一個system表裡面做記錄。比如當我們修復到B節點的sub_range2時出現問題了,下一次B節點再啟動時會通過system表斷點續傳到sub_range2,然後sub_range2繼續完成任務。這樣做的好處是很多過程可以完全自動化,獨立的修復鏈路不會影響正常的讀寫鏈路,除此之外還可以降低對線上服務的影響以及有一個可控的修復時間。

接下來我們就效能增強方面選一個點進行詳細介紹。

我們的效能增強基於我們阿里雲的部署形態,我們的底層使用的是盤古提供的塊儲存裝置。我們可以看到Cassandra原有的架構是上面是LSM,底下是我們現在用的Ext4檔案系統,然後是一些作業系統的處理(比如Logical Volume和Volume Group),最終落到下面是有一個單獨的disk放commitlog,其他的disk會放sstable。這樣的部署模式會引入一些問題:

  • ​我們看到寫入鏈是先寫入commitlog,再寫入memtable,然後再返回給客戶。那麼當我們把一個commitlog部署在Cloud Disk 1上面,它的寫入吞吐會受到Cloud Disk 1的限制。另外commitlog現在在社群也是不支援部署在多盤上面的。
  • ​第二個點是在我們這個雲上面涉及到產品形態的設計。首先,commitlog這個盤對我們不會產生費用,我們只售賣sstable的檔案儲存。那麼如果這樣去設計的話,額外的commitlog儲存會產生額外的費用,繼而產生對客戶的額外費用,這樣對客戶來說相對不太公平。
  • ​第三,如果我們有四塊盤,我們拿出一塊盤給commitlog,其它的給sstable,這樣的資源利用也是不公平的。

那麼我們的優化方式就是把底層通過LVM條帶,可以把下層的cloud disk1-4 bind起來。這樣當從上層寫入時,不論是sstable還是commitlog,都可以充分利用四塊盤的資源,而不是隻有disk 1寫commitlog,其它disk 2、3、4寫sstable。我們是把四塊盤的併發能力全用起來。當寫入一個commitlog,它不只是被寫入disk 1。通過LVM條帶,commitlog和sstable會被分成chunk,併發地寫入disk 1、2、3、4。

 

這樣的好處一是可以利用LVM的條帶化和多盤的並行能力提高寫入效能。現在我們的寫入效能比之前提高了20%以上,這是一個平均數,比較極致的提高會更多。第二,我們的四塊盤既可以提供commitlog也可以提供sstable,我們就不需要額外的一塊盤放commitlog,這樣的價效比是最高的。另外,假設我們四塊盤加起來的容量是80個G,它們對應的IOPS和一塊80個G盤的IOPS是一樣的,但是前者的價格會比後者低。通過這個方式,我們可以把整個Cassandra產品的價格降低。第三,我們底層所用的盤古可以提供比較極致的資料可靠性(9個9)。我們可以利用盤古的資料可靠性和LVM的條帶化保證資料節點的資料可靠性,因為如果單塊盤的資料可靠性不高時,LVM條帶化是用不起來的。

除此之外,我們做了一些功能性的增強。

第一,我們支援全量和增量的備份恢復。原有的Cassandra並沒有一個機制可以把增量的備份恢復做到同一的系統裡面。我們現在能做到的是,假設原叢集是三個節點,我們可以恢復到對應的三個節點。我們現在在雲上的宗旨是恢復到對等節點。

我們的備份和恢復分為兩部分:全量的備份恢復和增量的備份恢復。

首先我們在圖上有snapshot這個點,我們會對各個節點併發地做snapshot,做完snapshot我們會有一個全量的sstable。在打完snapshot這個時間點以後,我們會開始做增量的備份。增量的備份我們分兩部分:一是incremental backup是社群已有的功能,我們在此基礎上做了一個表級別的備份恢復的點。除此之外,我們還做了一個增量commitlog的資料備份恢復。

可能有的使用者會問,增量的incremental backup和commitlog的資料其實是有重疊的,我們後面會對此做一些介紹,解釋我們為什麼這樣做。

我們通過snapshot打完全量的快照以後,把每個節點的資料備份到阿里雲的oss上面去。當使用者選擇恢復的時候,我們會對使用者所有的sstable做對等拓撲的恢復,每個節點的token範圍也是對等對映的。這樣做的好處是可以不通過sstableloader的方式把sstable load進去,這樣恢復的速度是最快的。我們只需要做一個對等拷貝,然後做一個單節點的nodetool refresh就可以了。

增量我們通過incremental backup及WAL log online archive來做。我們在雲上做了這樣的一個優化:每次從memtable flush下來的sstable會通過incremental backup產生hard link到對應的backups目錄,同時擴容節點的時候,streaming生成的SSTable也會產生hard link。我們會把hard link對應的SSTable也備份。

 

除此之外,我們利用了Cassandra原有的archive功能,把每個節點寫入的WAL log也做一個備份。當每個commitlog生成的時候,它都會把一個hard link到使用者指定的地方。因為archive是需要重啟叢集和節點的,我們在這裡做的一個優化使之無需重啟。我們做了一個線上歸檔的功能,只要使用者點選某個命令,開啟incremental backup log的歸檔,我們會有對應的程式把log收到OSS上面去。因為我們的備份恢復是對等拓撲的,節點在恢復的時候都會對應到與它相關的token的節點上去。它恢復的時候可以做本節點的nodetool flush以及本節點的commitlog replay,並且這個replay是online replay。

 

這樣的好處是備份恢復的時間是最短的。Incremental backup和commitlog的組合可以讓恢復的時間是最短的,因為我們通過incremental backup的sstable篩選出需要恢復的WAL log/commitlog,然後做一個歸檔。這樣的話可以避免log的replay的時間越來越多。

接下來我會介紹一下我們的資料遷移。

Cassandra原有的資料遷移分為COPY TO/FROM命令和檔案級別的sstableloader兩種。COPY TO/FROM是一個多執行緒讀寫key value的操作,當資料量比較大時,它的速度會比較慢。就sstableloader來說,O1、O2、O3節點上的資料都需要被load,load到新的叢集時可能會有一些冗餘。另外實時新增的資料可能處理得不會很融洽。

在這裡,我們啟動了阿里雲的BDS服務。無論原叢集和目標叢集是對等或不對等拓撲,它們都可以通過BDS高效遷移。

原有的sstableloader方案中,原叢集所有節點都需要進行一個類似於streaming的過程,並在目標叢集進行一個拖資料的過程。原叢集中節點o1的檔案可能和目標叢集中的節點n1、n2、n3都會有重疊。原叢集o1中的檔案複製到目標叢集可能要有一個三副本的放大。當原叢集有三個副本,目標叢集也三個副本時,一份資料通過sstableloader可能會有九倍的放大。這會產生冗餘。

當使用BDS,我們把原叢集和目標叢集做了資料範圍的對映。原叢集的primary range的資料我們只會遷移到目標叢集的primary range,副本節點的資料會遷移到副本節點。我們的副本擺放策略預設使用SimpleStrategy,根據這個副本擺放策略我們做一個副本範圍的一一對映。當某個sstable在目標叢集上橫跨了多個節點時,我們會對於這個sstable做一個切分,切分後需要把對應的資料複製到對應的節點上面去。這樣可以避免資料的冗餘。

除此之外,我們還做了檔案級別的遷移,速度比較快。另外我們也支援增量資料的遷移,包括增量的commitlog和incremental backup。我們支援實時的增量資料的遷移需求,使用者只需要通過我們的BDS服務,無需額外操作即可完成無縫遷移。

最後,我來介紹一下我們監控報警的大概模式。我們會分三個層面來介紹。

首先是OS作業系統層面。

因為Cassandra是share-nothing的架構,它是直接寫本地的檔案系統。對於本地的檔案系統的error我們會做實時探測,對網路包package的異常處理我們也會做監控。在這裡像file system error這樣的相對比較重要的error,我們會通過unavailable這樣的異常報給Ops服務。我們也會對Cassandra的daemon death進行實時監控,在Cassandra每一個程式的機制下面,我們都會有個單獨的agent來發出system error,包括網路和記憶體的異常。另外Cassandra daemon的判活還有gc。關於gc,我們比較關注的是時間比較長的後續情況,超過500毫秒我們會通過發出unavailable異常報給Ops同學。

第二個層面是Logs層面異常的收集。

第一是slow cql,就是讀的時候比較慢的cql,我們會收集。gc log是Cassandra自己的GCInspector的log,還有warn log比如large partition。這些我們會通過SLS收集,之後相關的報警也會告訴我們值班的同學,最上層是Cassandra自己的metric的資訊。Metric資訊我們會分兩類進行處理。第一是展示給使用者的Metric,比如容量、compaction等,是我們覺得使用者會比較關心的,會通過CMS給使用者。全量的80%的metric也會通過CMS鏈路報給我們自己的Ops同學。通過這種方式,我們可以對metric也設定一些報警。

 

相關文章