限られたリソースまたは日没に直面して巨大なテーブルを最適化する

背景



フレームワークには、大量のデータを処理する必要があるプロジェクトがあります。 特に、既存の顧客の現在のすべてのオファーとis_deleted = 1とマークされた古いオファーが保存される非正規化されたテーブルが1つあります。



このテーブルのエントリ数は、最近まで3,000万から5,000万の範囲でした。 通常の最適化は、そのような条件下であっても、常に機能するとは限りませんでした。 したがって、創業者の父親(Yevgeny Vasilievich)は、次のような方法でテーブルを再構築する方法を思い付きました。すべての関連する(is_deleted = 0)は、日付と時刻によるプレフィックスを追加した同一構造のテーブルにコピーされ、コピーが完了すると、元のテーブルを削除して名前を変更するだけでしたソース。



このアプローチは、オファーの検索速度を上げることが必要になるまで、確実に機能しました。 そして、ここから小さな物語が始まります。



変化の風



奇妙なことに、検索速度を上げるために、検索エンジンを使用することが決定されました。 Solrを選びました。 なんで? 私たちの目的のためにそれは良いからです。 そして、私たちの目的のためだけではありません。 時間がある場合は、この検索エンジンに関する記事を必ず作成します。



開発用サーバーでデバッグした後、運用用に新しいバージョンのサイトを展開するまで、すべてが順調でした。 検索エンジンは機能し、クライアントの価格パーサーは起動し、いくつかの粗さを除いて、新しいスキームに従って非常にうまく機能しました。 しかし、すべてのオファーのテーブルを再構築するためのスクリプトは、毎晩落ち始めました。



問題は、Solrがマッスルと同じサーバーに配置されていたことです。 サイトでオファーを検索するには、これは正常でした。 しかし、Solrは軽快な獣ですが、その作業には多くのリソースが必要です。 ただし、同様のソリューションでは、サーバーリソースを筋肉と検索エンジンの間で半分に分割します。 したがって、文を再コンパイルするスクリプトは、tmpfsのスペース不足に関するエラーでクラッシュしました。



ソリューションを検索する



オプションゼロ 、非現実的。 検索エンジン用に別のサーバーを割り当てます。 実際のところ、このサービスはまだ宣伝も訪問もされていないため、別の非常に高価なサーバーを購入しています。



最初のオプション 。 これは、既存のスクリプトを何らかの形で最適化する試みで構成されていました。 しかし、私たちは成功せず、ほとんどすぐにそれを放棄しました。



2番目のオプションは、HandlerSocketを使用することです。 HSは、高速で信頼性が高く、最終的にファッショナブルです。 しかし、HSは膨大な量のデータの読み取りには適していないことが判明しました。 HSは、ランダムに配置された個々のレコードをすばやく見つけるという素晴らしい仕事をしています。 また、大きなデータ配列を部分的に連続して読み取る場合、limit、offsetを使用すると、次の各ステップで速度が低下します。 ただし、HSを使用する場合、これは最大の問題ではありません。条件is_deleted = 0に従って選択する必要があり、このフィールドはインデックスではありませんでした。 そして、一般的に言えば、そのようにすることは無意味です。 したがって、他のタスクで既に実証済みの勇敢なHandlerSocketは、今回は期待に応えることができませんでした。



幸いなことに、私が個人的に使用したことのない3番目のオプションがありました。 これがネイティブの筋肉ハンドラーです。 彼は何をすることを許し、何のために彼は何をするのですか? 通常、制限、オフセット、またはその間の計算のために発生する速度を損なうことなく、特定の条件(インデックスフィールドでなく)でレコードを順次読み取ることができます。 ハンドラーを開いて、特定の条件(READ FIRST)で最初のデータを読み取り、条件を変更せずに、少なくとも一部のデータがある間にREAD NEXTを実装するだけです。 アクションのシーケンスは、ディレクトリのスキャンなど、C-shnyアプローチに関連付けられています。 そして、ここで最も嬉しいことは、ポインターが最後に置いた場所に残っていることです。



その結果、2億7千万件のレコードがテーブルに蓄積されていたとしても、テーブル全体でデータを読み取る際には、一定の高速読み取りとメモリの合理的な使用が可能になります。 このソリューションを見つけるまでに、まさに非常に多くの記録がありました。 それはたくさんですか、それとも少しですか? 質問は相対的です。 しかし、そのようなボリュームが原因でサービスが失敗し始めた場合、多くの場合。



リソースが限られている状況では、このソリューションが速度と信頼性において最も有利であることが判明しました。 1回の反復で最初の10,000レコードを読み取ることができた場合、その後のレコード数に関係なく、すべてのレコードもカウントします。



PS



このソリューションは誰かにとって間違いなく役に立つと思います。



謝辞



ハンドラーのアイデアを実際に提案してくれたYuri Maslennikovに感謝します。



All Articles