最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Discord如何存儲(chǔ)萬億級(jí)消息

2023-07-28 12:41 作者:睡不醒的Pounds  | 我要投稿

作者:Discord 高級(jí)軟件工程師 Bo Ingram

2023.03.06

2017 年,我們撰寫了一篇關(guān)于如何存儲(chǔ)數(shù)十億條消息的博文。 我們分享了我們?nèi)绾伍_始使用 MongoDB,但后來將數(shù)據(jù)遷移到 Cassandra,因?yàn)槲覀冋趯ふ乙粋€(gè)可擴(kuò)展、容錯(cuò)且維護(hù)成本相對(duì)較低的數(shù)據(jù)庫。 我們知道我們會(huì)成長(zhǎng),而且我們確實(shí)做到了!

?

我們想要一個(gè)與我們一起成長(zhǎng)的數(shù)據(jù)庫,但希望它的維護(hù)需求不會(huì)隨著我們的存儲(chǔ)需求而增長(zhǎng)。 不幸的是,我們發(fā)現(xiàn)事實(shí)并非如此——我們的 Cassandra 集群出現(xiàn)了嚴(yán)重的性能問題,需要付出越來越多的努力來維護(hù),而不是改進(jìn)。

?

大約六年后,我們發(fā)生了很多變化,我們存儲(chǔ)消息的方式也發(fā)生了變化。


我們的 Cassandra 麻煩

我們將消息存儲(chǔ)在名為 cassandra-messages 的數(shù)據(jù)庫中。 顧名思義,它運(yùn)行 Cassandra,并存儲(chǔ)消息。 2017 年,我們運(yùn)行了 12 個(gè) Cassandra 節(jié)點(diǎn),存儲(chǔ)了數(shù)十億條消息。

?

2022 年初,它有 177 個(gè)節(jié)點(diǎn),擁有數(shù)萬億條消息。 令我們懊惱的是,這是一個(gè)高勞累的系統(tǒng)——我們的待命團(tuán)隊(duì)經(jīng)常因數(shù)據(jù)庫問題而被傳呼,延遲是不可預(yù)測(cè)的,而且我們不得不減少維護(hù)操作,因?yàn)檫\(yùn)行成本太高。

?

是什么導(dǎo)致了這些問題? 首先,我們來看一條消息。

?


上面的 CQL 語句是消息模型的最小版本。 我們使用的每個(gè) ID 都是雪花,使其可以按時(shí)間順序排序。 我們根據(jù)消息發(fā)送的頻道以及存儲(chǔ)桶(靜態(tài)時(shí)間窗口)對(duì)消息進(jìn)行分區(qū)。 這種分區(qū)意味著,在 Cassandra 中,給定頻道和存儲(chǔ)桶的所有消息將存儲(chǔ)在一起并跨三個(gè)節(jié)點(diǎn)進(jìn)行復(fù)制。(根據(jù)您設(shè)置的復(fù)制因子/ replica factor)

?

這種分區(qū)存在一個(gè)潛在的性能缺陷:只有一小群朋友的服務(wù)器發(fā)送的消息往往比擁有數(shù)十萬人的服務(wù)器少幾個(gè)數(shù)量級(jí)。

?

在 Cassandra 中,讀取比寫入更昂貴。 寫入會(huì)附加到提交日志并寫入稱為內(nèi)存表的內(nèi)存結(jié)構(gòu),最終刷新到磁盤。 然而,讀取需要查詢 memtable 和可能的多個(gè) SSTable(磁盤文件),這是一個(gè)更昂貴的操作。 用戶與服務(wù)器交互時(shí)的大量并發(fā)讀取可以使分區(qū)成為熱點(diǎn),我們想象中將其稱為“熱分區(qū)”。 當(dāng)數(shù)據(jù)集的大小與這些訪問模式相結(jié)合時(shí),將導(dǎo)致我們的集群陷入困境。

?

