天天看點

Cassandra 性能壓測及調優實戰

一、性能壓測  

(一)壓測工具 ——ycsb

優勢

• 使用比較簡單

• 支援多種開源資料庫:redis,mongo,cassandra,hbase

• 友善對不同資料庫做性能對比

市面上有很多壓測工具,這裡主要選擇了ycsb這一款壓測工具。選擇它的原因很簡單,因為它的使用上比較簡單,并且它支援多種開源資料庫,像redis,mongo,cassandra,hbase ,是以你一旦掌握了,它就可以對多種資料庫進行壓測,并且友善對不同資料庫做性能對比,這樣可以選擇對你最适合的資料庫,它支援對多種資料庫進行壓測,如果你下載下傳的完整壓縮包的話會比較大。

cassandra專用壓縮包:

下載下傳

Wget

https://github.com/brianfrankcooper/YCSB/releases/download/0.15.0/ycsb-cassandra-binding-0.15.0.tar.gz

tar -xvf ycsb-0.15.0.tar.gz

cd ycsb-0.15.0

(二)目錄結構

Cassandra 性能壓測及調優實戰

•bin ——執行檔案目錄

•lib ——依賴jar 包

•workloads ——壓測模型定義檔案

壓縮之後進到它的目錄下面,可以看到它的目錄結構主要有三個目錄,分别是bin,lib,workloads ,bin目錄主要是執行檔案目錄,而lib主要是依賴的jar目錄,像這個包它由于隻支援cassandra的壓測,是以它的lib包下面的jar非常的少,而我們的重點關注在于workloads的這一個目錄。

在這一個目錄裡面你可以看到他預先存在一些定義好的壓測模型,你可以根據他提供的這種預設的壓測模型進行略微的修改,很快的得到你需要的一個壓測模型。

(一)定義壓測模型

文檔位址:

https://github.com/brianfrankcooper/YCSB/wiki/Core-Properties

•recordcount —— 定義壓測初始資料量,盡可能比對實際資料

•operationcount —— 壓測過程中,執行的讀寫次數,建議運作

半小時級别以上

•fieldcount —— 字段數

•fieldlength —— 字段長度,fieldlength + fieldcount 決定一

行的大小

•readallfields —— 是否讀所有字段

•readproportion + updateproportion + insertproportion + 

scanproportion —— 定義讀寫比例,可以純讀,純寫,或者讀

寫混合(比例可調)

10w 資料量,10w 次純讀,每行10 個字段,每個字段200 bytes 大小

Cassandra 性能壓測及調優實戰

一次正确的壓測,首先最重要的是你需要定義你的壓測模型,首先你需要定義你初始的資料量,這個資料量最好是比對你實際的資料量,比如你有異議的資料,你在壓測的時候你就需要準備1億的資料,如果你隻準備了1萬或者10萬的資料,壓出來的性能和你實際的性能會相差甚遠。你在壓測過程中需要執行的一個讀寫次數,還有一個比較重要的就是因為以表結構來舉例子的話,表是有很多行組成的,每一行它其實有多個列,每列它其實會有一個大小,你需要定義你的字段數以及每個字段的長度,這樣去比對實際業務模型,才能得到一個比較準确的壓測。

(一)建表

// 副本數設定和實際生産保持一緻,副本數會影響資料大小,也會影響讀寫性能。

// 副本數不一樣,壓測出來的結果會非常不同

create keyspace ycsb WITH replication = {'class': 'NetworkTopologyStrategy', 'cn-shanghai-g': 2};

create table ycsb.usertable (

y_id varchar primary key, 

field0 varchar, 

field1 varchar, 

field2 varchar, 

field3 varchar, 

field4 varchar, 

field5 varchar, 

field6 varchar, 

field7 varchar, 

field8 varchar, 

field9 varchar);

我們需要對我們的​資料庫做一個初始化,ycsb這一款壓縮工具它預設的命名空間是 ycsb,然後它預設的壓縮表是usertable,是以通過這兩條指令你可以直接建立出他所需要的namespace和table表。這裡面需要注意的是在建立namespace的時候需要指定一個副本數,這一個副本數也會影響整體的一個資料大小,同時會影響讀寫性能。是以在設定壓測的副本數的時候,和實際應用保持一緻是最好的。

(二)構造測試資料

./bin/ycsb load cassandra2-cql -s -threads 20 -P workloads/read

注意事項:

• 通過内網通路進行壓測

• 用來壓測的ecs 規格不宜太小

• 構造資料的性能可以看做純寫入下的db 性能,通過調整線程數逼近

db 的寫入性能上限

• 測試資料量一定要逼近真實資料量大小,否則,cache 命中率不一樣,

