1. 程式人生 > >Cassandra,我又回來了

Cassandra,我又回來了

         早在2010年中的時候,我就對Casandra特別感興趣,那時候還是0.7版本,累計2個月每天晚上都花2小時來啃原始碼,讀寫流程都除錯N遍了,也整出來幾篇小文,不過後臺工作方向上最終沒有它的用武之地,後面就慢慢沒有再持續更進了。這個差不多5年以後的現在,有些場景覺得Cassandra很合適,就又把他拿出來溜一把。

         業務上有類似播放列表的需求,由於需要分析使用者的行為資料(使用者的播放與下載資訊都有單條的記錄資訊),不光需要能進行資料清洗還要能查詢指定使用者按照時間維度的詳細行為,已經收集到的資料累計有近80億條。對於寫入和讀取都有很高的要求,如果每秒寫入1000條的話,需要寫入2222小時,每秒寫入10000條,需要寫入222小時,對於讀取資料也是一樣的,而我根據資料分析的結果不同可能需要把這個資料過濾很多遍,就算每次遍歷速度為10000條/秒,那也要遍歷222小時,如果就這個速度,這事基本也就不用做了。這個時候,Cassandra就又來到了我的面前了,雖說放下5年了,但是我還是不時的想起它來,多少還是知道它進展到哪裡了。

         (一)關於Key的那些事

        直接進入正題了。我覺得composite-keys-in-apache-cassandra這篇文章所描述的概念如果不能理解透徹的話,真不應該去擅自去實驗使用C*,當然更加不應該去在產品中使用了。

        (1)單欄位作為分割槽鍵          

create table bite (
      id varchar PRIMARY KEY,
      feedid varchar,
      score bigint,
      data varchar
  );
 
create index bite_feedid on bite (feedid);
create index bite_score on bite (score);
這裡id作為分割槽Key,就像我們經常在mysql中用到的按照Id維度來分表一樣,id欄位決定了該條資料到底落地在C*的哪一個節點上。至於後面的二級索引,基本可以當它不存在,號稱是索引,真的派不上用場的,就像划船繡腿一樣,只能用來吹吹,沒有使用價值。我這裡就不表了,如果你真的想明白了二級索引的原理,真的徹底知道它的優缺點之前,不要去用它是最好的選擇。

           (2)複合key

create table Bite (
      partkey varchar,
      score bigint,
      id varchar,
      data varchar,
      PRIMARY KEY (partkey, score, id)
  ) with clustering order by (score desc);
          這裡分割槽欄位是partkey,而score和id欄位就是輔助key,直白一點說就是partkey決定了資料在哪一個節點上,score和id欄位則決定了在同一個分割槽key下,資料是按照score和id來排序的。

            (3)複合key增強版