當(dāng)我們遇到熱分區(qū)時(shí),它經(jīng)常會(huì)影響整個(gè)數(shù)據(jù)庫集群的延遲。 一個(gè)頻道于存儲(chǔ)桶對(duì) 接收了大量流量,并且隨著節(jié)點(diǎn)越來越努力地服務(wù)流量并且越來越落后,節(jié)點(diǎn)中的延遲將會(huì)增加。

?

由于該節(jié)點(diǎn)無法跟上請(qǐng)求,對(duì)該節(jié)點(diǎn)的其他查詢也會(huì)受到影響。 由于我們以仲裁一致性 (quorum consistency) 級(jí)別執(zhí)行讀取和寫入,因此對(duì)服務(wù)熱分區(qū)的節(jié)點(diǎn)的所有查詢都會(huì)遭受延遲增加,從而導(dǎo)致更廣泛的最終用戶影響。

?

集群維護(hù)任務(wù)也經(jīng)常造成麻煩。 我們很容易在壓縮方面落后,Cassandra 會(huì)壓縮磁盤上的 SSTable 以提高讀取性能。 不僅我們的讀取成本更高,而且當(dāng)節(jié)點(diǎn)試圖壓縮時(shí),我們還會(huì)看到級(jí)聯(lián)延遲。

?

我們經(jīng)常執(zhí)行一種稱為“流言舞”的操作,其中我們將一個(gè)節(jié)點(diǎn)取出,使其在不占用流量的情況下進(jìn)行壓縮,然后將其放回以從 Cassandra 的提示切換中獲取提示,然后重復(fù)直到積壓的壓縮任務(wù)完成。 我們還花費(fèi)了大量時(shí)間調(diào)整 JVM 的垃圾收集器和堆設(shè)置,因?yàn)?GC 暫停會(huì)導(dǎo)致顯著的延遲峰值。

?

改變我們的架構(gòu)

我們的消息集群并不是唯一的 Cassandra 數(shù)據(jù)庫。 我們還有其他幾個(gè)集群,每個(gè)集群都表現(xiàn)出類似(盡管可能不那么嚴(yán)重)的故障。

?

在本文的上一次迭代中,我們提到對(duì) ScyllaDB 很感興趣,這是一個(gè)用 C++ 編寫的與 Cassandra 兼容的數(shù)據(jù)庫。 它承諾提供更好的性能、更快的修復(fù)、通過按核分片架構(gòu)實(shí)現(xiàn)更強(qiáng)的工作負(fù)載隔離,以及無垃圾收集的生活,聽起來相當(dāng)吸引人。

?

盡管 ScyllaDB 絕對(duì)不是沒有問題,但它沒有垃圾收集器,因?yàn)樗怯?C++ 而不是 Java 編寫的。 從歷史上看,我們的團(tuán)隊(duì)在 Cassandra 上的垃圾收集器方面遇到過許多問題,從影響延遲的 GC 暫停,一直到超長(zhǎng)的連續(xù) GC 暫停,情況非常糟糕,以至于操作員必須手動(dòng)重新啟動(dòng)并將有問題的節(jié)點(diǎn)恢復(fù)到原來的狀態(tài)。 這些問題是待命工作的一大夢(mèng)魘,也是我們消息集群中許多穩(wěn)定性問題的根源。

?

在探索 ScyllaDB 并觀察測(cè)試中的性能提升后,我們決定遷移所有數(shù)據(jù)庫。 雖然這一決定本身就可以寫一篇博客文章,但簡(jiǎn)短的版本是,到 2020 年,我們已經(jīng)將除一個(gè)數(shù)據(jù)庫之外的所有數(shù)據(jù)庫遷移到了 ScyllaDB。

?

最后一個(gè)? 我們的朋友,cassandra-message。

?