測試讀的時候,響應會截然不同

• 構造測試資料,一定要持續一段時間,這樣才能觀察到db 背景任務

運作對寫入性能的影響

Cassandra 性能壓測及調優實戰

你在構造你的壓測資料的時候,你資料量一定要足夠大,然後一定要持續一段時間,因為任何一款資料庫它都存在一些周期運作的任務,或者說一些背景的任務,如果你持續的時間比如說隻有一分鐘,很可能背景的任務或者周期任務他還沒有執行,那麼你壓測出來的表現就并不是最真實的一個表現,因為任何一個周期任務,它其實都會搶占你的CPU資源,或者說磁盤的io資源,它會影響你的讀寫的性能,完成了測試資料的構造,那麼通過把漏的指令改成亂指令,我們就可以對你的實際的壓測産品做一個壓測。

(一)讀場景性能壓測

./bin/ycsb run cassandra2-cql -s -threads 20 -P workloads/read

注意事項

• 讀性能壓測,一定要持續一段時間,資料庫都有緩存,需要等緩存命中

率比較穩定時,其性能表現才比較真實

Cassandra 性能壓測及調優實戰

完成了測試資料的構造,那麼通過把load的指令改成run指令,我們就可以對你的實際的壓測産品做一個壓測。這裡其實就是一個單純的讀産品的壓測,在壓測完成之後,也能看到在這一個多場景下的性能情況。壓測的時候,你的應用cassandra裡面的緩存其實是空的,隻有在持續一段時間之後,你的資料庫的緩存它的命中率比較穩定了,壓測出來的資料才是比較真實的。

二、性能調優

(一)Cassandra讀寫原理

Cassandra 性能壓測及調優實戰

在進行場景介紹之前,首先介紹一下Cassandra的讀寫原理,這樣友善後面講解它的優化思路的時候,大家能夠更加快速的了解。

首先講Cassandra的寫請求,他寫請求其實非常的簡單,一條寫請求進來之後會首先記錄一條log,也就是Commit Log或者說Write Ahead Log。在Log裡面記錄完成之後,會把它插入到記憶體裡面對應的一個結構Memtable裡面去,一旦插入完成,寫請求就結束了。寫請求這麼簡單,它的設計導緻Cassandra在寫場景非常優異,絕大部分使用場景下,你如果正确的使用寫入基本上都不會成為瓶頸。因為隻涉及到一次磁盤寫入和一次記憶體操作,這一次磁盤寫入其實是因為是寫log的形式,是以它其實就是直接append,磁盤寫入的話性能是非常高的。

我們來看一下Cassandra如何完成一次讀請求。每一次寫入到記憶體Memtable,記憶體中的Memtable會越來越多,記憶體放不下,為了避免記憶體水位過高,Cassandra會周期性的把記憶體裡面的Memtable flash到磁盤,形成一個SSTable檔案。那麼SSTable檔案逐漸增多,會有周期性的任務叫Compaction,把多個SSTable檔案合并成一個大的SSTable檔案,一條讀請求進來後,會對記憶體裡面的Memtable和磁盤上的SSTable做多路歸并排序,然後找到你所需要的資料再傳回給你。

(二)準備工作:完善的監控

任何一次的性能調優都需要有完善的監控,完善的監控是所有性能調優的出發點以及終點。

下圖是Cassandra上你能看到的監控圖,一個完善的監控,基本上需要具備CPU、記憶體、磁盤、網絡等最基本的系統級别監控,同時還需要能夠看到Cassandra應用内部的狀态,比如讀寫OPS、讀寫響應、GC情況、Compaction情況,Cache命中率以及各線程池目前狀态。

Cassandra 性能壓測及調優實戰

場景一:寫入穩定,讀取延遲逐漸升高

Cassandra 性能壓測及調優實戰

首先我來介紹場景一,場景一的特點是寫入穩定,讀取延遲逐漸升高,這是一個很典型的案例,之前介紹的如何處理一個讀請求,讀請求其實是會對記憶體裡的Memtable和磁盤上的SSTable做多路歸并排序。如果說你的SSTable數量越多,其實它可能涉及到的io次數就會越多,而我們都知道磁盤io是很慢的,是以當你的讀取延遲在逐漸升高的時候,你可以想到的一個可能性就是說你的檔案數在越來越多,Compaction的過程被阻塞了或者太慢了,導緻你的檔案數一直在增多。

通過nodetool  compactionstats檢視pending task,通過這個資料我們可以去定位是不是你的Compaction任務太慢了或者卡住了,導緻有太多堆積的Compaction任務沒有完成。如果是的話,可以通過調整你的Compaction并發數,比如說同時執行多個Compaction,或者對你的機器做更新使你擁有更富裕的CPU資源來完成你的Compaction任務,起到一個優化的效果。