CREATE TABLE t_play_download_event (
 userId bigint,
 opType int,
 entityType int,
 executeTime timestamp,
 entityId bigint,
 sEntityId bigint,
 PRIMARY KEY ((userId, opType, entityType ), executeTime, entityId)
);
這個例子中,userId、opType、entityType聯合作為分割槽鍵,但是資料可以根據executeTime和entityId來排序,不過在按照entityId來排序的時候必須得指定具體的executeTime的值。
         (二)分割槽器

       為什麼要大書特書分割槽器呢?個人認為這個至關重要了!我們用C*的時候,怎麼也得想清楚我們的資料在Cassandra中是如何分佈的,支援那些特性或者又不支援那些特性,否則事半功倍亦或是南轅北轍了,最後的大家都受傷了。比如使用者會說C*這個效能啊真是差啊,什麼Benchmark都是吹的;那些C*的老手都難得搭理這些惱騷,一幫不懂的人在那裡瞎嚷嚷些啥啊!

      C*中採用虛擬的vnode的方式把row key分散儲存到不同vnode,由於vnode可以分得相對較多些,所以資料基本上都均勻分佈到不同vnode中去了(或許有人不同意這個說法,但是至少比早期的一個節點上就是一個token範圍那強的太多了)。這個強調了一個”均勻“,這個是所有分散式儲存都面臨的問題了,要實現起來就難了,不同儲存由於特性各異,支援的分佈特性也各不同,當然這個是核心問題,也會給這個儲存帶來決定性的影響了。

       話說這麼多前湊了,那到底C*中有哪些法寶來分散資料呢?

       Murmur3Partitioner:這個是預設的分割槽器,也是最最符合C*設計者們的需要的一個分割槽器。一句話,這個是根據作為row key的欄位的hashcode來分佈的,它的分佈基本是均勻的。不過要記住,row key : 100001 ,100002,100003這些看起來是連續的row key採用hash後就不知道相差幾萬裡了,大家分散到不同機器,不同節點都是可能的。基本可以認為是隨機分佈好了,也就是說row key只支援精確匹配,不支援大小、範圍、前後綴匹配等等你想象到的查詢。不過話說回來,在同一個token範圍以內,row key是按照hashcode的值有序排列的。這個特性看起來沒啥用,不過在特定情況下就不是一般的有用了,那是唯一的大招了。

        RandomPartitioner:這個分割槽器也是隨機分割槽器,基本特性和Murmur3Partitioner大同小異,在Murmur3Partitioner實現之前這個就是C*的預設分割槽器。具體細節不說了,反正現在有Murmur3Partitioner分割槽器了,直接用它就好。

       ByteOrderedPartitioner:這個分割槽器是支援row key範圍查詢的。它採用的是row key的位元組資料來按照位元組序排序。

       OrderPreservingPartitioner:這個分割槽器也是支援row key範圍查詢的。它採用的是row key的utf-8編碼方式來排序。

       話說回來,我這裡就只重點介紹了第一個分割槽器Murmur3Partitioner,其它都是一帶而過。可以這樣說吧,用C*的話,你就用Murmur3Partitioner分割槽器好了,別的分割槽器不用為好,如果非要用,就要卻行自己搞清楚搞明白了。不過,可以說十有八九是不怎麼靠譜的。

      (三)實戰的故事

       在我儲存近80億條資料的時候,是用4臺機器,4個C*的節點,由於這些機器上不是隻在執行C*,所以記憶體根據各機器不同,有的分配8G,有的分配4,還有的只有3G,至於磁碟就沒有什麼好說的,都是commit log 和 data 儲存到一個STAT的硬碟上,裸盤,空間足夠大。我所能採用的資源就這麼些,也只能勉為其難了,不過好在Cassandra的效能足夠好,對於我的場景足夠用了。

       直接給出我的事例好了。

        (1)建好keyspace,複製因子為2,其它一路預設(用的的是DevCenter)下去就好了。

        (2)建好column family(t_user_event),其中userId、opType、entityType為rowkey,而executeTime、entityId和作為聚合key,同一個使用者對視訊或者音訊檔案的播放或者下載資料全部共用一個rowKey,而具體的操作資料則按照行為時間和操作物件ID來區隔開來。

