【Next Tokyo ’24】8/1 - 2 パシフィコ横浜にて開催!最新技術やトレンド、顧客事例、専門家によるセッションなど、ビジネス変革を加速させるヒントが満載です。

MySQL によるメモリの使われ方

MySQL インスタンスでは、多くのメモリが消費されることや、メモリ不足(OOM)の問題が発生することがよくあります。メモリが不足しがちなデータベース インスタンスの実行では、パフォーマンスの問題、ハングアップ、アプリケーションの機能停止を引き起こすことがよくあります。

MySQL インスタンスのメモリを割り当てる前に、MySQL によるメモリの使われ方を理解することが重要です。この記事では、メモリを消費する MySQL の機能について説明します。こうした機能は多くの場合、OOM の問題につながります。また、Google Cloud のフルマネージド サービスである Cloud SQL for MySQL では、メモリ管理に関してどのように設定されているかを説明します。

グローバル バッファ

MySQL は、サーバーの起動時にグローバル バッファを割り当て、すべての接続で共有されます。MySQL のメモリの大部分は、グローバル バッファ(innodb_buffer_pool_size、innodb_log_buffer_size、key_buffer_size など)によって消費されます。

InnoDB バッファプール

通常は、InnoDB のバッファプールが、MySQL インスタンス内で最大のメモリを消費します。これは、innodb_buffer_pool_size パラメータを使用して構成されます。これは、テーブルデータとインデックス、バッファの変更適応ハッシュ インデックス、他の内部構造のキャッシュ保存に使用されます。Google Cloud のマネージド MySQL サービスである Cloud SQL for MySQL は、インスタンスのサイズに応じて、innodb_buffer_pool_size をインスタンス メモリの 72% を上限に構成します。

InnoDB は、バッファおよび関連するデータ構造用に追加のメモリを予約します。割り当てられるメモリの合計は、指定されたバッファプールのサイズより約 10% 大きくなります。InnoDB のバッファプールのメモリ使用量は、show engine innodb status\G の出力で確認できます。

mysql> show engine innodb status\G

----------------------

BUFFER POOL AND MEMORY

----------------------

Total large memory allocated 11511349248

InnoDB ログバッファ

InnoDB のログバッファは、ディスク上の InnoDB REDO ログファイルに書き込まれる変更を保持するために使用されます。これは、innodb_log_buffer_size を使用して構成されます。MySQL コミュニティのデフォルト値は 16 MB です。Cloud SQL for MySQL も同じ値を使用します。

キーバッファのサイズ

キーバッファは MySQL が使用し、メモリに MyISAM インデックスをキャッシュ保存します。これは、key_buffer_size を使用して構成されます。MySQL コミュニティのデフォルト値は 8 MB です。Cloud SQL for MySQL も同じ値を使用します。Cloud SQL for MySQL は MyISAM テーブルをサポートしていないため、デフォルトのままで問題ありません。

クエリ キャッシュのサイズ

query_cache_size 構成変数は、クエリ結果をキャッシュに保存するために割り当てられるメモリ量を定めます。MySQL Community 5.7 と Cloud SQL for MySQL 5.7 では、デフォルトで無効になっています。

クエリ キャッシュは、重大なスケーラビリティの問題で知られていたため、MySQL 5.7.20 で非推奨になり、MySQL 8.0 で削除されました。MySQL 5.7 インスタンスで引き続き使用している場合は、ワークロードにとって本当に有用かどうかを確認してください。詳細は、こちらのブログをご覧ください。

グローバル キャッシュ

MySQL は、すべての接続で共有されるグローバル キャッシュを割り当てます。これらは動的に割り当てられ、構成変数によってその上限が定められます。

テーブル キャッシュ

MySQL では、テーブル キャッシュを使用してテーブルへのアクセスを高速化します。 MySQL テーブル キャッシュには、開いているテーブルのキャッシュと、テーブル定義のキャッシュの 2 つがあり、それぞれ table_open_cachetable_definition_cache で構成されます。

