你們好,我是華爲消費者雲的吳太銀。node
我今天分享的主要是華爲消費者雲服務使用Cassandra的應用場景和最佳實踐。我這個可能跟其餘嘉賓分享的不太同樣,由於前幾個嘉賓講的實際上對Cassandra原生的代碼有必定的修改,而咱們當前使用的是純粹的、原生的Cassandra,咱們沒有作任何的修改。因此這個分享能夠給一些想大量使用原生的Cassandra的朋友有比較好的借鑑意義。算法
我今天會大概從這三個方面來給你們介紹一下:第一個就是咱們用Cassandra的一些使用歷程,經驗和教訓,以及咱們當前的規模;第二個就是咱們現網遇到的典型問題,我以前跟組織者交流,由於咱們當前的規模比較大,他主要是想看咱們在用到典型的ToC場景下,在用到大規模,大數據量的狀況下,在現網有哪些典型的問題,這個對你們應該有必定的啓示做用(哪些是Cassandra的雷區,是不能碰的,若是你把這些避免掉,就不會出大問題);第三個就是咱們使用Cassandra總結出來的最佳實踐,由於咱們如今全部的終端業務,基本上都會用到Cassandra,咱們的業務場景很是的複雜,必須有些設計上的,包括表結構的設計上的約束,不能隨便用,由於隨便用它必定會有問題。這個在前面的各位演講嘉賓也常常提到:咱們要順着它來用。數據庫
咱們如今先看一下爲何選Cassandra。你們可能都比較清楚了,我就簡單的說一下:一個是去中心化的部署,不但簡單,並且擴展性很好,能夠輕鬆應對業務發展帶來的數據容量和性能上的要求;第三個是它自然支持多DC的部署,咱們當前是一主一備,再加容災,三個數據中心,它自然的支持(這種部署),內部自動同步;第四個是它的監控指標和監控接口很是完善,經過nodetool和JMX能夠很是容易監控到Cassandra原生的各個指標,這個在咱們後面的幻燈片裏會看到,這一塊是很是重要的,在現網,特別是你在集羣規模變大了以後,你須要快速恢復一些故障的時候,沒有這些東西,你是作不到的;第五個是它的這個開源社區確實很活躍,包括穩定的版本演進,可讓咱們不停的選擇它。緩存
這個(幻燈片)是咱們的使用歷程,給你們看一下。咱們其實是從2010年開始就使用了。Cassandra是差很少2008年開始在Apache孵化,咱們差很少是跟孵化同時的時間開始接觸,一開始是0.7版本。Cassandra在咱們這邊用大概分兩個階段:前一個階段,多是一個相對來講比較失敗的一個經歷,由於這個階段咱們仍是主要用於ToB的場景。當時咱們的華爲手機還沒徹底(流行)起來。這個場景在這個階段咱們面對都是電信級的應用。安全
在這個時間段,其實NoSQL尚未徹底流行起來。咱們找的應用都是電信級的應用。可是電信級的應用你們都習慣用SQL的方式去作,第一個當時KV的方式你們也不太習慣,第二個當時Cassandra的接口不像如今這麼好。當時是純的Thrift接口,如今支持CQL,還有不少CQL的驅動。因此說當時是咱們找業務,因此咱們要按照它的使用方式,提供了一堆的定製化的東西,好比說咱們在Thrfit的基礎上,定製了一個類JDBC的接口,讓它像SQL同樣用Cassandra。這一塊當時咱們也是深刻的修改,咱們寫了一整套SQL解析的模塊(DDL,DML所有都重寫了,而後轉換成原生的mutation對象)。序列化和反序列化咱們所有都改了。包括咱們作得比較前沿的東西(由於當時0.7的版本尚未堆外內存),由於它的GC比較嚴重,咱們把memtable, index summary, bloom filter, row cache, key cache這些常駐內存的一大部分所有都放到了堆外。網絡
另外,咱們還作了存儲過程、二級索引、觸發器等。其實當時咱們就是對標的關係型數據庫去作。可是實際上咱們你們也知道原本Cassandra原生的是列數據庫,咱們強制按照行的方式來改造,實際上有很大的問題。再加上電信級的業務場景,這個對可靠性和數據的準確性的要求是很是高的。因此說咱們當時雖然作到了SQL的形狀,可是實際上沒有SQL的實質。這個只是在小範圍使用,也沒有徹底用起來。這個基本上算是一個失敗的嘗試。架構
而後這個過程對咱們有什麼好處呢?這個讓咱們深刻的看到了一些Cassandra架構,以及它的處理方式,還有它的源碼。由於在後續的發展過程當中,Cassandra的代碼雖然重寫了好多版(不停的重構),可是它的整個框架,整個處理流程是沒有變化的。這些知識對咱們後面這個階段是有很好的指導意義的。雖然咱們把Cassandra應用在電信場景沒有很成功,可是後來華爲的手機慢慢流行起來了。2014年開始,終端開始起來了。框架
以後,咱們面臨互聯網ToC的場景,實際上是很是適合Cassandra的,咱們就慢慢的找到了Cassandra存在的一些價值,而且不停的在往下走。這一階段咱們就沒有修改任何源碼了,徹底用原生的。由於根據咱們第一階段的教訓,改了源碼以後,基本上就成爲了孤版,很難向前演進。而後在終端狀況下,咱們不停的找,它最佳的使用場景。第二個由於ToC終端用戶對實時性和可靠性要求都很是高,因此咱們基於Cassandra的天生的多DC方式,實現故障切換。tcp
這裏仔細講一下:咱們當前的業務通常是1+1+1,一主一備一容災,每一個DC都是3副本。正常的狀況下咱們只會向一個DC寫,若是出現故障,咱們經過這個咱們重寫的驅動,把它切到另外一個DC去,保證任何DC裏的兩個節點出現故障,對終端業務的請求來講是無損的,客戶端會自動切換數據中心。另外,Cassandra原來是有OpsCenter來進行管理的,可是由於咱們公司的安全規範,沒有用它。咱們如今是構建了一套華爲本身的集羣部署管理,包括監控系統。第三,咱們不斷跟進社區的新版本。第四,Cassandra在華爲的使用場景很是多。能夠這樣說,凡是華爲終端,包括手機,包括穿戴式,包括IoT的全部華爲終端應用的背後,你看得見看不見的背後,都有咱們Cassandra的身影。好比舉個簡單的例子,運動健康,你們跑步的時候,就是這些數據都基本上存在咱們Cassandra裏去。華爲手機上的應用,只要你看獲得的,基本上後面都有Cassandra的身影。因此Cassandra伴隨了咱們消費者雲,伴隨了咱們華爲終端,六年的快速發展。性能
而後咱們能夠看一下咱們當前的規模。咱們當前的規模仍是比較龐大的,基本上咱們這裏存的全是用戶數據。Cassandra咱們全球的節點大概有三萬多臺,咱們的數據規模大概有20PB。咱們的集羣數量可能有500多。咱們最大的集羣的節點數有600多節點。咱們如今全網每秒有一千萬每秒的訪問吞吐量。咱們的平均延遲是4毫秒。咱們當前最大的一張表,單表達到三千億條記錄。像咱們這個量,在原生的沒有改動Cassandra源碼的狀況,可以達到這個規模,也是比較值得讓人驕傲的一件事情。這些數據從另外一個角度證實,Cassandra原生的穩定性,使得它足以在ToC的這種線上場景,能夠有很好的一個應用。
咱們下面再看一下,雖然咱們規模有這麼大,可是不表明Cassandra是萬能的,也不表明Cassandra它什麼問題都能解決。咱們要避開這些問題。
咱們當前面臨的挑戰,首先是華爲終端,包括中國區和海外不停的業務發展帶來的龐大數據量形成的穩定性的問題。如今華爲終端賣得很是好,並且用的人是愈來愈多,這個對咱們數據庫的壓力很大,也帶來數據一致性的問題。當前咱們有些數據是沒有上雲的。咱們自建了機房,自建機房一塊塊的盤,是不穩定的,會遇到一些壞盤的問題,壞盤會帶來一致性,包括殭屍的問題。第三個是基礎設施的問題,好比JDK的問題,網絡的問題,磁盤的問題,咱們都所有遇到過。第四個是故障的快速定位、定界,以及恢復。由於咱們如今面臨的都是OLTP的場景,全是ToC的。ToC的場景,基本上就是華爲終端用戶的場景。我舉個例子:假如你用到的華爲手錶,故障的時間一長,你的業務終端用戶就不能用,人家是很着急的。因此說咱們如今對於業務的體驗,包括故障的恢復的要求也很是高。咱們必須在半個小時以內把全部的故障必須恢復,你能夠定位不出來問題,可是你必須把它恢復掉。
我這裏有一個分類,把咱們現網裏遇到的典型問題列了一下。咱們現網遇到的問題比這多得多,多是這個的好幾倍,可是我總結了一下這些典型的問題,但願對你們,或者是即將使用原生Cassandra來構建本身的核心業務的朋友作一個提醒,你必定要注意這些方面的問題。這裏都是咱們在業務發展過程當中遇到的典型問題。我後面會針對每個問題,包括它的現象,包括從監控裏面的反應,包括堆棧,都會介紹一下,結合咱們的業務場景,給你們講講。
你們能夠看一下,這裏是咱們的監控系統,我把一些IP抹掉了,這是咱們的業務成功率,這是咱們現網節點的CPU、IO等系統指標。你們能夠看到案例的描述:有一次,現網擴容,可是擴着擴着就發現,到必定程度的時候,全部節點的CPU和IO都所有很是高,這個對咱們的業務影響你們能夠在右邊的圖裏看到,原本成功率百分之百,突然一降低了這麼多。對應的時間點內CPU、IO所有都飆升。爲何,這個就是集羣規模過大形成的影響。咱們能夠先看一下爲何會這樣。
根本緣由是:第一是咱們的集羣很是大,幾百個節點,第二個是咱們的Token數有256個,這樣算起來, 咱們最多能夠有十幾萬個Token範圍。新節點加入集羣過程當中,Token信息須要更新。同時,Cassandra讀寫流程裏面,也須要獲取Token信息用於路由。兩個流程使用讀寫鎖獲取一個對象。當集羣規模達到必定的程度時,Token數量過大,會致使Token信息更新緩慢,若是此時恰好業務高峯,請求會由於拿不到鎖而阻塞,從而致使業務請求大量超時失敗。這裏咱們給出的解決方案是,控制單集羣規模,主要是虛擬Token數量,儘可能不要超過十萬。集羣過大的時候,須要考慮拆分,不要讓一個集羣無限膨脹。咱們如今ToC的集羣爲了穩定性,咱們的集羣節點數不超過兩百。超過兩百個節點咱們建議業務去拆分。
第二個是,單節點數據量過大的時候,會有什麼問題。咱們當時每一個節點數據量達到了5TB,集羣變得很是不穩定。表如今單節點數據量大時,bloomfilter、index summary等須要的常駐內存量會很大,致使頻繁full GC甚至OOM;另外,咱們默認使用的壓實算法是Leveled Compaction Strategy,若是使用LCS並且數據量過大,磁盤空間可能不夠,由於L0常常須要使用STCS來作壓實操做。解決的方法是避免單節點數據量超過1.5TB,另外在擴容過程當中臨時增大磁盤空間或者設置disable_tscs_in_l0=true。注意,這個參數只能在緊急時候使用,擴容完成後,務必記得恢復成默認值。
第三個問題是節點壓實操做(Compaction)堆積嚴重。大量的壓實堆積說明壓實跟不上,會產生大量小文件,影響讀性能。後面這兩張圖裏能夠明顯看到在LCS的小文件太多的時候,讀延遲大大增高。咱們找出的解決辦法,一個是調整compaction的速度,一個是調整兩個系統參數:sstable_preemptive_open_interval_in_mb,以及-Dcassandra.never_purge_tombstones。經過jstack查看線程的調用棧能夠判斷須要調整那個參數。另外注意,never_purge_tombstones也僅限緊急狀況下使用,壓實的堆積消除之後必須恢復原有的默認配置。
第四個問題是大Key的問題。前面的幾位嘉賓也提到單個partition太大的時候對性能和穩定性的影響。這個在Cassandra日誌裏會出現告警信息。解決的辦法是在業務裏改變表結構和使用方法。好比一個文件刪除記錄表,對於我的文件來講,某個文件下面的刪除記錄不會很大,可是對於公共文件,好比華爲手機上的鎖屏圖片,就會出現大Key問題,解決的辦法就是在業務裏增長判斷,若是是熱門文件,在刪除次數達到某個閾值後就再也不新增刪除記錄。再好比,若是記錄一個熱門電影的預定用戶,使用電影的resourceID做爲分區鍵,預定用戶的UserID做爲聚類鍵,當預定的用戶數達到千萬甚至上億級別,就必定會出現大Key問題。解決辦法就是使用額外的hash串將resourceID繼續離散,避免單個resourceID下的分區太大。
第五個問題是熱點Key問題。表如今短期內對同一個Key頻繁操做,會致使該節點的CPU和Load太高,影響其餘的請求,致使業務成功率降低。這個從右邊監控系統的截圖能夠看到,部分節點的CPU和負載都很是高。應急處理的方法,通常是經過toppartitions找到訪問量最大的partition key,在業務側加黑名單屏蔽這種熱Key。最終的解決方案是利用緩存來減少熱Key對數據庫的衝擊。
第六個是墓碑問題,這個我就不花太多時間說了。這方面必定要避免的就是短時間內若是有頻繁的刪除而且還有頻繁的讀操做的話,可能Cassandra並不適合這種場景。另外,做爲應急方案,能夠臨時減小gc_grace_seconds,以加速墓碑的物理清理回收時間。
第七個是壞盤致使的殭屍數據,這個你們能夠直接看一下圖示和源碼,由於個人時間有限。咱們的解決方案是若是你用的是自建的IDC機房,出現壞盤了,必須在gc_grace_seconds的週期內完成數據修復,或者直接replace掉出了壞盤的節點;固然,若是你的業務有條件上雲的話,這種壞盤發生的可能性要低不少。
第八個是基礎設施方面的網絡丟包問題。咱們現網當時出現的症狀是忽然時延大幅度增長,Cassandra驅動側出現大量的慢日誌信息。排查了集羣的資源利用和線程池都沒發現問題,可是咱們用getendpoints把慢查詢日誌涉及的分區鍵對應的副本節點打出來,發現都涉及到一個*.*.23.20的節點。後來果真發現這個節點的網卡出現了丟包的故障。修復了丟包故障後,業務時延恢復正常。
第九個是集羣節點規格不一致致使的節點負載不均。這個其實涉及Cassandra的一個優化,可是優化用得很差,也會帶來問題。由於Cassandra的Gossip交換的信息裏,會包含每一個副本節點的負載,負載越小,收到的請求就越多。若是你的節點的物理配置不均,會致使請求集中在高配的幾個節點上。這個對自建IDC的影響比較大。在雲上,你們的節點配置比較一致,會較少遇到這個問題。
第十個是操做系統的網絡調參。咱們這裏只列舉了一個。網絡參數不合理的症狀是數據遷移不會出錯,可是會卡死。在集羣擴容時,200GB的數據不是卡死,就是長達一兩天。在公有云上咱們發現把net.ipv4.tcp_sack (Selective ACK) 開啓,以後咱們200GB的數據遷移20分鐘就完成了。這個參數可以減少報文重傳的機率,在網絡擁塞或者亂序的狀況下會有很好的效果。
最後一個是JDK的STW (Stop The World)的問題。這個問題咱們到如今都尚未復現,咱們是經過把業務切到備用的DC,而後重啓故障DC的全部節點解決的。咱們是怎麼發現這個問題呢,當時業務的平均時延增高到3秒,可是系統CPU、IO、負載都正常,咱們也排查了集羣節點系統的各個核心參數,均沒有發現問題,可是注意到Hint大量出現,這說明數據在寫入過程當中,出現了大量的業務節點被短暫識別爲宕機狀態,引發Hint被記錄下來。經過查看Jstack和GC日誌,發現線程卡頓和STW常常長達10秒。
最後,咱們再來看看咱們總結出來的Cassandra最佳實踐。我這裏總結了幾點。
首先,須要管控業務使用場景,增強業務表結構的評審。無論你是用雲上的,仍是用自建IDC的,這個對你們都是有必定的借鑑意義的。咱們如今整個業務大概有幾百個利用Cassandra數據庫。咱們這個組如今負責在業務上線以前,對業務場景和表結構進行評審。咱們基於這樣一些方面的規範(咱們也叫「軍規」):主鍵設計合不合理,Schema約束,數據老化機制,單條數據頻繁更新/刪除,單條記錄過大,大面積數據刪除引起墓碑問題,集羣規模。咱們如今爲何會作到這麼大的量,是由於咱們管控了使用的場景,讓它必須按照咱們要求的來作。
而後,是構建完善的Cassandra集羣監控系統。咱們有不少方面的監控:第一個是主機級別的監控,包括CPU/IO/磁盤/內存;第二個是讀寫請求的監控,這個是從業務的角度來看請求量是多少;第三個是Cassandra內部核心線程監控,這個是Cassandra內部的一些顯微鏡級別的監控手段,必須可視化出來,不然的話現網幾萬臺機器,出了問題的話,你是沒有任何辦法能夠快速恢復的;第四個是集羣規模的監控,包括節點數和集羣統計量,告警,自動化部署相關的指標。
另外一個最佳實踐,就是使用Cassandra,必定要多看源碼,多熟練掌握nodetool各類命令和使用場景。Nodetool命令其實很是好用,這個只是列了一些咱們用得最多的,包括cleanup, compactionstats, getendpoints, netstats, rebuild, repair, toppartitions, tpstats, cfstats,我不在這裏一一說明,你們能夠看這個表。若是你在大規模應用中,須要快速的恢復,這些命令對於故障排查和恢復會很是有幫助。