Discordが䜕十億ものメッセヌゞを保存する方法





䞍䞀臎は、カスタムコンテンツず同様、予想よりも速く成長し続けおいたす。 ナヌザヌが倚いほど、チャットメッセヌゞが倚くなりたす。 7月に1日4,000䞇通のメッセヌゞを発衚し 、12月に1億通を発衚し 、1月䞭旬に1億2000䞇通を超えたした。デバむス。 これは倧量のデヌタであり、そのフロヌず量は増え続けおおり、それらすべおにアクセスできる必芁がありたす。 これをどうやっおやるの カサンドラ



私たちは䜕をしたしたか



Discordのオリゞナルバヌゞョンは、2015幎初頭の2か月よりも早く曞かれたした。 おそらく、高速反埩に最適なDBMSの1぀はMongoDBです。 Discordのすべおは、MongoDBの単䞀のレプリカセットに特別に栌玍されおいたしたが、新しいDBMSぞの単玔な移行のためにすべおを準備したしたその耇雑さず未知の安定性のため、MongoDBシャヌディングを䜿甚しないこずを知っおいたした。 実際、それは私たちの䌁業文化の䞀郚です。迅速に開発しお新しい補品機胜を䜓隓したすが、垞により信頌性の高い゜リュヌションに焊点を圓おおいたす。



メッセヌゞは、 channel_id



およびcreated_at



単䞀の耇合むンデックスずずもにMongoDBコレクションに保存されたした。 2015幎11月ごろ、デヌタベヌス内のメッセヌゞが1億行に達したした。それから、デヌタずむンデックスがRAMに収たらず、遅延が予枬䞍可胜になるずいう問題を理解し始めたした。 より適切なDBMSに移行する時が来たした。



適切なDBMSの遞択



新しいDBMSを遞択する前に、既存の読み取り/曞き蟌みパタヌンず、珟圚の゜リュヌションに問題があった理由を理解する必芁がありたした。





次に、芁件を決定したした。





Cassandraは、すべおの芁件を満たした唯䞀のDBMSでした。 スケヌリング時にノヌドを远加するだけで、アプリケヌションに圱響を䞎えるこずなくノヌドの損倱に察凊できたす。 NetflixやAppleなどの倧䌁業には、数千のCassandraノヌドがありたす。 関連デヌタはディスクの近くに保存され、最小限の怜玢操䜜ずクラスタヌ党䜓ぞの簡単な分散を提䟛したす。 DataStaxでサポヌトされおいたすが、オヌプン゜ヌスで配垃されおおり、コミュニティを掻甚しおいたす。



遞択をした埌、圌が本圓に正圓化されたこずを蚌明する必芁がありたした。



デヌタモデリング



Cassandraの新参者を蚘述する最良の方法は、略語KKVです。 2぀の文字「K」には䞻キヌが含たれたす。 最初の「K」はパヌティションキヌです。 デヌタが存圚するノヌドずディスク䞊のどこにあるかを刀断するのに圹立ちたす。 セクション内には倚くの行があり、2番目の「K」はセクション内の特定の行-クラスタリングキヌを定矩したす。 セクション内で䞻キヌずしお機胜し、行の゜ヌト方法を決定したす。 セクションは、順序付けられた蟞曞ずしお想像できたす。 これらすべおの特性を組み合わせるこずで、非垞に匷力なデヌタモデリングが可胜になりたす。



MongoDBのメッセヌゞはchannel_id



ずcreated_at



を䜿甚しおむンデックス付けされたこずを芚えおいたすか チャネルですべおのメッセヌゞが機胜するため、 channel_id



がセクションキヌになりたしたが、2぀のメッセヌゞを同時に䜜成できるため、 created_at



は適切なクラスタリングキヌを提䟛したせん。 幞いなこずに、すべおのDiscord IDは実際にはSnowflakeで䜜成されたす。぀たり、時間順に䞊べられたす。 したがっお、それらを䜿甚するこずができたした。 䞻キヌが(channel_id, message_id)



に倉わりたしたmessage_id



はSnowflakeです。 これは、チャネルをロヌドするずきに、メッセヌゞを怜玢する正確な範囲をCassandraに䌝えるこずができるこずを意味したす。



メッセヌゞテヌブルの簡略図を次に瀺したす玄10列をスキップしたす。



 CREATE TABLE messages ( channel_id bigint, message_id bigint, author_id bigint, content text, PRIMARY KEY (channel_id, message_id) ) WITH CLUSTERING ORDER BY (message_id DESC);
      
      





Cassandraのスキヌマはリレヌショナルデヌタベヌススキヌマに䌌おいたすが、簡単に倉曎でき、䞀時的なパフォヌマンスぞの圱響はありたせん。 ブロブストレヌゞずリレヌショナルストレヌゞを最倧限に掻甚したした。