table_open_cache は、接続されたすべてのスレッドが開いているテーブルのファイル記述子を保存するメモリ キャッシュです。この値を大きくすると、mysqld プログラム(MySQL サーバーとも呼ばれる)が必要とするファイル記述子の数が増加します。お使いのオペレーティング システムが、table_open_cache の設定によって暗黙的に指定されるオープン ファイル記述子の数を扱えることを確認してください。

複数のクライアント セッションが特定のテーブルに同時にアクセスでき、そのテーブルは同時クライアント セッションごとに独立して開きます。このため、開いているテーブルの数がサーバー内のテーブル数より多くなることがあります。テーブル キャッシュがいっぱいになると、サーバーは現在使用されていないテーブルを、最も長い間使われていないテーブルから順に解放します。

table_definition_cache は、テーブル定義を保存するメモリ キャッシュです。これはグローバルなもので、すべての接続で共有されます。

CloudSQL for MySQL 5.7 では、table_open_cachetable_definition_cache のデフォルト値として 2000 と 1400 が使用されます。

CloudSQL for MySQL 8.0 では、table_open_cachetable_definition_cache のデフォルト値として 4000 と 2000 が使用されます。

スレッド キャッシュ

MySQL はクライアント接続ごとに、クライアントが切断するまですべてのクエリを実行しクライアントに結果を返す専用のスレッドを割り当てます。MySQL は、接続ごとにスレッドを作成して破棄する必要がないように、スレッドをキャッシュに保存します。スレッド キャッシュ内のスレッド数は、thread_cache_size 変数を使用して構成します。

CloudSQL for MySQL では、thread_cache_size にデフォルトで 48 を使用します。

InnoDB データ ディクショナリ キャッシュ

InnoDB は、テーブル定義を保存するための独自のキャッシュを備えています。これは、テーブル オープン キャッシュやテーブル定義キャッシュとは異なります。InnoDB データ ディクショナリに割り当てられたメモリは、show engine innodb status\G の出力で確認できます。

----------------------

BUFFER POOL AND MEMORY

----------------------

Dictionary memory allocated 65816817

table_definition_cache 設定では、InnoDB データ ディクショナリ キャッシュのテーブル インスタンス数に対してソフト上限を設定します。InnoDB データ ディクショナリ キャッシュのテーブル数が table_defined_cache 上限を超過すると、LRU メカニズムがエビクションの印をテーブル インスタンスに付け始め、それらは最終的にこのキャッシュから削除されます。

これは InnoDB データ ディクショナリ キャッシュのテーブル インスタンス数が、table_definition_cache の上限よりも常に少なくなることを意味するのでしょうか。そういうわけではなく、外部キーの関係を持つテーブル インスタンスは、LRU リストに配置されません。それらはキャッシュに残り、テーブル インスタンスが table_definition_cache の上限を超えて大きくなり、メモリ使用量の増加につながります。外部キーの関係を持つテーブルで消費されたメモリは、MySQL のシャットダウン / 再起動イベントでのみ解放されます。この問題は、MySQL 5.7 と 8.0 の両方に存在し、確認済みのバグがあります。

MySQL インスタンスに外部キーの関係を持つテーブルが多数ある場合、InnoDB データ ディクショナリ キャッシュは数 GB のメモリを消費することがあります。MySQL のバッファ / キャッシュを構成する際に見落とされがちですが、予期しない高メモリ使用量やメモリ不足(OOM)の問題の原因の 1 つとなる可能性があります。

サンプル出力では、小規模なインスタンスによる 4.16 GB の InnoDB データ ディクショナリ キャッシュの消費を示します。

$ mysql -e "show engine innodb status\G" | grep -i memory

BUFFER POOL AND MEMORY

Total large memory allocated 7696023552

Dictionary memory allocated 4465193358

セッション バッファ

メモリを消費する MySQL のもう一つの機能は、セッション バッファです。これらのバッファは、セッションごとに割り当てられ、場合によっては、バッファの複数のインスタンスを単一のクエリ(特に join_buffer_size)に割り当てることができます。

これらのバッファは、クエリで必要な場合にのみ割り当てられますが(並べ替え、結合、インデックス/フルテーブル スキャンなど)、必要な場合は、ごく小さい割り当てが必要だとしてもフルサイズで割り当てられます。これらのバッファを大きな値に設定すると、メモリが無駄になる可能性があります。