為什么我們還沒有遷移它? 首先,它是一個(gè)大集群。 由于有數(shù)萬億條消息和近 200 個(gè)節(jié)點(diǎn),任何遷移都將是一項(xiàng)復(fù)雜的工作。 此外,我們希望確保我們的新數(shù)據(jù)庫在我們努力調(diào)整其性能的同時(shí)能夠達(dá)到最佳狀態(tài)。 我們還希望在生產(chǎn)中獲得更多使用 ScyllaDB 的經(jīng)驗(yàn),狠狠地使用它并了解它的陷阱。

?

我們還致力于提高 ScyllaDB 用例的性能。 在我們的測(cè)試中,我們發(fā)現(xiàn)反向查詢的性能不足以滿足我們的需求。 當(dāng)我們嘗試以與表排序相反的順序掃描數(shù)據(jù)庫時(shí),例如當(dāng)我們以升序掃描消息時(shí),我們會(huì)執(zhí)行反向查詢。 ScyllaDB 團(tuán)隊(duì)優(yōu)先考慮改進(jìn)并實(shí)現(xiàn)了高性能反向查詢,消除了我們遷移計(jì)劃中的最后一個(gè)數(shù)據(jù)庫障礙。

?

我們懷疑在我們的系統(tǒng)上安裝一個(gè)新數(shù)據(jù)庫并不會(huì)讓一切都神奇地變得更好。 熱分區(qū)仍然是 ScyllaDB 中的一個(gè)問題,因此我們還希望投入精力改進(jìn)數(shù)據(jù)庫上游的系統(tǒng),以幫助保護(hù)和促進(jìn)更好的數(shù)據(jù)庫性能。

?

數(shù)據(jù)服務(wù)服務(wù)數(shù)據(jù)

對(duì)于 Cassandra,我們?cè)跓岱謪^(qū)方面遇到了困難。 給定分區(qū)的高流量會(huì)導(dǎo)致無限并發(fā),從而導(dǎo)致級(jí)聯(lián)延遲,其中后續(xù)查詢的延遲將繼續(xù)增長(zhǎng)。 如果我們能夠控制熱分區(qū)的并發(fā)流量,我們就可以保護(hù)數(shù)據(jù)庫不被淹沒。

?

為了完成這項(xiàng)任務(wù),我們編寫了所謂的數(shù)據(jù)服務(wù)(data service) —— 位于 API和數(shù)據(jù)庫集群之間的中間服務(wù)。 在編寫數(shù)據(jù)服務(wù)時(shí),我們選擇了一種在 Discord 中越來越多地使用的語言:Rust! 我們之前在幾個(gè)項(xiàng)目中使用過它,它也沒有辜負(fù)我們的期許。 它為我們提供了與C/C++ 一樣的速度,而無需犧牲安全性。

?

Rust 將無所畏懼的并發(fā)性視為其主要優(yōu)點(diǎn)之一——該語言應(yīng)該讓編寫安全、并發(fā)的代碼變得容易。 它的庫也非常適合我們想要實(shí)現(xiàn)的目標(biāo)。 Tokio 生態(tài)系統(tǒng)是構(gòu)建異步 I/O 系統(tǒng)的巨大基礎(chǔ),并且該語言為 Cassandra 和 ScyllaDB 提供驅(qū)動(dòng)程序支持。

?

此外,我們發(fā)現(xiàn)在編譯器的幫助、錯(cuò)誤消息的清晰度、語言結(jié)構(gòu)及其對(duì)安全性的強(qiáng)調(diào)下進(jìn)行編碼是一種樂趣。 我們非常喜歡它一旦編譯后就可以正常工作的方式。 而且,最重要的是,它讓我們可以說我們用 Rust 重寫了它?。╩eme信譽(yù)非常重要, Rust yyds)。

?