CREATE TABLE t_user_event (
 userId bigint,
 opType int,
 entityType int,
 executeTime timestamp,
 entityId bigint,
 sEntityId bigint,
 PRIMARY KEY ((userId, opType, entityType ), executeTime, entityId)
) WITH bloom_filter_fp_chance = 0.01
AND comment = ''
AND dclocal_read_repair_chance = 0.1
AND default_time_to_live = 0
AND gc_grace_seconds = 864000
AND max_index_interval = 2048
AND memtable_flush_period_in_ms = 0
AND min_index_interval = 128
AND read_repair_chance = 0.0
AND speculative_retry = '99.0PERCENTILE'
AND caching = {
 'keys' : 'ALL',
 'rows_per_partition' : 'NONE'
}
AND compression = {
 'chunk_length_kb' : 64,
 'crc_check_chance' : 1.0,
 'sstable_compression' : 'LZ4Compressor'
}
AND compaction = {
 'bucket_high' : 1.5,
 'bucket_low' : 0.5,
 'class' : 'SizeTieredCompactionStrategy',
 'cold_reads_to_omit' : 0.05,
 'enabled' : true,
 'max_threshold' : 32,
 'min_sstable_size' : 50,
 'min_threshold' : 4,
 'tombstone_compaction_interval' : 86400,
 'tombstone_threshold' : 0.2,
 'unchecked_tombstone_compaction' : false
};

      (3)我直接就用Java版本的客戶端(cassandra-driver-mapping)來寫入資料

       注意我們的寫入節點是一個單點,就放在Cassandra所屬節點的一臺伺服器上。嗮一下我的寫入效能,連續寫入50億條資料,整體的平均速度差不多保持在每秒50000條資料。期間也碰到不少問題,由於Linux的記憶體不夠,都使用到交換區間了,導致機器的負載很高的現象,不過在機器資源相對富裕的機器上則很淡定,有一個不精確的估計,一個靠譜Cassandra的節點,應該分給Heap的記憶體在4-8G比較靠譜穩定高效。

       話說在讀取資料的時候就太費腦筋了。我需要把寫入到Cassandra的資料都遍歷出來,最開始是用1-2億範圍的數字ID來作為使用者ID,至於opType則之後選擇使用播放還是下載,至於entityType就只用音視訊來區分,這樣累計出來的可能rowkey就有4-8億了。最開始使用的讀取基本用到了Cassandra的隨機讀,結果讓人崩潰了,單節點多執行緒的方式去讀,每秒鐘才讀200-500個而已,我的最大8億個rowkey不知道何年何月才能遍歷完。由此可見,Cassandra的隨機讀,在記憶體不足的時候,簡直就是直接考驗磁碟IO了。我的80億條資料佔了200G*2的空間,而我的4個節點上才有可憐的18G的記憶體,我那種訪問方式看似順序,而對於Cassandra來說就等於徹底的隨機訪問了,這樣不慢才是怪事。

       想來想去,幾無可能改善情況了。

       要想提供速度只得想大招把磁碟隨機讀變成順序讀才有可能。後來,終於想到如果能順序遍歷token不就可以充分利用順序讀嗎?這不可以試一試了,就有了類似下面的CQL出現:

select token(userId,opType,entityType),executeTime,opType,sEntityId,entityId,userId,entityType from lrts_data_center.t_play_download_event where token(userId,opType,entityType) > 0 limit ?10000;
     實驗下來,終於靠譜了。這次,我把[Long.MIN_VALUE,Long.MAX_VALUE]範圍內的token分成等分的8個區間,用8個執行緒來掃描各自負責的範圍內的token。最後的結果太驚人了,遍歷資料的速度達到每秒種峰值超過40萬條,就是80億條資料遍歷下來的平均速度也高達371820條/秒。這回,我的資料幾個小時就可以清理一遍,完全滿足要求了。

(四)那些在等著你的坑

        1、第一個就是記憶體來了。Java這東東什麼都好,就是GC不好,小了限制寫入速度,大了也有問題。建議在單節點4-8G。反正我是碰到不少問題了,這裡只給出結論。

        2、最常見的異常

2015-11-08 01:31:02,225 ERROR [com.lazyaudio.test.cassandra.task.RowTextParserTask:60] [IO error]errorMsg=Cassandra timeout during write query at consistency ONE (1 replica w
ere required but only 0 acknowledged the write)
com.datastax.driver.core.exceptions.WriteTimeoutException: Cassandra timeout during write query at consistency ONE (1 replica were required but only 0 acknowledged the write)
        at com.datastax.driver.core.exceptions.WriteTimeoutException.copy(WriteTimeoutException.java:73)