場景2——寫少讀多,對響應延遲較為敏感

場景二是寫入很少,但讀取很多,對讀取的響應延遲較為敏感,這裡需要介紹一下cassandra預設的compacion政策叫做Size-tiered compacion。在compacion執行很多次之後,磁盤上的sstable會形成類似于根據大小進行分層的一種分布設計。這種預設的compacion設計,有好處也有劣勢,每一個sstable是可能存在重疊,在最壞的情況下,一個讀取請求進來,可能需要對每一個sstable做一次seek操作,才能知道目前sstable裡面有沒有對應的資料,檔案數越多,涉及的IO越長,延遲越長。

Cassandra 性能壓測及調優實戰

這時可以考慮使用另一種compacion政策,叫做leveled-tiered compacion。能夠把磁盤上的sstable分成若幹層,每一層裡面的sstable互相之間沒有重疊關系,因為有這個保證,是以一條讀取請求進來之後,每一層裡面最多隻有一個sstable納入到歸并排序當中,層級次數決定涉及這一次讀取請求需要處理sstable的上線,導緻讀延遲更低,也更加可控。

由于需要保證每一個層級裡面的sstable互相之間不重疊,是以對寫放大較為嚴重和較多compacion任務的執行,比較适合于讀比較多,寫入比較少的場景。

場景3——寫入量級特别大

場景三寫入量級特别大,如:IoT行業、物聯網行業、滴滴軌迹記錄等行業,很少讀取,但寫入量級特别大。

針對這種場景有幾個優化方式:

1)方式一:

·常識:網絡延遲>磁盤寫入延遲。

·通過batch insert的方式,降低用戶端和服務端的互動次數,進而減少網絡延遲的影響。

需要知道網絡延遲遠遠高于磁盤寫入延遲,寫入量級特别大的時候,可以考慮批量寫入方式,來使網絡延遲減少用戶端和服務端的互動次數,進而減少網絡延遲的影響。

·Cassandra batch可以實作跨表級的事務,但是性能損耗較大。

使用注意事項:

·隻做一張表的batch insert;

·使用unlogged的batch insert;

·每一個batch insert 包含的insert數建議不超過10。

Cassandra 性能壓測及調優實戰

2)方式二:

如果前一個方式應用之後,還是不能滿足寫入要求,遇到第二個瓶頸,commit log flush 目前cassandra 是單線程做的,寫入量級太大的情況下,會成為瓶頸。

原理是在cassandra裡面,預設每10秒對commit log做一次sync操作,sync操作把記憶體裡面的commit log刷到盤裡面去,每次sync都會産生一次磁盤寫入的峰值,而這一次寫錄其實還沒有真正寫入到磁盤的媒體當中,會寫入到磁盤的pageCache裡面,預設政策為周期性将pageCache中寫入持久化。目前很多使用者使用各大雲廠商的雲盤産品都有寫入流量的限流政策。預設參數下面,每一次寫入磁盤都是一次大批量的寫入,會産生較大峰值,很有可能觸發寫入流量的限流政策。

Cassandra 性能壓測及調優實戰

在這個情況下,調節Linux核心參數:

Vm.dirty_writebark_centisecs=10

Vm.dirty_expire_centisecs=20

可以提高 pageCache下刷雲盤的頻率,進而導緻每一次刷下去的大小都會減小,不容易觸發限流政策,導緻了io Write顯着的降低,對于寫延遲會有質的提升。

3)方式3:

由于預設每10秒一次sync,如果寫入量級特别大,10秒内會堆積大量commit log,需要被sync到磁盤,而在cassandra的實作裡面,對于commit log的sync操作,是單線程處理的操作。是以當sync的速度跟不上寫入的速度的時候,寫入就被block住等待。

Cassandra 性能壓測及調優實戰

如上圖所示,含義是根據上一次sync完成的時間點和當下期望的時間點,如果sync小于期望sync的時間點,證明sync的速率跟不上寫入的速率,就會做一個等待操作,降低寫入的TPS讓sync能夠追上。

是以搭建一個完整的監控系統,要看waitingOnCommit監控名額發現這一瓶頸。每一個commit log都是一個單獨檔案,雲cassandra通過檔案級别并發做sync提升了sync環節的處理效率,解決了這一問題。

4)方式4:

為了資料可靠性,往往建議設定多個副本。多副本的場景下,接受節點往往會生成一個副本同時向其他節點發送請求,生成足夠的副本數。每個節點和叢集所有其他節點之間會維護一個隊列來儲存節點之間通信的消息。

Cassandra 性能壓測及調優實戰