我們的數(shù)據(jù)服務(wù)位于 API 和 ScyllaDB 集群之間。 它們每個(gè)數(shù)據(jù)庫查詢大約包含一個(gè) gRPC 端點(diǎn),并且故意不包含任何業(yè)務(wù)邏輯。 我們的數(shù)據(jù)服務(wù)提供的一大功能是請(qǐng)求合并。 如果多個(gè)用戶同時(shí)請(qǐng)求同一行,我們只會(huì)查詢數(shù)據(jù)庫一次。 第一個(gè)發(fā)出請(qǐng)求的用戶會(huì)觸發(fā)worker啟動(dòng)工作任務(wù)。 后續(xù)請(qǐng)求將檢查該任務(wù)是否存在并訂閱它。 該工作任務(wù)將查詢數(shù)據(jù)庫并將該行返回給所有訂閱者。

?

這就是 Rust 的強(qiáng)大之處:它讓編寫安全的并發(fā)代碼變得容易。


讓我們想象一下大型服務(wù)器上有一個(gè)重大公告,通知@everyone:用戶將打開應(yīng)用程序并閱讀消息,向數(shù)據(jù)庫發(fā)送大量流量。 以前,這可能會(huì)導(dǎo)致熱分區(qū),并且待命的工程師可能需要進(jìn)行分頁以幫助系統(tǒng)恢復(fù)。 借助我們的數(shù)據(jù)服務(wù),我們能夠顯著減少數(shù)據(jù)庫的流量峰值。

?

這里神奇的第二部分是我們數(shù)據(jù)服務(wù)的上游。 我們對(duì)數(shù)據(jù)服務(wù)實(shí)施了基于一致性哈希的路由,以實(shí)現(xiàn)更有效的合并。 對(duì)于對(duì)我們數(shù)據(jù)服務(wù)的每個(gè)請(qǐng)求,我們提供一個(gè)路由密鑰。 對(duì)于消息,這是一個(gè)頻道 ID,因此同一頻道的所有請(qǐng)求都會(huì)發(fā)送到同一服務(wù)實(shí)例。 此路由進(jìn)一步有助于減少數(shù)據(jù)庫的負(fù)載。

?

這些改進(jìn)有很大幫助,但并不能解決我們所有的問題。 我們?nèi)匀豢吹?Cassandra 集群上出現(xiàn)熱分區(qū)和延遲增加,只是頻率不那么高。 它為我們贏得了一些時(shí)間,以便我們可以準(zhǔn)備新的最佳 ScyllaDB 集群并執(zhí)行遷移。

?

一次非常大的遷徙

我們對(duì)遷移的要求非常簡(jiǎn)單:我們需要在不停機(jī)的情況下遷移數(shù)萬億條消息,并且需要快速完成,因?yàn)殡m然 Cassandra 的情況有所改善,但我們經(jīng)常需要救火。

?

第一步很簡(jiǎn)單:我們使用我們的超級(jí)磁盤存儲(chǔ)拓?fù)渑渲靡粋€(gè)新的 ScyllaDB 集群。 通過使用本地 SSD 提高速度并利用 RAID 將數(shù)據(jù)鏡像到持久化磁盤,我們本地SSD的速度和以及永久磁盤的持久性。 集群?jiǎn)?dòng)后,我們可以開始將數(shù)據(jù)遷移到其中。

?

我們的遷移計(jì)劃的初稿旨在迅速實(shí)現(xiàn)價(jià)值。我們將從一個(gè)切換時(shí)間開始,使用我們嶄新的 ScyllaDB 集群處理較新的數(shù)據(jù),然后在其后遷移歷史數(shù)據(jù)。這增加了更多的復(fù)雜性,但是每一個(gè)大型項(xiàng)目需要的就是額外的復(fù)雜性,對(duì)吧?

?

我們開始將新數(shù)據(jù)雙重寫入 Cassandra 和 ScyllaDB,同時(shí)開始配置 ScyllaDB 的 Spark 遷移器。 它需要大量的調(diào)整,一旦完成設(shè)置,我們預(yù)計(jì)完成時(shí)間:三個(gè)月。

?