這個問題涉及面說多也多,說少也少,說白了還是記憶體問題。要把Java客戶端的超時時間稍微調長點,或者在服務端的記憶體過小需要調整到4-8G範圍,再不行還要能把斷連得連結重試來重新連結。

           解決問題的過程才是最爽的,NB的人就是靠著一個有一個戰勝困難才能達成的。

相關推薦

Cassandra回來

         早在2010年中的時候,我就對Casandra特別感興趣,那時候還是0.7版本,累計2個月每天晚上都花2小時來啃原始碼,讀寫流程都除錯N遍了,也整出來幾篇小文,不過後臺工作方向上最終沒有它的用武之地,後面就慢慢沒有再持續更進了。這個差不多5年以後的現在,有

時隔兩年回來

首先說明下回來的原因 一、我這個人經常會有很多的想法,然後呢,又會因為各種的原因而耽擱了。所以想要有一個地方可以記錄我的想法,並且能夠更新進度的。大致調查了一下,也就ERP系統差不多滿足我的想法,但是契合度太差,我想要的是能夠分類的,新增想法,新增進度的東西。所以最終選擇了CSDN,畢竟可以分類

時隔三年回來

    過去三年,一直忙於碩士論文  +  外出實習(百度 + 華為 + 網易遊戲)一年  +  談戀愛(現已拜拜)。     畢業後,在中國電信IT研發中心工作了兩年大資料平臺相關的工作。     現在在阿里做大資料相關工作。     突然收到郵件說我的部落格很久沒更新了,

很好csdn的部落格不錯回來

以前由於csdn的部落格登入速度慢,寫了一個文章可能沒有發表成功而使我的書寫白白作廢了,今天回來一看,喲呵,變了不少,而且速度也上來了,以後針對技術類的文章,我還是要發表在這裡了。在百度空間上的東西,都放一些與技術無關,

Disqus回來

文章目錄 提醒:本文最後更新於 1185 天前,文中所描述的資訊可能已發生改變,請謹慎使用。 上個月底,我將部落格用了幾年的 Disqus 評論系統替換成了國內的多說,還寫了一篇「讓多說評論框完美支援 HTTPS」的文章,列舉了我對多說的改造。然而,不到一個月的時間,我卻決定再次換回 Di

回來

文章 方法 定時 包括 回來 關於 進步 問題 解決 久別多日,我又回來了 已經好久沒有更新,文章,再次說聲抱歉. 後期將會不定時更新,更新內容有所變更(但是依舊是關於Java的),更新內容主要以下面幾點為主: 1.已經熟知的Java知識將會很少涉及(例如SSM框架知識);

實習之後來到親愛的程式設計世界

   好久沒有寫文章了,今天想突然想寫一下了,想把我最近這段時間實習的一些東西跟大家分享一下,當一個人真正進入到一個專案的開發中時,和在學校做練習是完全不是一個感覺的。    首先從要求上就不一樣,在學校做練習,對介面的要求會很低,有時候只要我們實現了一些

離職阿里三年後回來

11月22日,馬輝從黃龍體育中心附近的辦公室開車來到阿里園區北2門,離開阿里三年後,馬輝和1000多名已經畢業的“校友”又回到了這個夢想啟程的地方。 在校友會現場,馬輝分享了自己的公益故事。 1991年,大眼睛女孩蘇明娟的照片《我要讀書》傳遍全國,引發了國人對貧困地區兒童的關注。2016

離職阿裏三年後回來

發現 優秀 過去 真的 開始 教師 教育 機構 素質 11月22日,馬輝從黃龍體育中心附近的辦公室開車來到阿裏園區北2門,離開阿裏三年後,馬輝和1000多名已經畢業的“校友”又回到了這個夢想啟程的地方。 在校友會現場,馬輝分享了自己的公益故事。 1991年,大眼睛女孩蘇明娟

回來