舉例:3副本,10wtps寫入,會産生20w内部消息通信,副本數越多,内部消息通信放大越嚴重當量級過高時,cassandra預設的隊列實作會産生嚴重的鎖沖突,導緻性能下降。通過iprofiler的jvm性能工具可以友善的監測鎖沖突的嚴重情況。

在這個場景下面,可以通過降低副本數,達到減少内部通信的量級規避問題。或者增加節點數,因為節點數增加了,變相的節點之間的隊列數就增加了,每一個隊列的負載相對就會減少,進而達到降低鎖沖突的效果,但是這兩個措施都需要業務改造,并且都有對應的成本。比如副本數降低,資料可靠性就降低了,或者叢集節點數增加,運維成本就會增加,增加的是整個經濟成本。

雲cassandra通過實作了一個高性能的無鎖隊列,參考開源的實作disruptor,性能非常棒,替換了cassandra預設的隊列實作,大幅提升了這一場量下的性能上限。

場景4——讀響應時間長,磁盤IO重

Cassandra 性能壓測及調優實戰

讀響應時間比較長,io比較重,這裡有一個通用的使用誤區,在cassandra之前的版本,如果使用了壓縮,它預設的大小是64k,某種程度上是合理的,因為壓縮它是需要針對一個指定的大小進行一個壓縮,才能達到一個比較理想的壓縮率,磁盤的存儲成本才能夠降低,但是預設的64k還是太大,是以在社群讨論已經建議調整為16k,在新版版本裡,預設的壓縮的快大小就是16k,同時這個大小可以滿足實作比較理想的一個壓縮率,好處就是io會顯著的降低。

是以當block的大小設定的太大的時候,磁盤io會增加特别多,通過alert表屬型進行調整之後,做一個major compaction,才能使調整真正的生效。

Cassandra 性能壓測及調優實戰

除了調整block的大小之外,磁盤io重,就是因為cache的命中沒有命中到,走到磁盤,産生磁盤io,可以通過nodetool info工具,看到對應如chunk cache和key cache的大小以及對應的命中率。通過cache如果執行個體上有較富餘的記憶體資源,可以調整chunk cache和key cache的大小,進而去提升cache的命中率,這樣落到磁盤上的io就會顯著地減少,降低io,進而讀響應時間會更加的快。

如果場景是80%的讀請求集中在20%的row上面,可以考慮開啟row cache功能,它預設是關閉的,因為它會帶來記憶體的壓力,開啟便會有比較好的一個效果。

key cache、chunk cache和row cache三個cache的大小是沒有一個最佳的比例的,根據實際情況,去調整三個cache的大小關系,調整完後以監控資料為準,監控資料實際效果好的就是最佳的一個大小比例。

這也是一個完善的監控是很重要的,就是它不僅能夠發現問題,還能去驗證優化效果是否達到了預期,優化措施是否有效果。

場景5——讀響應毛刺較高

讀響應毛刺很高,較高的機率是由于gc導緻的,如較長的full gc或者很頻繁的full gc,首先就需要排查cassandra是否存在記憶體洩漏,其次去參考jvm的GC調參最佳實踐,調參GC相關的參數,也能實作GC的優化。

考慮使用cassandra自帶的Speculative特性,其工作原理就是用戶端向服務端的一個節點發送了請求,根據自己設定的一個域值,在超過這個門檻值之後,如果請求還沒有得到相應的話,會向第二個節點發送一個請求,這時候是針對一個請求,發送了兩次,請求到服務端這兩次請求任何一次請求優先傳回之後,都算成功生效。

Cassandra 性能壓測及調優實戰

思路就是一個叢集内可能周期性的會有一些慢節點,通過這個門檻值來判斷是否請求到了一個慢節點,如果是,就換一個節點,進而規避掉慢節點,避免請求一直被卡住,如果門檻值設定的過小,會産生較多的額外請求,會增加整個叢集的負載和壓力,需要根據監控去不斷的調整的門檻值,找到一個比較合适的點。

(三)性能調優總結

性能調優

第一,一定要有監控,有監控才能去做分析,去評估優化的效果,監控是所有性能優化的出發點和終點。

第二,熟練掌握相關的工具,如jprofile是一個比較好的監控GC或記憶體洩漏的一個工具。

自帶的nodetool,其實會暴露内部的一些情況,如線程池的使用狀況,但也可比較好排查性能瓶頸位于哪一個環節,需要對原理有一定的了解,才能去分析可以采取的措施,以及說目前處于瓶頸的會涉及到的環節,哪些環節可能成為的性能瓶頸。

優化的時候,可以考慮從業務改造上去進行規避,也可以考慮從源碼級别去做性能的優化,思路比較靈活。