這個(gè)時(shí)間范圍并沒有讓我們感到溫暖更多地是混亂/迷惑,我們希望更快地獲得價(jià)值。 我們作為一個(gè)團(tuán)隊(duì)坐下來,集思廣益,討論加快速度的方法,直到我們記得我們已經(jīng)編寫了一個(gè)可以擴(kuò)展的快速且高性能的數(shù)據(jù)庫lib。 我們選擇從事一些 meme 驅(qū)動(dòng)的工程并用 Rust 重寫數(shù)據(jù)遷移器。

?

一個(gè)下午,我們擴(kuò)展了我們的數(shù)據(jù)服務(wù)lib來進(jìn)行大規(guī)模的數(shù)據(jù)遷移。 它從數(shù)據(jù)庫讀取令牌范圍,通過 SQLite 在本地對(duì)它們?cè)O(shè)置檢查點(diǎn) (Checkpoint) ,然后將它們傳輸?shù)?ScyllaDB。 我們連接了新的,改進(jìn)的遷移器并得到了新的預(yù)估時(shí)間:九天! 如果我們能夠如此快速地遷移數(shù)據(jù),那么我們就可以忘記復(fù)雜的基于時(shí)間的方法,而是立即替換所有內(nèi)容。

?

我們將其打開并保持運(yùn)行,以高達(dá)每秒 320 萬條的速度遷移消息。 幾天后,我們聚在一起看著它達(dá)到 100%,然后我們意識(shí)到它已經(jīng)完成了 99.9999%(不,是真的)。 我們的遷移器在讀取最后幾個(gè)令牌范圍的數(shù)據(jù)時(shí)超時(shí),因?yàn)樗鼈儼瑥奈丛?Cassandra 中壓縮的巨大墓碑范圍。 我們壓縮該令牌范圍,幾秒鐘后,遷移完成了!

?

我們通過向兩個(gè)數(shù)據(jù)庫發(fā)送一小部分讀取數(shù)據(jù)并比較結(jié)果來執(zhí)行自動(dòng)數(shù)據(jù)驗(yàn)證,一切看起來都很棒。 該集群在滿生產(chǎn)流量的情況下運(yùn)行良好,而 Cassandra 則遇到了越來越頻繁的延遲問題。 我們?cè)诂F(xiàn)場(chǎng)的團(tuán)隊(duì)聚集在一起,按下開關(guān)將 ScyllaDB 轉(zhuǎn)換為主數(shù)據(jù)庫,并吃了慶祝蛋糕!

?

幾個(gè)月后……

我們于 2022 年 5 月切換了消息數(shù)據(jù)庫,但此后它的表現(xiàn)如何?

?

這是一個(gè)安靜、運(yùn)行良好的數(shù)據(jù)庫(因?yàn)槲疫@周沒有值班)。 我們不會(huì)進(jìn)行橫跨整個(gè)周末的救火,也不會(huì)在集群中調(diào)整節(jié)點(diǎn)以試圖保持正常運(yùn)行時(shí)間。 這是一個(gè)更高效的數(shù)據(jù)庫——我們將從運(yùn)行 177 個(gè) Cassandra 節(jié)點(diǎn)減少到僅運(yùn)行 72 個(gè) ScyllaDB 節(jié)點(diǎn)。 每個(gè) ScyllaDB 節(jié)點(diǎn)擁有 9 TB 磁盤空間,高于每個(gè) Cassandra 節(jié)點(diǎn)平均 4 TB 的磁盤空間。

?

我們的尾部延遲也顯著改善。 例如,在 Cassandra 上獲取歷史消息的 p99 為 40-125 毫秒,而 ScyllaDB 的延遲為 15 毫秒,消息插入性能從 Cassandra 上的 5-70 毫秒 p99 到 ScyllaDB 上穩(wěn)定的 5 毫秒 p99。 由于上述性能改進(jìn),我們現(xiàn)在對(duì)我們的消息數(shù)據(jù)庫充滿信心,已經(jīng)解鎖了新的產(chǎn)品用例。

?