今天登入CSDN,呵呵,改版了。近期動作不小,也不少。好啊。 以前,一開始用Blog就是在這裡。可後來我不用了,因為實在是不好用,寫個文章老是發不出去,速度還慢,有時還沒法訪問。後來我就跑到Sohu去了。 可Sohu那畢竟不是一個我們這樣的人待的地方。總感覺彆扭,可也沒辦法,

hive 學習系列五(hive 和elasticsearch 的交互很詳細哦來吹liubi

圖片 upload ima com 5.6 cat rds href ping hive 操作elasticsearch 一,從hive 表格向elasticsearch 導入數據 1,首先,創建elasticsearch 索引,索引如下 curl -XPUT ‘10.81

誰動的乳酪誰動的程式碼的“bug"

  "你的是我的,我的還是我的”經常在熱戀中的情侶中這樣說,但現實生活中還是要好好掌握自己的主動權。 自己的東西,始終是自己的,不允許任何人在不知情的情況下,進行隨意的支配,就算在親密的人,在不知情的情況下,觸犯到了彼此的隱私,心情也會不美麗的,久而久之,還會積累很多的矛盾。    

那個賣房子去大理的姑娘4個月後回來

我一直是個後知後覺的人。比如,這一輪舉國談論了大半年的房價飛漲,我很晚才覺察到周圍人的異樣。怎麼每個人都在談房子?就連平常看的一些安貧樂道的公知們寫的公號文章,都忽然間畫風突變,瀰漫著焦慮、憤恨。還有捶胸頓足地教導大家“賺錢的重要性”。當然,也因為對時局的後知後覺,我在去年年初,興高采烈地賣掉了北京的房子,舉

比特幣分叉案判決丟失的BCH終於回來

去年8月1日,UTC時間(零時區)12:37,比特幣在區塊高度478558開始硬分叉,比特幣現金就此誕生了。 只要在分叉前擁有比特幣的人,分叉後就會獲得等額BCH,而BCH也自分叉那一刻開始“挖礦”,獨立成為一種新的數字貨幣。 在比特幣生出的眾多“兒子”當

紀念一下回來

學習C#的時候就在CSDN寫部落格,後來又跑去開源中國寫。 現在受不了開源中國的markdown又回來了。 https://my.oschina.net/Shawn1in/home 這裡留個地址,將

lemonoil回來。。才怪。。

eiπ+1=0eiπ+1=0 E=mc2E=mc2 Ψ(x,t)=ψ0e−iEt−p⃗ ⋅x⃗ ℏΨ(x,t)=ψ0e−iEt−p→⋅x→ℏ H^Ψ=iℏ∂Ψ∂tH^Ψ=iℏ∂Ψ∂t ΔxΔ

生活是苦難的劃著的斷槳出發

沒有 點點滴滴 拖延 clas 今天 畢業 卻又 一點一點的來 class    種一棵樹最好的時機是十年前,其次是現在。   已經很久沒有寫過什麽了,雖然從大三那年就想著開通一個自己的博客,記錄一下生活的點點滴滴,或是積累一下專業方面的知識,然而這個計劃總是被自己以各種

今天 Google 回來好像

可惜的是,目前已經無法訪問了。可能是由於 Google-CH 搜尋功能開放後,訪問量過大導致搜尋掛掉了。Google-CH 專案做起來需要太多的伺服器資源,不是 google fans 能承擔得起的。可見,我們大陸網友使用 Google 搜尋的迫切心情。這種開源的專案,其實需要大量的伺服器資源,而承載能力大的

一次線上升級大規模報錯後重新學習序列化!

### 背景 去年9月份時候fastjson出現過一個漏洞,需要升級到1.2.60,舊版本是1.2.12,測試環境驗證完畢後上線,上線幾分鐘瞬間幾百封報錯郵件,當時瞬間心裡特緊張,但是表面上得裝著沒事,咱能搞定,哈哈,還好迅速定位並解決了問題。 ### 系統流程 出問題模組流程比較簡單,需要查詢一些