ある日 InnoDB Cluster をコンテナ上で動かしてたがメモリを期待していた以上に消費していたので調べていた。
その時は innodb_dedicated_server を 1 にしてた。
innodb_dedicated_server
MySQL 8.0 から追加された変数で自動で innodb_buffer_pool_size とかを自動で決めてくれる便利もの。
dev.mysql.com
ソースを覗いてみる
buffer_pool_size が決まるところ
ha_Innodb.cc:3992 で innodb_dedicated_server が ON の場合の分岐が走り、
ha_innodb.cc:3999 でサーバーにあるメモリ量を取得して innodb_buffer_pool_size が決まる。
ha_innodb.cc の innodb_buffer_pool_size_init 部分 ↓
/** Initialize and normalize innodb_buffer_pool_size. */ static void innodb_buffer_pool_size_init() { #ifdef UNIV_DEBUG ulong srv_buf_pool_instances_org = srv_buf_pool_instances; #endif /* UNIV_DEBUG */ acquire_sysvar_source_service(); /* If innodb_dedicated_server == ON */ if (srv_dedicated_server && sysvar_source_svc != nullptr) { static const char *variable_name = "innodb_buffer_pool_size"; enum enum_variable_source source; if (!sysvar_source_svc->get( variable_name, static_cast<unsigned int>(strlen(variable_name)), &source)) { if (source == COMPILED) { double server_mem = get_sys_mem(); if (server_mem < 1.0) { ; } else if (server_mem <= 4.0) { srv_buf_pool_size = static_cast<ulint>(server_mem * 0.5 * GB); } else srv_buf_pool_size = static_cast<ulint>(server_mem * 0.75 * GB); } else { ib::warn(ER_IB_MSG_533) << "Option innodb_dedicated_server" " is ignored for" " innodb_buffer_pool_size because" " innodb_buffer_pool_size=" << srv_buf_pool_curr_size << " is specified explicitly."; } } } release_sysvar_source_service(); if (srv_buf_pool_size >= BUF_POOL_SIZE_THRESHOLD) { if (srv_buf_pool_instances == srv_buf_pool_instances_default) { #if defined(_WIN32) && !defined(_WIN64) /* Do not allocate too large of a buffer pool on Windows 32-bit systems, which can have trouble allocating larger single contiguous memory blocks. */ srv_buf_pool_instances = ut_min(static_cast<ulong>(MAX_BUFFER_POOLS), static_cast<ulong>(srv_buf_pool_size / (128 * 1024 * 1024))); #else /* defined(_WIN32) && !defined(_WIN64) */ /* Default to 8 instances when size > 1GB. */ srv_buf_pool_instances = 8; #endif /* defined(_WIN32) && !defined(_WIN64) */ } } else { /* If buffer pool is less than 1 GiB, assume fewer threads. Also use only one buffer pool instance. */ if (srv_buf_pool_instances != srv_buf_pool_instances_default && srv_buf_pool_instances != 1) { /* We can't distinguish whether the user has explicitly started mysqld with --innodb-buffer-pool-instances=0, (srv_buf_pool_instances_default is 0) or has not specified that option at all. Thus we have the limitation that if the user started with =0, we will not emit a warning here, but we should actually do so. */ ib::info(ER_IB_MSG_534) << "Adjusting innodb_buffer_pool_instances" " from " << srv_buf_pool_instances << " to 1" " since innodb_buffer_pool_size is less than " << BUF_POOL_SIZE_THRESHOLD / (1024 * 1024) << " MiB"; } srv_buf_pool_instances = 1; } #ifdef UNIV_DEBUG if (srv_buf_pool_debug && srv_buf_pool_instances_org != srv_buf_pool_instances_default) { srv_buf_pool_instances = srv_buf_pool_instances_org; }; #endif /* UNIV_DEBUG */ srv_buf_pool_chunk_unit = buf_pool_adjust_chunk_unit(srv_buf_pool_chunk_unit); srv_buf_pool_size = buf_pool_size_align(srv_buf_pool_size); ut_ad(srv_buf_pool_chunk_unit >= srv_buf_pool_chunk_unit_min); ut_ad(srv_buf_pool_chunk_unit <= srv_buf_pool_chunk_unit_max); ut_ad(srv_buf_pool_chunk_unit % srv_buf_pool_chunk_unit_blk_sz == 0); ut_ad(srv_buf_pool_chunk_unit % UNIV_PAGE_SIZE == 0); ut_ad(0 == srv_buf_pool_size % (srv_buf_pool_chunk_unit * srv_buf_pool_instances)); ut_ad(srv_buf_pool_chunk_unit * srv_buf_pool_instances <= srv_buf_pool_size); srv_buf_pool_curr_size = srv_buf_pool_size; }
メモリサイズを返しているところ
get_sys_mem() でサーバーに割り当てられたメモリ量を取得している。
ha_innodb.cc:297 ↓
static double get_mem_sysconf() { return (((double)sysconf(_SC_PHYS_PAGES)) * ((double)sysconf(_SC_PAGESIZE) / GB)); }
_SC_PHYS_PAGES
物理メモリのページ数
_SC_PAGESIZE
バイト単位でのページサイズ
MySQL はメモリの管理方式としてはページング方式を使っていて物理メモリのページ数と1ページ辺りのサイズをかけて返してるらしい。
_SC_PHYS_PAGES は物理マシンのページ数を返すのでコンテナ(プロセス)で動かす場合では不都合が起きる。
似たようなことを経験したことがあったからある程度予測はついていた。
rarirure.rip
C 読めないし、MySQL Server はソースが膨大でコンパイルして開くまで30分かかった。
間違ってたら(補足があったら)教えてくれると助かります🙏