2022年底,全世界的人們都收看世界杯。 我們很快發(fā)現(xiàn)的一件事是進(jìn)球數(shù)顯示在我們的監(jiān)控圖表中。 這非???,因?yàn)椴粌H可以在系統(tǒng)中看到真實(shí)世界的事件,而且這給了我們的團(tuán)隊(duì)一個(gè)在會(huì)議期間觀看足球比賽的借口。 我們不是“在會(huì)議期間看足球”,而是“主動(dòng)監(jiān)控系統(tǒng)的性能”。

?

我們實(shí)際上可以通過消息發(fā)送圖來講述世界杯決賽的故事。 這場(chǎng)比賽非常精彩。 萊昂內(nèi)爾·梅西(Lionel Messi) 試圖完成他職業(yè)生涯中的最后一項(xiàng)成就,鞏固自己作為有史以來最偉大球員的地位,并帶領(lǐng)阿根廷隊(duì)奪得冠軍,但才華橫溢的基利安·姆巴佩(Kylian Mbappe)和法國(guó)隊(duì)擋在了他的路上。

?

該圖中的九個(gè)尖峰中的每一個(gè)都代表比賽中的一個(gè)事件。

  1. 梅西主罰命中,阿根廷1-0領(lǐng)先。

  2. 阿根廷再次進(jìn)球,2-0領(lǐng)先。

  3. 現(xiàn)在是中場(chǎng)休息。 當(dāng)用戶談?wù)撨@場(chǎng)比賽時(shí),會(huì)出現(xiàn)持續(xù)十五分鐘的停滯狀態(tài)。

  4. 這里最大的亮點(diǎn)是因?yàn)槟钒团鍨榉▏?guó)隊(duì)進(jìn)球,并在 90 秒后再次進(jìn)球?qū)⒈确肿菲剑?/p>

  5. 常規(guī)賽結(jié)束了,這場(chǎng)大型比賽將進(jìn)入加時(shí)賽。

  6. 加時(shí)賽上半場(chǎng)沒有發(fā)生太多事情,但我們到了中場(chǎng)休息,用戶們正在聊天。

  7. 梅西再次進(jìn)球,阿根廷取得領(lǐng)先!

  8. 姆巴佩反擊扳平比分!

  9. 加時(shí)賽結(jié)束,我們進(jìn)入點(diǎn)球大戰(zhàn)!

  10. 點(diǎn)球大戰(zhàn)中,興奮和壓力不斷增加,直到法國(guó)隊(duì)錯(cuò)失而阿根廷隊(duì)錯(cuò)失! 阿根廷獲勝!

每秒消息的合并數(shù)

全世界的人們都在觀看這場(chǎng)令人難以置信的比賽,但與此同時(shí),Discord 和消息數(shù)據(jù)庫毫無波動(dòng)。 我們?cè)谙l(fā)送和處理方面已經(jīng)取得了很大進(jìn)展。 借助我們基于 Rust 的數(shù)據(jù)服務(wù)和 ScyllaDB,我們能夠承擔(dān)這樣巨大的流量并為用戶提供交流平臺(tái)。

?

我們構(gòu)建了一個(gè)可以處理數(shù)萬億條消息的系統(tǒng),如果這項(xiàng)工作讓您興奮,請(qǐng)查看我們的career page。 我們正在招聘!

Discord如何存儲(chǔ)萬億級(jí)消息的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
蒙山县| 安丘市| 铅山县| 昭觉县| 恭城| 土默特左旗| 沿河| 工布江达县| 高州市| 曲松县| 朔州市| 萝北县| 临沭县| 武夷山市| 雷州市| 莎车县| 河间市| 高唐县| 吴旗县| 衡东县| 富民县| 承德市| 富裕县| 舞钢市| 青川县| 凤山县| 东乌| 内乡县| 桑植县| 朝阳区| 酒泉市| 若羌县| 宾川县| 巢湖市| 二连浩特市| 浮山县| 潜江市| 昔阳县| 宿松县| 东乡族自治县| 台东市|