大容量データでのMySQL InnoDBの実用的な最適化とスケーラビリティ

この投稿では、インデックス、クエリプラン、集計を作成するトリガー、およびクエリとデータベース構造を最適化するその他の一般的な方法については説明しません。 また、innodb_プレフィックスを使用した最適な設定については説明しません。 おそらく、以下のテキストを読むことで、それらのいくつかの意味をよりよく理解できるでしょう。 この投稿では、 InnoDBとその操作について説明します。



この投稿で解決できる問題は何ですか?







いつものように、データベースでの作業



おおよその作業スキームは通常そのようなものです

  1. リクエスト
  2. リクエストプラン
  3. インデックス検索
  4. テーブルからデータを取得する
  5. クライアントへのデータの送信


トランザクションを開始しなかった場合でも、個々のリクエストはそれぞれ1つのリクエストからのトランザクションになります。 ご存知のように、トランザクションにはMySQLがデフォルトでREPEATABLE READに設定する分離レベルがあります 。 これは私たちにとって何を意味するのでしょうか? そして、トランザクションで「任意のテーブルに触れる」と、その時点でそのバージョンが修正され、他のトランザクションで行われた変更が表示されなくなるという事実。 クエリまたはトランザクションが長くなるほど、MySQLはより多くの「古い」データを蓄積し続けます。これは、メインメモリプールのアクティブな使用で発生すると信じる理由があります。 つまり データベースを使用したアクティブな作業の場合、主キーによる10個のテーブルを組み合わせた各無害な選択には、かなり深刻な副作用が生じ始めます。 PostgreSQLは、Oracleと同様に、デフォルトの分離レベルREAD COMMITTEDを備えており、 REPEATABLE READよりもはるかに簡単に機能します。 もちろん、 READ COMMITTED分離レベルでは、 行ベースのレプリケーションを使用する必要があります。 2つのクライアントをデータベースに接続し、同じテーブルで選択、削除、更新を行うだけで、トランザクション分離レベルを簡単に確認できます。 これは、選択の凍結に関する質問への回答です。データベースの分離レベルを変更してみてください。これは役に立ちます。



InnoDBがデータを処理する方法


InnoDBはデータをハードドライブにページ単位で保存します。 目的のページにアクセスすると、そのページがRAMに読み込まれ、レコードを読み取っていようと、他の何かを読み取ろうと、さまざまなアクションが実行されます。 Innodb_buffer_poolがinnodb_buffer_pool_sizeで設定したサイズであるのはこのメモリです。 作業のスキームは非常に古典的であり、その中に異常なものは何もありません。 InnoDBパフォーマンスレポートを次のように表示します。



SHOW VARIABLES like 'Innodb%';

SHOW GLOBAL STATUS like 'Innodb%';

SHOW ENGINE INNODB STATUS;









合計すると、データベースで読み取りまたは書き込み操作を実行するために次の時間コストがかかります

  1. ハードディスクからメモリにデータをロードする時間
  2. メモリ処理時間
  3. 必要に応じてハードディスクにデータを書き込む時間(すべてのデータがすぐにディスクに書き込まれるわけではないことに注意してください。主なことは、それらがログに記録されることです)




データがリクエスト時にInnoDBプールにある場合、ディスクからロードされないため、データベース操作の実行時間が大幅に短縮されることは直感的に明らかだと思います。



データベースが最も速く動作する方法は、すべてのデータとインデックスがプールに簡単に収まり、実際にデータベースが常にメモリから動作する場合です。 バージョン5.6.5では、データベースの再起動時にプール全体をディスクに保存することもでき、コールドスタートを回避できます。



次に、ディスク上のデータ量がメモリプールのサイズを超えた場合のイベントのわずかに異なるバージョンを見てみましょう。 プールサイズを4ページとすると、それぞれ[0,0,0,0]および16データページ1..16のようになります。 ほとんどの場合、ユーザーは15ページと16ページをリクエストします。 最新のデータがあり、常にメモリ内にあります。 明らかに、すべてが上記の場合と同じくらい速く動作します。



