メトリックのメインリポジトリはcassandraであり、3年以上使用しています。 これまでのすべての問題について、cassandraの組み込みの診断ツールを使用して解決策を見つけることに成功しました。
Cassandraには、非常に有益なロギング(特にその場で有効にできるDEBUGレベル)、JMXを介して利用可能な詳細なメトリック、および豊富なユーティリティセット(nodetool、sstable *)があります。
しかし最近、私たちはかなり興味深い問題に直面し、真剣に脳を壊し、cassandraのソースコードを読んで何が起こっているのかを把握する必要がありました。
すべては、テーブルの1つを読み取るKassandraの応答時間が増加し始めたという事実から始まりました。

この場合、ログは空で、バックグラウンドプロセス(圧縮)はありませんでした。 bunchesテーブル内のSSTableの数が増えていることにすぐに気付きました(顧客のメトリックの値を保存しています)。

さらに、これは9台のうち3台のサーバーでのみ発生します。

その後、私たちは長い間愚かで、グーグルでJIRAを読みましたが、同様のバグはありませんでした。 しかし、時間が経過し、応答時間がほぼ直線的に増加したため、少なくとも一時的な解決策を見つける必要がありました。 バンチテーブルの圧縮を行うことが決定されましたが、ドキュメントが明確ではないため、1つまたはすべてのノードがnodetool compactを使用して圧縮を開始します。このプロセスはJMXから開始しました。
実際には、 ALTER TABLE
を使用して圧縮戦略を変更すると、クラスターのすべてのノードで完全な圧縮を同時に起動することに悩まされるという苦い経験から既に学んでいます。 その後、より管理しやすい方法でこれを行う方法がありました。
今回、 nodetool compactは、作業中のノードでのみ圧縮を実行することが判明しました。
コンパクト化が終了した後、安定の量は減少しましたが、すぐに再び成長し始めました:

このように、手作業でcassandraのパフォーマンスを許容レベルに維持できる松葉杖を手に入れました。 問題のあるノードのクラウンにコンパクションコンパクションを配置すると、応答の読み取りのタイムラインは次のようになりました。

現在、cassandra 2.1.15を使用していますが、JIRAではバージョン2.2以降で修正された同様のバグがいくつか見つかりました。
当時は良いアイデアがなかったため、問題のあるノードの1つを2.2にアップグレードすることにしました(特に、とにかくこれを行うつもりで、アプリケーションが既に2.2でテストされているため)。 更新はスムーズに進みましたが、これで問題は解決しませんでした。
現在の状況で追加のエントロピーを導入しないために、クラスター全体を更新せずに2.1に戻すことにしました(これはクラスターからノードを削除し、古いバージョンで戻すことで行われます)。
この問題を最初から解決することは不可能であることが明らかになり、cassandraコードを読みに行く時が来ました。 最終的にこのテーブルに時系列を格納するため、 DateTieredCompactionStrategyを次の設定で使用します。
{ 'class': 'org.apache.cassandra.db.compaction.DateTieredCompactionStrategy', 'base_time_seconds': '14400', 'max_sstable_age_days': '90' }
これにより、同じ時間間隔のデータが近くにあり、古いデータと混ざらないようにすることができます。 同時に、90日より古いデータはまったく圧縮しないでください。このデータは絶対に変更されないため、ディスクへの不必要な負荷がなくなります。
仮説があります:Cassandraは90日以上経過していると考えているので、突然、安定版は圧縮されませんか?
cassandraが依存する時間は、すべての列に必要な内部タイムスタンプです。 Kassandraは、データを書き込むときに現在のタイムスタンプを記録するか、クライアントが設定できます。
INSERT INTO table (fld1, fld2) VALUES (val1, val2) USING TIMESTAMP 123456789;
(この機能は使用しません)。
すべてのsstable sstablemetadataユーティリティのメタデータを確認すると、異常なタイムスタンプ値が見つかりました。
$ sstablemetadata /mnt/ssd1/cassandra/okmeter/bunches-3f892060ef5811e5950a476750300bfc/okmeter-bunches-ka-377-Data.db |head SSTable: /mnt/ssd1/cassandra/okmeter/bunches-3f892060ef5811e5950a476750300bfc/okmeter-bunches-ka-377 Partitioner: org.apache.cassandra.dht.RandomPartitioner Bloom Filter FP chance: 0.010000 Minimum timestamp: 1458916698801023 Maximum timestamp: 5760529710388872447
しかし、新しく作成された安定版には絶対に通常のタイムスタンプがありました。なぜ圧縮されないのですか? 次のコードが見つかりました:
private long getNow() { return Collections.max(cfs.getSSTables(), new Comparator<SSTableReader>() { public int compare(SSTableReader o1, SSTableReader o2) { return Long.compare(o1.getMaxTimestamp(), o2.getMaxTimestamp()); } }).getMaxTimestamp(); }
今の場合:
$ date -d @5760529710388 Sat Dec 2 16:46:28 MSK 184513
それは、別の182千年、あなたも圧縮を期待することはできません:)
問題のある3つのサーバーのそれぞれに、十分に大きいサイズ(60Gb、160Gb、および180Gb)の1つの「壊れた」安定版がありました。 最小のものは横に押し出され、 sstable2jsonを介して125Gbの人間が読めるファイルを取得し、grepを開始しました。 安全に削除できる破損した列(1つのテストプロジェクトのセカンダリメトリック)が1つあることが判明しました。
Cassandraは、 sstableからデータを削除する標準的な方法を見つけませんでしたが、 sstablescrubユーティリティの意味は非常に似ています。 Scrubber.javaを見て、タイムスタンプを読み取っていないことが明らかになり、美しいパッチを作成するのはかなり困難であるため、見苦しくなりました。
、ここで226; 4; eJlZUXr078; 1472083200はビートレコードのキーであり、sstable2jsonでのエクササイズの結果としてわかっています。
そしてうまくいきました!
それとは別に、 sstablescrubはほとんどディスクへの書き込み速度で非常に高速に動作します。 sstableは不変の構造であるため、変更を行うと新しいsstableが作成されます。つまり、スクラブは十分な空きディスク領域を提供する必要があります。 これは私たちにとって問題であることが判明しました。別のサーバーでスクラブを実行し、クリーニングした安定版を目的のサーバーにコピーする必要がありました。
ビートの記録を取り除いた後、テーブルはコンパクトになり始めました。
しかし、あるメモでは、100Gbを超えるかなり重い安定版(それ自体)が常に圧縮されていることに気付きました。
CompactionTask.java:274 - Compacted 1 sstables to [/mnt/ssd1/cassandra/okmeter/bunches-3f892060ef5811e5950a476750300bfc/okmeter-bunches-ka-5322,]. 116,660,699,171 bytes to 116,660,699,171 (~100% of original) in 3,653,864ms = 30.448947MB/s. 287,450 total partitions merged to 287,450. Partition merge counts were {1:287450, }
プロセスが終了するとすぐに、再び圧縮が開始されました。たとえば、ディスク読み取り操作のスケジュールは次のようになりました。

