从源码看MySQL参数
建索引、调参数、改SQL,是MySQL DBA性能调优的必备技能,建索引和调整参数带来的性能提升更是立竿见影。然而许多时候我们调整参数都是基于经验判断,而不清楚其背后的原理,也不清楚参数之间存在的相关依赖。殊不知,我们与这些参数其实只隔了几行代码!
本文就结合MySQL源码,力求让读者了解max_connections, back_log, thread_cache_size, table_open_cache四个参数如何影响应用端(客户端)到服务端的访问的。
max_connections
max_connections参数用来设置最大连接数,默认值为100。MySQL会保留一个用于管理员(具有SUPER权限)登录的连接,确保了连接数达到了max_connections上限后,管理员还能正常登录进行应急管理。因此MySQL的实际最大可连接数为max_connections+1。
看下列代码,MySQL在使用create_new_thread(thd)创建一个新连接时,会检查当前的连接数(connection_count)有没有超过配置值:
if (connection_count >= max_connections + 1 || abort_loop)
{
mysql_mutex_unlock(&LOCK_connection_count);
DBUG_PRINT("error",("Too many connections"));
}
如果设置过小,会报"Too many connections"的错误。
back_log
先看下MySQL源码中对back_log参数的注释:
uint m_backlog; // backlog specifying length of pending connection queue。
MySQL每处理一个应用端连接请求的时候都会创建一个新线程与之对应,创建新线程期间,如果应用端有大量的短连接请求访问数据库,且连接超过max_connections设定值,MySQL会将新的连接放入到一个请求队列中,这个队列的深度由参数back_log控制,如果等待的连接数超过back_log,新的连接请求会被拒绝。MySQL在启动过程中,还会对该参数结合max_connections进行调整:
/* Fix back_log */
if (back_log == 0 && (back_log= 50 + max_connections / 5) > 900)
back_log= 900;
需要注意的是,back_log值还由TCP/IP中的侦听队列/proc/sys/net/core/somaxconn控制,一旦超过该值则会失效。因为somaxconn是内核态的参数,而back_log属于用户态的参数,内核态参数的优先级要高于用户态参数。
笔者自己的MySQL测试机中将max_connections调大为8000(仅做测试用,勿参考),(50+8000/5)>900,因此back_log值为900。
mysql> SHOW VARIABLES LIKE '%max_connections%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| max_connections | 8000 |
+------------------------+-------+
mysql> show variables like 'back_log';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| back_log | 900 |
+--------------------+-------+
thread_cache_size
thread_cache_size参数也依赖于max_connections。当应用端的连接线程断开后,不是直接释放,而是进行缓存,等待新的连接请求进行复用。因为线程不断创建并销毁非常影响性能,因此这个值的大小需要综合考虑应用端的连接类型是长连接还是短连接。如果是短连接,值调大,如果是长连接,则调小点。缓存的大小还和系统内存有关,因此需综合考虑。
/* Calculate and update default value for thread_cache_size. */
if ((default_value= 8 + max_connections / 100) > 100)
default_value= 100;
var= intern_find_sys_var(STRING_WITH_LEN("thread_cache_size"));
var->update_default(default_value);
table_open_cache
table_open_cache参数保存了打开表的文件描述符,用于减少SQL语句中涉及表的打开关闭的频率。需要注意的是,缓存里还存放了临时表和临时文件的文件描述符,所以在设计时注意预留好大小。MySQL在启动时也会调整table_open_cache的真实设置:
void adjust_table_cache_size(ulong requested_open_files)
{
ulong limit;
limit= max((requested_open_files - 10 - max_connections) / 2,
TABLE_OPEN_CACHE_MIN);
if (limit < table_cache_size)
{
sql_print_warning("Changed limits: table_open_cache: %lu (requested %lu)", limit, table_cache_size);
table_cache_size= limit;
}
table_cache_size_per_instance= table_cache_size / table_cache_instances;
}
可以看到该参数由requested_open_files,max_connections,
TABLE_OPEN_CACHE_MIN(400)共同决定。而对requested_open_files,MySQL同样有所限制:
*requested_open_files= min(effective_open_files, request_open_files)
总结
不难发现,上述四个参数在处理MySQL应用端连接过程中不可或缺,互相影响,我们最后看看以下代码:
void adjust_related_options(ulong *requested_open_files)
{
/* In bootstrap, disable grant tables (we are about to create them) */
if (opt_bootstrap)
opt_noacl= 1;
/* Theorder is critical here, because of dependencies. */
adjust_open_files_limit(requested_open_files);
adjust_max_connections(*requested_open_files);
adjust_table_cache_size(*requested_open_files);
adjust_table_def_size();
}
在MySQL服务启动时,open_files_limit决定着应用端能够连接的最大连接数(limit= requested_open_files - 10 - TABLE_OPEN_CACHE_MIN * 2),而requested_open_file和max_connections又决定了table_cache_size的大小(limit= max((requested_open_files - 10 - max_connections) / 2, TABLE_OPEN_CACHE_MIN);)。
本文并没有结合案例教大家如何调整参数,也没有深入到源码sqlparse和优化器等核心功能,只希望给大家打开一条思路,那就是可以通过查看源码,了解各个参数如何影响MySQL正常访问的。