デフォルト値は、MySQL コミュニティと Cloud SQL for MySQL で同じです。

バイナリログ キャッシュ

MySQL では、バイナリログ キャッシュを使用して、トランザクションの実行中にバイナリログに加えられた変更を保持します。これは、binlog_cache_size を使用して構成されます。バイナリ ロギングが有効になっている場合(log_bin=ON)は、クライアントごとに割り当てられます。

binlog_cache_size のデフォルト値は MySQL Community と Cloud SQL for MySQL で同じです。

一時テーブル

MySQL は、GROUP BY、ORDER BY、DISTINCT、UNION などのクエリを処理しながら、中間結果を保存する内部一時テーブルを作成します。これらの内部一時テーブルは、まずメモリ内に作成され、最大サイズに達するとディスク上のテーブルに変換されます。内部一時テーブルの最大サイズは、tmp_table_size 変数と max_heap_table_size 変数の最小値として決まります。

tmp_table_sizemax_heap_table_size のデフォルト値は、MySQL コミュニティと Cloud SQL for MySQL で同じです。

注: セッションごとのバッファとメモリ内一時テーブルは、接続ごとにメモリを個別に割り当てるため、多くの接続がそれを必要とする場合、全体的なメモリ使用量は非常に大きくなります。これらの値を高くしすぎないようにし、テストしてワークロードに最適な値を見つけることをおすすめします。

接続ごとのメモリ

すべてのスレッドが、クライアント接続を管理するためのメモリをほとんど必要としません。次の変数によってサイズを制御します。

  • thread_stack: 各スレッドのスタックサイズ。デフォルトは 256 KB です。
  • net_buffer_length: 各クライアントは、net_buffer_length の接続バッファと結果バッファに関連付けられます。これにより、最大 max_allowed_packet のサイズまで拡張できます。

Performance_schema

performance_schema を有効にすると、MySQL サーバーの実行を低レベルでモニタリングできます。performance_schema は、メモリを動的に割り当て、MySQL のシャットダウン / 再起動時にしか解放されません。

Cloud SQL for MySQL では、RAM サイズが 15 GB 以上のインスタンスで performance_schema を有効にできます。これは、MySQL 8.0.26 バージョンからデフォルトで有効になっています。performance_schema は、MySQL 5.6、5.7、8.0.18 バージョンではデフォルトで無効になっていますが、データベース フラグを使用して有効にできます。

まとめ

Cloud SQL for MySQL は、すぐに使用できる適切なパフォーマンスのためにメモリ関連のパラメータを自動的に構成します。ワークロードで多数のテーブルや接続をサポートするためにより大きなキャッシュが必要な場合、インスタンスで OOM の問題が発生する可能性があります。多くのスレッドがセッション バッファを同時に割り当てる場合も、メモリ関連の問題が発生する可能性があります。グローバル バッファ / キャッシュに割り当てるメモリが多いほど、接続に使用できるメモリが少なくなり(セッション バッファも同様)、また逆も同様で、良好なバランスを取ることが鍵になります。

ワークロードでより大きなキャッシュ / セッション バッファが必要な場合は、innodb_buffer_pool_size でグローバル バッファのサイズを小さくできます。Cloud SQL for MySQL インスタンスの構成パラメータは、データベース フラグを使用して変更できます。引き続き OOM やパフォーマンスの問題が発生する場合は、インスタンス サイズをアップグレードしてメモリを増やすことが可能です。

次のステップ

$300 分の無料クレジットと 20 以上の Always Free プロダクトを活用して、Google Cloud で構築を開始しましょう。

Google Cloud
  • ‪English‬
  • ‪Deutsch‬
  • ‪Español‬
  • ‪Español (Latinoamérica)‬
  • ‪Français‬
  • ‪Indonesia‬
  • ‪Italiano‬
  • ‪Português (Brasil)‬
  • ‪简体中文‬
  • ‪繁體中文‬
  • ‪日本語‬
  • ‪한국어‬
コンソール
  • Google Cloud プロダクト
  • 100 種類を超えるプロダクトをご用意しています。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。また、すべてのお客様に 25 以上のプロダクトを無料でご利用いただけます(毎月の使用量上限があります)。
Google Cloud