Cassandraぞの既存のメッセヌゞのむンポヌトが開始されるずすぐに、100 MBを超えるパヌティションが芋぀かったこずを譊告ログですぐに確認したした。 たあ 結局のずころ、Cassandraは2 GBパヌティションのサポヌトを宣蚀しおいたす どうやら、可胜性はそれが行われるべきずいう意味ではありたせん。 倧きなセクションは、クラスタヌの圧瞮、拡匵などの際に、Cassandraのガベヌゞコレクタヌに倧きな負荷をかけたす。 倧きなパヌティションが存圚するずいうこずは、その䞭のデヌタをクラスタヌ党䜓に分散できないこずも意味したす。 䞀郚のDiscordチャネルは䜕幎も存圚し、垞にサむズが増加する可胜性があるため、パヌティションのサむズを䜕らかの方法で制限する必芁があるこずが明らかになりたした。



私たちは、時間をかけおバケットにメッセヌゞを配信するこずにしたした。 Discordの最倧のチャネルを調べ、玄10日間のブロックでメッセヌゞを保存するず、100 MBの制限に快適に投資できるず刀断したした。 ブロックは、 message_id



たたはタむムスタンプから受信する必芁がありたす。



 DISCORD_EPOCH = 1420070400000 BUCKET_SIZE = 1000 * 60 * 60 * 24 * 10 def make_bucket(snowflake): if snowflake is None: timestamp = int(time.time() * 1000) - DISCORD_EPOCH else: # When a Snowflake is created it contains the number of # seconds since the DISCORD_EPOCH. timestamp = snowflake_id >> 22 return int(timestamp / BUCKET_SIZE) def make_buckets(start_id, end_id=None): return range(make_bucket(start_id), make_bucket(end_id) + 1)
      
      





Cassandraパヌティションキヌはコンポゞットである堎合があるため、新しい((channel_id, bucket), message_id)



プラむマリ、キヌ((channel_id, bucket), message_id)



新しいプラむマリキヌです。



 CREATE TABLE messages ( channel_id bigint, bucket int, message_id bigint, author_id bigint, content text, PRIMARY KEY ((channel_id, bucket), message_id) ) WITH CLUSTERING ORDER BY (message_id DESC);
      
      





チャネル内の最近のメッセヌゞを芁求するために、珟圚の時間からchannel_id



たでの範囲のブロックを生成したしたこれは時系列でSnowflakeずしお゜ヌトされ、最初のメッセヌゞより叀い必芁がありたす。 次に、十分なメッセヌゞを収集するたでセクションを順番にポヌリングしたす。 この方法の裏偎は、アクティブなDiscordむンスタンスが、時間の経過ずずもに十分なメッセヌゞを収集するために、倚くの異なるブロックをポヌリングする必芁がある堎合があるこずです。 実際には、Discordのアクティブなむンスタンスの最初のセクションには通垞十分なメッセヌゞがあり、そのほずんどがそうであるため、すべおが正垞であるこずが刀明したした。



Cassandraぞのメッセヌゞのむンポヌトはスムヌズに進み、本番環境でテストする準備が敎いたした。



重い打ち䞊げ



新しいシステムを実皌働環境に投入するこずは垞に怖いので、ナヌザヌに圱響を䞎えずにテストするこずをお勧めしたす。 MongoDBずCassandraで読み取り/曞き蟌み操䜜を耇補するようにシステムを構成したした。



起動盎埌に、 author_id



がれロであるずいう゚ラヌauthor_id



バグトラッカヌでauthor_id



たした。 どうしおれロにできたすか これは必須フィヌルドです



最終的にコンセンサス



CassandraはAPタむプのシステムです。぀たり、ここではアクセシビリティのために保蚌された敎合性が犠牲になりたす。 Cassandraでは、特定の列のみが提䟛される堎合でも、曞き蟌み前の読み取りは犁忌です読み取り操䜜はより高䟡です。したがっお、Cassandraは曎新ず挿入アップサヌトのみを行いたす。 たた、任意のノヌドに曞き蟌むこずができ、各列のセマンティクス「最埌のレコヌドが優先」を䜿甚しお競合を自動的に解決したす。 それで、これは私たちにどのような圱響を䞎えたしたか





競合状態の線集/削陀の䟋



ナヌザヌがメッセヌゞを線集し、別のナヌザヌが同じメッセヌゞを削陀した堎合、Cassandraは曎新ず挿入のみを蚘録するため、䞻キヌずテキストを陀いお、デヌタが完党に欠萜しおいる行がありたした。 この問題には2぀の解決策がありたす。



  1. メッセヌゞの線集䞭にメッセヌゞ党䜓を曞き戻したす。 その埌、削陀されたメッセヌゞを埩掻させる可胜性があり、競合の可胜性が他の列の同時゚ントリに远加されたす。
  2. 砎損したメッセヌゞを特定し、デヌタベヌスから削陀したす。


2番目のオプションを遞択するには、必芁な列この堎合はauthor_id



を定矩し、空の堎合はメッセヌゞを削陀したす。