ここで、このファイルがssd1からssd2へ、またはその逆にどのように移行したかを確認できます。
ログにスペース不足エラーもありました。
CompactionTask.java:87 - insufficient space to compact all requested files SSTableReader(path='/mnt/ssd2/cassandra/okmeter/bunches-3f892060ef5811e5950a476750300bfc/okmeter-bunches-ka-2135-Data.db'), STableReader(path='/mnt/ssd1/cassandra/okmeter/bunches-3f892060ef5811e5950a476750300bfc/okmeter-bunches-ka-5322-Data.db')
しかし、なぜ1つの安定版を圧縮するのですか? DateTieredCompactionStrategyでのコンパクションの安定性が一般的にどのように選択されるかを把握する必要がありました。
- 現在のテーブルのすべての安定版のリストが取得されます。
- 現在、コンパクションに参加している安定版は除外されています。
- 最大タイムスタンプがmax_sstable_age_daysよりも古い安定版は除外されます。
- 残りは、最新のものから始まる最小タイムスタンプでグループ化されます。 これらの各グループでは、 SizeTieredCompactionStrategyに従って候補が選択されます 。最初の間隔(base_time_seconds)には最小min_threshold (この場合は4)ファイルが必要で、古いファイルでは2つで十分です。 グループ内に候補者がいない場合、グループはスキップされます。 1つのパスで、「最も若い」グループの1つが圧縮のために選択されます。
- 圧縮用に選択した安定したグループでは、必要な空き領域がdata_file_directoriesにない場合、結果のファイルのサイズが予測され(すべてのソースファイルの合計のみ)、最大のファイルがグループから除外されます。
- グループに少なくとも1つのファイルが残っている場合、圧縮が開始されます。
DEBUGロギングレベルでは、このケースでは次のことが明らかになりました。
- 3つのファイルからのコンパクト化に関するグループが判明
- SizeTieredCompactionStrategyは3つのうち2つのファイルをマージすることを選択しました
- スペース不足のため、1人の候補者が残り、彼は円で圧縮されました
このバグや機能を判断することは想定していません(TTLを使用する場合は1ファイルを圧縮する必要があるかもしれません)が、どうにかしてこれを整理する必要がありました。 Cassandraでそれらを圧縮する方法を見つける必要があると判断しました。
2つのSATAディスクと2つのSSDを使用するサーバーを使用します。 ssdのスペースに問題があるため、この問題の最適化の候補をディスクにコピーし、ssdにリンクを配置して、ssdのスペースを解放して結果の安定版にすることを決定しました。 これは機能し、このマシンのコンパクト化は通常どおり機能し始めました。

このグラフは、hdd2がプロセスにどのように参加したかを示しています。
合計
- カーブしたタイムスタンプを持つレコードがどのように安定したのかを理解していませんでした(有限になる場合は、繰り返すまで延期します)
- DateTieredCompactionStrategyの設定を調整する必要があります: max_sstable_age_daysを10-30日に下げて、sstableが巨大なサイズにならないようにします(操作するときにバッファーを提供する方が簡単です)
- cassandraのソースコードは非常に明確で文書化されています。
- この問題は、サービスの可用性にはほとんど影響しませんでした(2〜3分間数回減速しました)。