web-dev-qa-db-ja.com

ビッグデータの取り扱い

毎秒2000行の新しい行が挿入されるMySQLデータベースがあります。これらの行は、その特定の時点でのセンサーの値を示します。

計画は、chart.jsを使用してこのデータをグラフィカルな表現にすることです。もちろん、すべてのデータポイントを表示しても意味がなく、非常に遅いクエリになります。

私の質問は、このような状況でとるべき適切なルートは何ですか?これが私の考えです:

必要なデータ解決は、その日の1分間隔、15分間隔、30分間隔、1時間間隔、および1日の値の移動平均であると想定しています。

  1. 2つの期間の間に利用可能な値を解析するcronジョブスクリプトを作成します。上記の間隔を、生の値とは別のデータベースの5個の各テーブルに保存します。
  2. Cron-jobスクリプトが平均化ジョブを実行して間隔の値を決定するときに、本番データベースから生の値をパージ/アーカイブします。

このアプローチを使用すると、整頓された状態を保つことができ、データをグラフィカルな表現で簡単に表示できます。ここに問題が表示されます:

  1. チャートをフィルタリングして先月の日の値を確認する場合、表示する値について31のテーブルをチェックする必要があります。
  2. 解像度が小さくなり、期間が長くなると、問題は指数関数的に増加します。

うさぎの穴が深すぎるかもしれません。私はあなたが持っているかもしれないどんな良い読みもします。

2
Sami A

Yurセットアップのいくつかの提案

DBセットアップ

1)一時(ステージング)テーブルを使用して、新しいレコードを収集します。できれば、 insert timestamp を使用して、このテーブルをrangeパーティションに最も細かい集計間隔(分など)で分割する必要があります。測定のタイムスタンプ(センサータイムスタンプと呼ばれる)とは逆のタイムスタンプを挿入することは、区別することが重要です。以下の説明を参照してください。

2)詳細テーブルを、パーティションキーとして使用する同じパーティションスキーマで定義しますセンサータイムスタンプ

3)定義集約テーブルが必要であり、センサータイムスタンプで分割されます。必要なレベルを注意深く確認してください。これは要求されたレポートでは定義されていませんが、パフォーマンスを使用してデータを収集できます。

例えば。 30分のレベルは、 15分のレベルから効果的にクエリできるため、やりすぎのようです。

処理中

1分に1回実行されるバックグラウンドジョブは、開始テーブルの1つのパーティションを処理します(つまり、1分 delta )および

  • 詳細テーブルにすべての行を挿入します

  • ステージテーブルから計算された delta ですべての集計テーブルを更新します

    ここでは注意が必要です。カウント、合計、平均は問題ありませんが、distinctカウントの場合、推定データのみを生成する HyperLogLog の実装を使用する必要があります。

遅延したデータエントリを処理する必要があるかどうかも確認する必要があります。つまり、 delta にも古いセンサーのタイムスタンプ。これらのタイムスタンプに関連するすべての集約間隔を refresh する必要があります。

例:10:01に挿入されたプロセスデータでは、oldes sensortエントリは09:59であるため、3分の集約(09:59、10:00および10:01)および2つの15分の集約(9:45および10:00)など.

毎日の締めくくり

delta 処理の不正確性に対処するために(上記のHyperLogLogを参照。ただし、他のすべての種類を含む)、定期的に集計の最後の部分を削除し、詳細テーブルから正確に再計算できます。

これにより、「エラーの蓄積」の問題が解消されます。この概念は Lambdaアーキテクチャ とも呼ばれます。

履歴を保持

すべてのテーブルには、ローリングウィンドウポリシー、つまりデータが保持される期間が定義されています。

集約されたテーブルは、レポート要件によって制御されます

詳細テーブルは、 backup として孤独に使用されています。何か問題が発生した場合、集約されたデータを回復する可能性が(限定的に)あります。したがって、経済的に十分意味のある限り設定してください。

古いデータはDROP PARTITIONのみを使用して削除されます(削除は不可)

開始テーブルに cycle パーティショニングを適用できます。つまり、日付コンポーネントではなく、時間のみをパーティションキーとして使用します。これにより、パーティションのメンテナンスが簡略化されます。代わりにTRUNCATE PARTITIONを使用してデータを削除します。

レポート

集計は毎分1回行われます。これは、ロウズ集計が常に一貫していることを意味します。反対に、最後の15分の集計は、 incomplete になり、数分のデータしか含まれません。

この問題を処理するには、 normalizing の概念を設計する必要があります。 Nice ではありません。 successfullイベントの数が1時間の最後の四半期に大幅に減少したことを確認してください。

幸運を!

2
Marmite Bomber

私が目にする主な問題:

  • 詳細データを含むテーブルのサイズ。年間2〜3テラバイトかかるようです
  • 1秒あたり2000行の取り込み速度。 SSDドライブを使用していますか?
  • 「古い」データのパージ-大きなDELETEsは大きなコストです。

そう...

  1. すべてのデータをデータベースに保存しないでください。あなたはそれを必要としません。実際に保持する必要がある場合は、代わりにプレーンファイルに書き込みます。
  2. 毎分120000の測定値をどこか(後で)収集し、要約して、テーブルに保存します。 (さらに多くの詳細情報を提供する場合は、詳細情報を提供します-異なるセンサーの数や各センサーの読み取り頻度など)
  3. これで、ドットがで満足するグラフの準備が整いました。 (適切な粒度ですか?)必要に応じて、「分」を他の何かに調整します(ステップ2で)。
  4. 同時に、1つまたは2つのテーブル-おそらく1時間と1日の解像度。あなたは多くを必要としません。 15分ごとにドットが必要な場合は、1分の解像度テーブルを使用して適切な計算を行ってください。 (等)

古いデータを削除しますか?その場合、おそらく1分のテーブルについてのみ心配する必要があります。他のテーブルは非常に小さいので、「永久に」保持できます。これを行うには、PARTITION BY RANGEを使用して、保持期間に基づいてパーティション数を決定します。 http://mysql.rjweb.org/doc.php/partitionmaint を参照してください。 (DROP PARTITIONは、同等のDELETEよりもmuch高速で、侵襲性が低くなります。)

高速取り込み-上記のヒントで労力を十分に削減できなかった場合は、 http://mysql.rjweb.org/doc.php/staging_table を参照してください。

その他のヒント:

  • PRIMARY KEYがありますが、適切な「自然インデックス」がある場合はAUTO_INCREMENTを使用しないでください。
  • 各列のサイズを慎重に決定します。ほとんどの実際のセンサーには、8ビットまたは16ビットに収まる値があります。たとえば、天気の温度では、気温が1度の場合、TINYINT SIGNED(1バイト)を使用できます。 10度または100度を取得するには、10を掛けてSMALLINT SIGNED(2バイト)を使用してスケーリングするのが最適な場合があります。 Eschew FLOAT(4バイト)、特にDOUBLE(8バイト)は、本当に必要な場合を除きます。
  • ノーマライズ。つまり、TINYINT UNSIGNEDにはSMALLINT UNSIGNEDまたはsensor_idを使用します。センサーの名前/場所/バルクIDなどへの/からの別のテーブルマッピングがあります。
  • セカンダリインデックスを最小化します。
2
Rick James