Aurora のパラメータグループで max_connections の値が計算値と合わない

最近 Aurora の検証をしているので,今後は Aurora 関連の記事を書く機会が増えそう.

前提

  • RDS (Aurora MySQL)
  • インスタンスタイプ : db.t2.medium

DBInstanceClassMemory とは

RDS のパラメータグループでは,特定の変数と演算子を使った動的な値設定ができる.今回は変数 DBInstanceClassMemory に関して調べたことと,計算が合わずに困ったことを書いておこうと思う.

DBInstanceClassMemory は,名前だけを見るとインスタンスタイプごとに搭載されたメモリサイズのように思えるけど,実際には違っていて,RDS プロセスに割り当てられたメモリサイズのことを意味する.よって,搭載されたメモリサイズよりは確実に小さい値となる.その点はドキュメントにも書いてある.

DBInstanceClassMemory
現在の DB インスタンスに関連付けられている DB インスタンスクラスに割り当てられたメモリのバイト数を返します。このメモリは、インスタンスを管理する Amazon RDS プロセスによって使用されるメモリよりも小さくなります。 docs.aws.amazon.com

DBInstanceClassMemory を参照しているパラメータ

デフォルトのパラメータグループ “default.aurora5.6” で,以下の4パラメータが DBInstanceClassMemory を参照している.特に innodb_buffer_pool_sizemax_connections などは,ワークロードに応じてチューニングが必要なので,Aurora クラスタのデフォルト値を理解しておくことは重要だと考えている.

  • innodb_buffer_pool_size
  • max_connections
  • query_cache_size
  • thread_cache_size

f:id:kakku22:20170202172100j:plain

逆算して DBInstanceClassMemory を知る

まず,デフォルトのパラメータグループのまま起動したクラスターの Aurora Writer で,上記のパラメータの値を確認してみた.

mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
+-------------------------+------------+
| Variable_name           | Value      |
+-------------------------+------------+
| innodb_buffer_pool_size | 1610612736 |
+-------------------------+------------+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 90    |
+-----------------+-------+
1 row in set (0.01 sec)

mysql> SHOW VARIABLES LIKE 'query_cache_size';
+------------------+----------+
| Variable_name    | Value    |
+------------------+----------+
| query_cache_size | 89498624 |
+------------------+----------+
1 row in set (0.01 sec)

mysql> SHOW VARIABLES LIKE 'thread_cache_size';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| thread_cache_size | 2     |
+-------------------+-------+
1 row in set (0.00 sec)

まず最初に innodb_buffer_pool_size の値から逆算して DBInstanceClassMemory を調べてみた.db.t2.medium のメモリサイズは 4GB なので,以下の式に当てはめて逆算すると,DBInstanceClassMemory は 2GB だとわかった.よって db.t2.medium においては,メモリサイズの 50% が DBInstanceClassMemory に割り当てられていることがわかった.

innodb_buffer_pool_size = {DBInstanceClassMemory*3/4} = 2147483648 * 3 / 4 = 1610612736

ちなみに,この割合は固定値ではなく,インスタンスタイプが良くなればなるほど,上がっていく.以下の記事を見ると,最高スペックの db.r3.8xlarge だと 96.4% が DBInstanceClassMemory に割り当たっていることがわかる.

query_cache_sizethread_cache_size も同様に逆算する

同様に query_cache_sizethread_cache_size も値から逆算すると,DBInstanceClassMemory は 2GB だとわかった.よって,db.t2.medium だと DBInstanceClassMemory は 2GB だとほぼ断定できそう.

query_cache_size = {DBInstanceClassMemory/24} = 2147483648 / 24 = 89478485.3333333
thread_cache_size = {DBInstanceClassMemory/1005785088} = 2147483648 / 1005785088 = 2.135131723

あれれ max_connections の計算が合わないぞ?

やっと今回の本題に入る.max_connections の式は以下のようになっていて,GREATEST 関数に含まれてる値の中で,一番大きい値が割り当たるようになっている.

GREATEST({log(DBInstanceClassMemory/1073741824)*45},{log(DBInstanceClassMemory/8187281408)*1000})

よって DBInstanceClassMemory を 2GB だとすると,以下の計算となり,値は 45 だと推測できる.

{log(DBInstanceClassMemory/1073741824)*45} = log(2147483648/1073741824) * 45 = 45
{log(DBInstanceClassMemory/8187281408)*1000} = log(2147483648/8187281408) * 1000 = -1930

でも実際には 90 だった.計算が合わない.

mysql> SHOW VARIABLES LIKE 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 90    |
+-----------------+-------+
1 row in set (0.01 sec)

デフォルトの式で max_connections を 90 にするには DBInstanceClassMemory が 4GB である必要があって,そうすると db.t2.medium に搭載されたメモリサイズと一致してしまう.となると,パラメータによって DBInstanceClassMemory の値が違う?そんなはずは無いだろう.うーん謎だ.

{log(DBInstanceClassMemory/1073741824)*45} = log(4294967296/1073741824) * 45 = 90

AWS サポートに問い合わせた

AWS サポートに問い合わせたところ,原因が判明した.

  • まず db.t2.mediumDBInstanceClassMemory は 2GB ではなく 2.0004 GB “程度” であること
    • innodb_buffer_pool_size の値から逆算すると気付けなかった
  • 2.0004 GB の前提で log 計算をすると log(2147913144.7296/1073741824) = 1.00028 となる
  • 1.00028 を 2.0 に “切り上げ” てから 45 を乗算するため 2 * 45 = 90 となる

結論として,ドキュメントに書かれていないロジックになっていて,逆算することは難しかった.今後 max_connections の計算式をもっと簡単にする予定があるらしく,今後に期待!(まぁ実際の運用を考えると max_connections をデフォルト値で運用することは無さそうなんだけど…)