1712745397
2024-04-09 08:09:53
プログラミングの最初のルールは何ですか? 「同じことを繰り返すな」とか「うまくいくなら触らないでください」といったところでしょうか。 あるいは、「独自のデータベースを作成しないでください!」はどうでしょうか…それは良いことです。
データベースを作成するのは悪夢であり、原子性、一貫性、分離性、耐久性 (ACID) 要件からシャーディング、障害回復、管理に至るまで、すべてが信じられないほど困難です。
幸いなことに、何十年にもわたって磨き上げられ、1 セントもかからない素晴らしいデータベースが存在します。 では、いったいなぜ私たちはゼロから何かを書くほど愚かなのでしょうか?
さて、ここからが問題です…
私たちは、数万の人と車両を同時に追跡するクラウド プラットフォームを実行しています。 すべての位置情報の更新は保存され、履歴 API を介して取得できます。
同時に接続される車両の数とその位置更新の頻度は時間の経過とともに大きく異なりますが、約 13,000 台の同時接続があり、それぞれが 1 秒あたり約 1 つの更新を送信するのはごく普通のことです。
当社の顧客はこのデータをさまざまな方法で使用します。 一部のユースケースは非常に大まかです。たとえば、レンタカー会社が顧客がその日に通ったルートの概要を表示したい場合です。 この種の要件は、1 時間の旅行であれば 30 ~ 100 の位置ポイントで処理でき、位置データを保存する前に高度に集約して圧縮することができます。
しかし、それができないユースケースは他にもたくさんあります。 配送会社は、事故に至るまでの正確な数秒を再現したいと考えています。 非常に正確なオンサイト位置トラッカーを備えた鉱山では、どの作業員がどの立ち入り禁止区域にわずか0.5メートルまで足を踏み入れたかのレポートを生成したいと考えています。
したがって、各顧客がどの程度の粒度を必要とするかが事前に分からないことを考慮して、位置情報の更新情報をすべて保存します。 13,000 台の車両では、毎月 35 億回のアップデートが行われることになりますが、その数は今後も増加する一方です。 これまで、地理空間データ ストレージ用に PostGIS 拡張機能を備えた AWS Aurora を使用してきました。 しかし、Aurora の料金はデータベースだけですでに月額 10,000 ドルを超えており、将来的にはさらに高くなるでしょう。
しかし、それは Aurora の価格だけの問題ではありません。 Aurora は負荷がかかっても十分に耐えられますが、多くのお客様はオンプレミス バージョンを使用しています。 そして、そこでは独自のデータベース クラスターを実行する必要があり、この量の更新によって容易に圧倒されてしまいます。
なぜ地理空間データ専用のデータベースを使用しないのでしょうか?
残念ながら、そのようなことはありません。 (もし存在していて、私たちが調査中に何らかの理由でそれを見落としたとしたら、 私にお知らせください)。 Mongo や H2 から Redis まで、多くのデータベースは、ポイントやエリアなどの空間データ タイプをサポートしています。 「空間データベース」もありますが、これらはもっぱら既存の DB の上に置かれる拡張機能です。 ポストGIS、PostgreSQL 上に構築されたものがおそらく最も有名なものですが、他にも次のようなものがあります。 ジオメサ 他のストレージ エンジンに加えて優れた地理空間クエリ機能を提供します。
残念ながら、それは私たちが必要としているものではありません。
要件プロファイルは次のようになります。
- 非常に高い書き込みパフォーマンス
ノードごとに 1 秒あたり最大 30,000 件の位置情報更新を処理できるようにしたいと考えています。 書き込み前にバッファリングできるため、IOPS の数値が大幅に低くなります。 - 無制限の並列処理
複数のノードが上限なしで同時にデータを書き込むことができる必要がある - ディスク上のサイズが小さい
データの量を考えると、ディスク上のスペースをできるだけ少なくする必要があります。
つまり、いくつかのトレードオフを受け入れる必要があります。 これで問題ないのは次のとおりです。
-
ディスクからの読み取りでは中程度のパフォーマンス
当社のサーバーはインメモリ アーキテクチャを中心に構築されています。 リアルタイム ストリームのクエリとフィルターはメモリ内のデータに対して実行されるため、結果として非常に高速になります。
ディスクからの読み取りは、新しいサーバーがオンラインになったとき、クライアントが履歴 API を使用したとき、または (近々) アプリ ユーザーがデジタル ツイン インターフェイスで時間を巻き戻すときにのみ発生します。 これらのディスク読み取りは、優れたユーザー エクスペリエンスを得るために十分な速度である必要がありますが、頻度は比較的低く、量も少ないです。 -
一貫性の保証が低い
多少のデータが失われても大丈夫です。 ディスクに書き込む前に、約 1 秒分の更新をバッファリングします。 サーバーがダウンして別のサーバーが引き継ぐというまれなケースでは、現在のバッファーにある 1 秒間の位置情報の更新が失われても問題ありません。
どのような種類のデータを保存する必要がありますか?
永続化する必要があるエンティティの主なタイプは「オブジェクト」で、基本的には車両、人、センサー、または機械です。 オブジェクトには、ID ラベル、位置、および燃料レベルや現在のライダー ID などの任意のキー/値データがあります。 位置情報は、経度、緯度の精度、速度、方位、高度、高度の精度で構成されますが、各更新で変更できるのはこれらのフィールドのサブセットのみです。
さらに、エリア、タスク (「オブジェクト」が実行しなければならないこと)、および命令 (受信データに基づいて Hivekit サーバーが実行する小さな空間ロジック) も保存する必要があります。
私たちが築いてきたもの
私たちは、コア サーバーと同じ実行可能ファイルの一部である、専用のインプロセス ストレージ エンジンを作成しました。 最小限のデルタベースのバイナリ形式を書き込みます。 単一のエントリは次のようになります。