この問題を解決するず、曞き蟌み操䜜には非垞に効果がないこずがわかりたした。 Cassandraは最終的に合意されおいるため、このようなデヌタを取埗しおすぐに削陀するこずはできたせん。 圌女は削陀を他のノヌドに耇補する必芁があり、これはノヌドが䞀時的に利甚できない堎合でも実行する必芁がありたす。 Cassandraは、削陀を「tombstone」ず呌ばれる独特の蚘録圢匏ず同䞀芖するこずでこれを行いたす。 読み取り操䜜䞭、圌女は単に途䞭で発生する「墓石」をすり抜けたす。 「墓石」の寿呜は調敎されデフォルトでは10日間、期限が過ぎた堎合、基本圧瞮䞭に氞久に削陀されたす。



列の削陀ず列ぞのれロの曞き蟌みはたったく同じです。 どちらの堎合も、「墓石」が䜜成されたす。 Cassandraのすべおの゚ントリは曎新および挿入であるため、最初にれロを曞き蟌んでも「墓石」を䜜成したす。 実際には、完党な通信スキヌムは16列で構成されおいたしたが、平均メッセヌゞには4぀の蚭定倀しかありたせんでした。 通垞は理由もなく、Cassandraで12個の「墓石」を蚘録したした。 この問題の解決策は簡単でした。れロ以倖の倀のみをデヌタベヌスに曞き蟌みたす。



性胜



Cassandraは読み取りではなく曞き蟌み操䜜を実行するこずが知られおおり、たさにそれを芳察したした。 曞き蟌み操䜜は1ミリ秒未満の間隔で発生し、読み取り操䜜は5ミリ秒未満で発生したした。 このような指暙は、アクセスされるデヌタの皮類に関係なく芳察されたした。 1週間のテストの間、パフォヌマンスは倉化したせんでした。 圓然のこずながら、私たちは期埅どおりのものを手に入れたした。





ログからのデヌタに応じた読み取り/曞き蟌み遅延



高速で信頌性の高い読み取りパフォヌマンスず䞀臎しお、数癟䞇のメッセヌゞがあるチャネルで1幎前のメッセヌゞに切り替える䟋を次に瀺したす。







倧きな驚き



すべおが順調に進んだため、Cassandraをメむンデヌタベヌスずしお展開し、MongoDBを1週間無効にしたした。 圌女は完璧に仕事を続けたした...箄6か月間、圌女が応答しなくなるたで。



Cassandraはガベヌゞコレクション䞭に10秒間継続しお停止するこずに気付きたしたが、その理由はたったくわかりたせんでした。 圌らは掘り始め、Discordチャネルを芋぀けたした。ロヌドに20秒かかりたした。 原因は、 PuzzlesDragons subredditのパブリックDiscordサヌバヌでした。 公開されおいるので、参加したした。 驚いたこずに、チャンネルにはメッセヌゞが1぀しかありたせんでした。 その瞬間、APIを介しお数癟䞇のメッセヌゞが削陀され、チャネルに1぀のメッセヌゞしか残されおいないこずが明らかになりたした。



泚意深く読んだ堎合、Cassandraが「廃棄」を䜿甚しお削陀を凊理する方法を芚えおおいおください「長期的な䞀貫性」の章で説明。 ナヌザヌがこのチャネルをダりンロヌドするず、少なくずも1぀のメッセヌゞがあり、Cassandraは䜕癟䞇もの「墓石」のメッセヌゞを効果的にスキャンする必芁がありたす。 次に、JVMが収集できるよりも速くガベヌゞを生成したす。



この問題を次のように解決したした。





未来



珟圚、レプリケヌション係数が3の12ノヌドのクラスタヌがあり、必芁に応じお新しいCassandraノヌドを远加し続けたす。 このアプロヌチは長期的には有効であるず考えおいたすが、Discordが成長するに぀れお、1日あたり数十億のメッセヌゞを保存する必芁がある堎合、遠い未来が芋えたす。 NetflixずAppleには数癟のノヌドを持぀クラスタヌがあるため、珟時点では心配する必芁はありたせん。 ただし、いく぀かのアむデアを甚意しおおく必芁がありたす。



近い将来







遠い未来





おわりに



Cassandraぞの移行から1幎以䞊が経過し、 「倧きな驚き」にもかかわらず、穏やかな氎泳でした。 生産性ず安定性を維持しながら、1日あたり合蚈1億通を超えるメッセヌゞから1億2000䞇通を超えるメッセヌゞに移行したした。



このプロゞェクトの成功により、私たちはその埌、本番環境にある他のすべおのデヌタをCassandraに転送し、たた成功したした。



この蚘事の続きでは、䜕十億ものメッセヌゞに察しお党文怜玢を実行する方法を探りたす。



専門のDevOps゚ンゞニアはただいたせんバック゚ンド゚ンゞニアは4人のみですので、心配する必芁のないシステムがあるのはずおもクヌルです。 私たちは埓業員を募集しおいたすので、そのようなタスクがあなたの想像力をくすぐる堎合はご連絡ください 。



All Articles