まあ、ユーザーによってアクティブに要求された2ページと、内部スクリプトとさまざまなデーモンによって常に使用されている8ページがある場合の悪いオプションです。 したがって、バッファー内の4ページについては、ディスクからの永続的な読み取りに変わる絶え間ない闘争があり、ユーザーのシステムの速度が低下します。 悪魔は通常、はるかに活発です。



このモードでは、さらに別のMySQLサーバーでレプリケーションを設定すると、クエリに参加してメモリプールの問題を軽減できます。 しかし、ご存知のように、MySQLのレプリケーションには重大な欠点があります。つまり、1つのスレッドで変更を適用することです。 つまり 特定の条件下では、スレーブが遅れ始めるか、生産性がまったく取るに足らないほど増加します。 この状況では、限られた数のテーブルでスレーブを作成する機能が役立ちます。 これにより、変更の適用とメモリプールの使用の両方で利益を得ることができます。 多くの場合、ユーザーが最も頻繁に要求するデータがわかっている場合、必要なテーブルのデータのみを保存するキャッシュを作成できます。 成功した場合、関連性を自動的に維持するキャッシュを取得します。 別のスレーブをすばやく作成する方法に興味がある人のために、私は側に目を向けることをお勧めします



STOP SLAVE;

SHOW SLAVE STATUS;//Master_Log_File Exec_Master_Log_Pos



START SLAVE;









データを新しいスレーブサーバーに貼り付けた後、必要なことは



CHANGE MASTER TO ... ;

START SLAVE;









もちろん、すべてがデータの量に依存しますが、原則として、このようなスレーブを非常に迅速に上げることができます。



部分複製を使用してシステムをモジュールに分解する


したがって、メインデータベースの部分的なレプリカを作成できます。これにより、特定のデータグループ間のメモリの分散を制御できます。 これは私たちにとってどのような機会をもたらしますか?

経験的にわかるように、スレーブサーバー上に独自のテーブルを作成したり、それらのテーブルに複製されたデータの外部キーを作成したりすることを妨げるものは誰もいません。 つまり 必要なメインデータベースだけでなく、テーブルのセットが拡張された必要なスレーブを持つこともできます。 たとえば、メインデータベースにはusersテーブルとpaymentsタイプのさまざまな補助テーブルが含まれています 。 また、ユーザーが投稿を書くことができるブログサービスもあります。 投稿テーブルを作成する別のデータベースにユーザーを複製します。 投稿テーブルを含むデータベースの読み込み負荷が高い場合、 ユーザー投稿テーブルを含むレプリカを作成します。 したがって、必要なテーブルのセットのデータ量が合理的な制限を超えなくなるまで分解することができます。 この場合、ユーザーIDのハッシュなどにより、巨大なテーブルをシャーディングする方向に注目し、MQを介して必要なワーカーにリクエストを送信する価値があります。



まとめ


MySQLは、指定されたテーブルにデータを書き込むだけで、シンプルなレプリケーションメカニズムを提供します。 これにより、データベースの不可欠な部分を含む追加のサービスを展開する十分な機会が得られます。



UPD。 データベースに多数の小さなトランザクションがある場合、innodb_flush_log_at_trx_commitの値を変更してみてください。これにより、ハードドライブの負荷が軽減されますが、注意してください! 理論的には、これによりデータが失われる可能性があります 。 この変数の結果を見るのはとても簡単です、なぜなら SET GLOBALを使用してインストールできます。



UPD2。 システムを正常に分解すると、実行するタスクに応じて個々のサーバーの設定を変更できます。 たとえば、支払いサーバーではSERIALIZABLEおよびinnodb_flush_log_at_trx_commit = 1を設定できます。また、ポストサーバーではREAD COMMITTEDおよびinnodb_flush_log_at_trx_commit = 2を設定できます。これはすべて、実行されるタスク、データの重要度、および失敗の確率に依存します。



All Articles