各ブロックはバイトを表します。 「フラグ」というラベルの付いた 2 バイトは、「緯度がある」、「経度がある」、「データがある」などを指定する Yes/No スイッチのリストで、エントリの残りのバイトで何を探すかをパーサーに指示します。
200 回の書き込みごとにオブジェクトの完全な状態を保存します。 これらの間では、デルタのみが保存されます。 つまり、時刻、ID、緯度、経度を含む単一の位置情報の更新には 34 バイトしかかかりません。 これは、約 3,000 万件の位置情報更新を 1 ギガバイトのディスク領域に詰め込むことができることを意味します。
また、各エントリの静的文字列 ID とそのタイプ (オブジェクト、エリアなど) を一意の 4 バイトの識別子に変換する別のインデックス ファイルも維持します。 この固定サイズの識別子は常に各エントリのバイト インデックス 6 ~ 9 であることがわかっているため、特定のオブジェクトの履歴の取得は非常に高速になります。
結果: クラウド コストが 98% 削減され、すべてが高速化されました。
このストレージ エンジンはサーバー バイナリの一部であるため、実行コストは変わりません。 ただし、変わったのは、月額 10,000 ドルの Aurora インスタンスを月額 200 ドルの Elastic Block Storage (EBS) ボリュームに置き換えたことです。 3000 IOPS のプロビジョンド IOPS SSD (io2) を使用し、ノードおよびレルムごとに 1 秒あたり 1 回の書き込みにバッチ更新しています。
EBS には自動バックアップとリカバリが組み込まれており、高い稼働率が保証されているため、Aurora が提供する信頼性保証を逃しているとは感じません。 現在、毎月約 100 GB のデータを生成しています。 ただし、顧客が 10 日より古いエントリをクエリすることはほとんどないため、30 GB を超えるすべてのものを AWS Glacier に移動し始め、これにより EBS コストがさらに削減されます。
しかし、それはコストだけではありません。 ファイル システム経由でローカル EBS に書き込む方が、Aurora に書き込むよりもはるかに高速で、オーバーヘッドが低くなります。 クエリも大幅に高速化されました。 クエリは完全に類似しているわけではないため、定量化するのは困難ですが、たとえば、レルム履歴の特定の時点の再作成にかかる時間は、約 2 秒から約 13 ミリ秒に短縮されました。
もちろん、これは不公平な比較です。結局のところ、Postgres は表現力豊かなクエリ言語を備えた汎用データベースであり、私たちが構築したものは、非常に限られた機能セットを備えたバイナリ ファイル フィードをストリーミングする単なるカーソルです。しかし、繰り返しになりますが、必要な機能を正確に備えており、機能が失われることはありませんでした。
Hivekit の API と機能について詳しくは、以下をご覧ください。 https://hivekit.io/developers/
#独自のデータベースを作成することでクラウド #コストを #節約した方法