{"id":215,"date":"2011-11-28T16:13:05","date_gmt":"2011-11-28T19:13:05","guid":{"rendered":"http:\/\/wagnerbianchi.com\/blog\/?p=215"},"modified":"2011-11-28T19:48:06","modified_gmt":"2011-11-28T22:48:06","slug":"cache-de-threads-thread_cache_size","status":"publish","type":"post","link":"http:\/\/wagnerbianchi.com\/blog\/?p=215","title":{"rendered":"Cache de Threads &#8211; thread_cache_size"},"content":{"rendered":"<p>Um dos pontos mais cr\u00edticos para o workload do MySQL \u00e9 a cria\u00e7\u00e3o cont\u00ednua de threads e sabendo-se que a cada conex\u00e3o que uma aplica\u00e7\u00e3o ou um cliente qualquer realiza com o MySQL, uma nova *thread* \u00e9 criada &#8211; imaginem um servidor com essa quantidade de requisi\u00e7\u00f5es:<\/p>\n<pre>mysql&gt; \\s\r\n--------------\r\nmysql Ver 14.14 Distrib 5.5.17, for Linux (x86_64)\r\n\r\nConnection id: 100407\r\nCurrent database:\r\nCurrent user: root@localhost\r\nSSL: Not in use\r\nCurrent pager: stdout\r\nUsing outfile: ''\r\nUsing delimiter: ;\r\nServer version: 5.5.17-log MySQL Community Server (GPL)\r\nProtocol version: 10\r\nConnection: Localhost via UNIX socket\r\nServer characterset: latin1\r\nDb characterset: latin1\r\nClient characterset: utf8\r\nConn. characterset: utf8\r\nUNIX socket: \/var\/lib\/mysql\/mysql.sock\r\nUptime: 8 days 17 hours 49 min 6 sec\r\n\r\nThreads: 696 Questions: 292951068 Slow queries: 225 Opens: 498354\r\nFlush tables: 1 Open tables: 256 Queries per second avg: 387.836\r\n--------------<\/pre>\n<p>A sa\u00edda do comando \\s ou status acima nos mostra que temos 696 threads atualmente conectadas (ativas ou em sleep). O mais interessante \u00e9 saber que atrav\u00e9s da vari\u00e1vel thread_cache_size n\u00f3s podemos solicitar que tais threads j\u00e1 criadas sejam limpas ap\u00f3s uma desconex\u00e3o e ap\u00f3s isso, serem armazenadas em cache para reutiliza\u00e7\u00e3o. Assim, o MySQL n\u00e3o precisam mais criar novas threads a todo momento que uma nova conex\u00e3o \u00e9 requisitada. No exemplo abaixo, no mesmo servidor, aonde o n\u00famero de conex\u00f5es simult\u00e2neas batem em quase 1000, deixei o valor padr\u00e3o de thread_cache_size configurado como 8, sendo um valor bem baixo para a demanda atual.<\/p>\n<pre>mysql&gt; show variables like 'thread_cache%';\r\n+-------------------+-------+\r\n| Variable_name     | Value |\r\n+-------------------+-------+\r\n| thread_cache_size | 8     |\r\n+-------------------+-------+\r\n1 row in set (0.00 sec)<\/pre>\n<p>Mais uma vez, atrav\u00e9s das vari\u00e1veis de status, podemos checar que o MySQL reutiliza o objeto thread para novas conex\u00f5es:<\/p>\n<pre>mysql&gt; show status like 'Thread%';\r\n+-------------------+-------+\r\n| Variable_name     | Value |\r\n+-------------------+-------+\r\n| Threads_cached    | 7     |\r\n| Threads_connected | 799   |\r\n| Threads_created   | 90435 |\r\n| Threads_running   | 1     |\r\n+-------------------+-------+\r\n4 rows in set (0.00 sec)\r\n\r\nmysql&gt; show status like 'Thread%';\r\n+-------------------+-------+\r\n| Variable_name     | Value |\r\n+-------------------+-------+\r\n| Threads_cached    | 6     |\r\n| Threads_connected | 799   |\r\n| Threads_created   | 90435 |\r\n| Threads_running   | 2     |\r\n+-------------------+-------+\r\n4 rows in set (0.00 sec)<\/pre>\n<p>Nos dois resultados acima, podemos ver que:<\/p>\n<ul>\n<li>o n\u00famero de threads em cache s\u00e3o 7, apontados por Threads_cached,<\/li>\n<li>o n\u00famero de threads conectadas \u00e9 799, o que mostra Threads_connected,<\/li>\n<li>o n\u00famero de threads j\u00e1 criadas desde a \u00faltima reinicializa\u00e7\u00e3o \u00e9 de 90435,<\/li>\n<li>o n\u00famero de threads que atualmente tem o status diferente de Sleep, Threads_running.<\/li>\n<\/ul>\n<div>Uma boa leitura para este cen\u00e1rio \u00e9, o n\u00famero de Threads_cached diminuiu, j\u00e1 que uma das 7 threads que estavam em cache foi utilizada para uma nova conex\u00e3o que agora est\u00e1 em um estado diferente de sleep (visto pelo SHOW PROCESSLIST). E o que mostra a otimiza\u00e7\u00e3o \u00e9 justamente a reutiliza\u00e7\u00e3o da thread que estava em cache e a n\u00e3o cri\u00e7\u00e3o de uma nova, j\u00e1 que o n\u00famero de Threads_created n\u00e3o foi alterado.\u00a0Voc\u00ea poder\u00e1 otimizar o n\u00famero de threads que voc\u00ea deseja armazenar no cache de threads do MySQL, \u00e1rea que \u00e9 controlada pela vari\u00e1vel thread_cache_size, atrav\u00e9s do arquivo de configura\u00e7\u00e3o do MySQL e setando um n\u00famero pr\u00f3ximo ao n\u00famero de threads j\u00e1 criadas, apotando por Threads_created.<\/div>\n<pre>[mysqld]\r\nthread_cache_size = 1000<\/pre>\n<div>Existe um problema em rela\u00e7\u00e3o ao valor de thread_cache_size ser maior que 14 em vers\u00f5es anteriores \u00e0 vers\u00e3o 5.5 do MySQL. Tenho alguns servidores de bancos de dados MySQL na vers\u00e3o 5.5++ em alguns clientes utilizando valores bem superiores, sem nenhum problema algum. O cache de threads poder\u00e1 reduzir a press\u00e3o sobre o SWAP e o load de CPU, auxiliando o engine do MySQL a ocupar os recurso de m\u00e1quina mais com outros problemas como a entrega de dados, por exemplo.<\/div>\n<div>\n<pre>mysql&gt; show status like 'Threads%';\r\n+-------------------+-------+\r\n| Variable_name     | Value |\r\n+-------------------+-------+\r\n| Threads_cached    | 273   |\r\n| Threads_connected | 727   |\r\n| Threads_created   | 4659  |\r\n| Threads_running   | 101   |\r\n+-------------------+-------+\r\n4 rows in set (0.00 sec)<\/pre>\n<\/div>\n<div>At\u00e9&#8230;<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Um dos pontos mais cr\u00edticos para o workload do MySQL \u00e9 a cria\u00e7\u00e3o cont\u00ednua de threads e sabendo-se que a cada conex\u00e3o que uma aplica\u00e7\u00e3o ou um cliente qualquer realiza com o MySQL, uma nova *thread* \u00e9 criada &#8211; imaginem um servidor com essa quantidade de requisi\u00e7\u00f5es: mysql&gt; \\s &#8212;&#8212;&#8212;&#8212;&#8211; mysql Ver 14.14 Distrib 5.5.17, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/215"}],"collection":[{"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=215"}],"version-history":[{"count":20,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/215\/revisions"}],"predecessor-version":[{"id":239,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/215\/revisions\/239"}],"wp:attachment":[{"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=215"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=215"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}