{"id":243,"date":"2011-12-17T13:32:14","date_gmt":"2011-12-17T16:32:14","guid":{"rendered":"http:\/\/wagnerbianchi.com\/blog\/?p=243"},"modified":"2012-02-01T11:21:06","modified_gmt":"2012-02-01T14:21:06","slug":"problemas-de-escala-de-usuarios-com-o-mysql","status":"publish","type":"post","link":"http:\/\/wagnerbianchi.com\/blog\/?p=243","title":{"rendered":"Problemas de escala de usu\u00e1rios com o MySQL"},"content":{"rendered":"<p>Essa semana tive um problema grave em um cliente que precisava escalar o n\u00fameros de conex\u00f5es simult\u00e2neas no MySQL de forma que estas conex\u00f5es superassem o n\u00famero de 2000. V\u00e1rios problemas foram analisados, desde pontos b\u00e1sicos como configura\u00e7\u00f5es do\u00a0pr\u00f3prio\u00a0servidor de bancos de dados MySQL como alguns pontos relacionados ao Kernel. Somente para situar o leitor em rela\u00e7\u00e3o ao que foi analisado, no MySQL, temos duas vari\u00e1veis muito importantes que determinam a quantidade de usu\u00e1rios que podem se conectar ao servidor de bancos de dados e tamb\u00e9m o n\u00fameros de tais conex\u00f5es que podem acontecer em um mesmo momento, ou seja, simult\u00e2neas.<\/p>\n<ol>\n<li><strong>max_connections<\/strong> &#8211; esse \u00e9 o par\u00e2metro que controla a quantidade de usu\u00e1rios que podem se conectar ao MySQL;<\/li>\n<li><strong>max_user_connections<\/strong> &#8211; esse \u00e9 o par\u00e2metro utilizado para configurar a quantidade de conex\u00f5es simult\u00e2neas que podem acontecer durante o funcionamento do MySQL &#8211; segundo o manual, manter o valor desta vari\u00e1vel como zero, \u00e9 o mesmo que dizer que a coisa \u00e9 ilimitada;<\/li>\n<\/ol>\n<p>Interessante sabermos que, al\u00e9m das vari\u00e1veis de ambiente, que s\u00e3o utilizadas para configurar os v\u00e1rios aspectos do MySQL e \u00e9 com elas que realizamos o tuning, temos tamb\u00e9m as vari\u00e1veis de status que cobrem todo o funcionamento do MySQL e \u00e9 atrav\u00e9s delas que consultamos o que est\u00e1 acontecendo com o servidor de bancos de dados. Com as quest\u00f5es relacionadas com usu\u00e1rios n\u00e3o \u00e9 diferente, veja s\u00f3:<\/p>\n<p><code>mysql&gt; show status like '%conn%';<br \/>\n+--------------------------+-------+<br \/>\n| Variable_name \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0| Value |<br \/>\n+--------------------------+-------+<br \/>\n| Aborted_connects \u00a0 \u00a0 \u00a0 \u00a0 | \u00a0 \u00a00 \u00a0|<br \/>\n| Connections \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0| 1387 \u00a0|<br \/>\n| Max_used_connections \u00a0 \u00a0 | \u00a0645 \u00a0|<br \/>\n| Ssl_client_connects \u00a0 \u00a0 \u00a0| \u00a0 \u00a00 \u00a0|<br \/>\n| Ssl_connect_renegotiates | \u00a0 \u00a00 \u00a0|<br \/>\n| Ssl_finished_connects \u00a0 \u00a0| \u00a0 \u00a00 \u00a0|<br \/>\n| Threads_connected \u00a0 \u00a0 \u00a0 \u00a0| \u00a0581 \u00a0|<br \/>\n+--------------------------+-------+<br \/>\n<\/code><br \/>\nSem pensar nas vari\u00e1veis SSL que foram retornadas na consulta acima, temos tr\u00eas vari\u00e1veis bastante importantes:\u00a0Aborted_connects,\u00a0Connections,\u00a0Max_used_connections. Cada uma delas tem um significado ligado diretamente \u00e0s conex\u00f5es de clientes\/usu\u00e1rios com o servidor de bancos de dados.<\/p>\n<ol>\n<li><strong>Aborted_Connects<\/strong>: se o n\u00famero desta vari\u00e1vel de status estiver alto voc\u00ea poder\u00e1 estar perdendo conex\u00f5es por quebra das mesmas, sua aplica\u00e7\u00e3o n\u00e3o est\u00e1 chamando um m\u00e9todo de de &#8220;connection_close&#8221; antes de fechar a conex\u00e3o ou mesmo, seu MySQL est\u00e1 evitando consultas;<\/li>\n<li><strong>Connections<\/strong>: \u00e9 n\u00famero total de conex\u00f5es que j\u00e1 acontecer\u00e3o desde o \u00faltimo restart;<\/li>\n<li><strong>Max_used_connections<\/strong>: \u00e9 o n\u00famero de conex\u00f5es simult\u00e2neas que acontecer\u00e3o desde \u00a0o \u00faltimo restart.<\/li>\n<\/ol>\n<p>Sendo assim, j\u00e1 temos um norte para trabalhar quest\u00f5es de escala de conex\u00f5es com o MySQL. J\u00e1 ouvi dizer sobre escalonador de threads e par\u00e2metros de kernel do Linux, mas, a coisa pode ser mais simples que isso. As configira\u00e7\u00f5es atuais de um servidor que tenho monitorado s\u00e3o as seguintes:<\/p>\n<p><code>mysql&gt; show variables like 'max_connections';<br \/>\n+-----------------+-------+<br \/>\n| Variable_name \u00a0 | Value |<br \/>\n+-----------------+-------+<br \/>\n| max_connections | 6000 \u00a0|<br \/>\n+-----------------+-------+<br \/>\n1 row in set (0.00 sec)<\/code><\/p>\n<p><code>mysql&gt; show variables like 'max_user%';<br \/>\n+----------------------+-------+<br \/>\n| Variable_name \u00a0 \u00a0 \u00a0 \u00a0| Value |<br \/>\n+----------------------+-------+<br \/>\n| max_user_connections | 0 \u00a0 \u00a0 |<br \/>\n+----------------------+-------+<br \/>\n1 row in set (0.00 sec)<\/code><\/p>\n<p>Com base nisso, passei a observar que quando as conex\u00f5es atingiam o n\u00famero de 1000 acontecendo de forma simult\u00e2nea, v\u00ed que o valor da vari\u00e1vel de status Aborted_Connects iniciava a aumentar freneticamente e \u00a0quando eu tentava acessar o MySQL via mysql client com qualuqer usu\u00e1rio, o seguinte mensagem de erro era enviada:<\/p>\n<p><code>Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug<\/code><\/p>\n<p>Ou seja, ou voc\u00ea est\u00e1 rodando o servidor de bancos de dados configurado com um valor de mem\u00f3ria al\u00e9m daquele que o servidor tem dispon\u00edvel ou existe um bug no sistema operacional. Por elimina\u00e7\u00e3o, o servidor aonde roda este MySQL tem 64GB e est\u00e1 com 16GB sobrando. Ent\u00e3o, esse problema tem havir com algo no sistema operacional. Pesquisando no internet, puder ver que outros amigos tiveram um cen\u00e1rio parecido e tamb\u00e9m criaram um blog sobre o assunto, como fez o amigo Dimitri em\u00a0http:\/\/bit.ly\/trVqL4.<\/p>\n<p>Seguindo mais ou menos o que ele relatou nesse seu blog, eu tinha os memos par\u00e2metros de ulimit para o usu\u00e1rio mysql (su &#8211; mysql), mas tinha um valor diferente para threads-max, um valor muito inferior ao mostrado por ele no blog, que \u00e9 2065067. Ent\u00e3o foi assim que procedi:<\/p>\n<ol>\n<li>Configurei a qtd m\u00e1xima de threads: echo &#8220;2065067&#8221; &gt; \/proc\/sys\/kernel\/threads-max<\/li>\n<li>Configurei o arquivo &#8220;limits.conf&#8221; para as sess\u00f5es dos usu\u00e1rios mysql e root:<\/li>\n<\/ol>\n<p><code>mysql soft nofile 10240<br \/>\nmysql hard nofile 40960<br \/>\nmysql soft nproc 10240<br \/>\nmysql hard nproc 40960<br \/>\nroot soft nofile 10240<br \/>\nroot hard nofile 40960<br \/>\nroot soft nproc 10240<br \/>\nroot hard nproc 40960<\/code><\/p>\n<p>A configura\u00e7\u00e3o n\u00famero dois me pareceu muito familiar e foi bem aceita, pois, isso j\u00e1 \u00e9 realizado quando se instala o Oracle Database. Ap\u00f3s feito isso, foram realizados v\u00e1rios um testes de stress com o <a title=\"mysqlslap\" href=\"http:\/\/tek.io\/vg5CS0\" target=\"_blank\">mysqlslap<\/a>, biblioteca de benchmark do pr\u00f3prio MySQL e o problema persistia. V\u00e1rios bin\u00e1rios foram testados para verificar quest\u00f5es de escala entre uma vers\u00e3o e outra:<\/p>\n<p><strong>MySQL Oracle 5.5.17<\/strong><\/p>\n<p><code>mysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nmysqlslap: Error when connecting to server: 1135 Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug<br \/>\nmysqlslap: Error when connecting to server: 1135 Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug<br \/>\nmysqlslap: Error when connecting to server: 1135 Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug<br \/>\nmysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nmysqlslap: Error when connecting to server: 1135 Can't create a new thread (errno 11); if you are not out of available memory, you can consult the manual for a possible OS-dependent bug<br \/>\nmysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nmysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nBenchmark<br \/>\nAverage number of seconds to run all queries: 4.117 seconds<br \/>\nMinimum number of seconds to run all queries: 4.117 seconds<br \/>\nMaximum number of seconds to run all queries: 4.117 seconds<br \/>\nNumber of clients running queries: 1200<br \/>\nAverage number of queries per client: 0<br \/>\n<\/code><br \/>\n<strong>MySQL Oracle 5.0.92<\/strong><\/p>\n<p><code>mysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nmysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nmysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nmysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nBenchmark<br \/>\nAverage number of seconds to run all queries: 3.049 seconds<br \/>\nMinimum number of seconds to run all queries: 3.049 seconds<br \/>\nMaximum number of seconds to run all queries: 3.049 seconds<br \/>\nNumber of clients running queries: 1200<br \/>\nAverage number of queries per client: 0<br \/>\n<\/code><br \/>\n<strong>Percona Server 5.5.17<\/strong><\/p>\n<p><code>mysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nmysqlslap: Error when connecting to server: 2001 Can't create UNIX socket (24)<br \/>\nBenchmark<br \/>\nAverage number of seconds to run all queries: 4.137 seconds<br \/>\nMinimum number of seconds to run all queries: 4.137 seconds<br \/>\nMaximum number of seconds to run all queries: 4.137 seconds<br \/>\nNumber of clients running queries: 1200<br \/>\nAverage number of queries per client: 0<\/code><\/p>\n<p>Os testes acima foram realizados em uma mesma m\u00e1quina com um arquivo de configura\u00e7\u00e3o padr\u00e3o, somente com o valor de max_connections=6000 e max_user_connections=o.<\/p>\n<p><code>[root@server mysql-coms]# my_print_defaults mysqld<br \/>\n--skip-external-locking<br \/>\n--port=3306<br \/>\n--socket=\/var\/lib\/mysql\/mysql.sock<br \/>\n--max_connections=6000<br \/>\n--max_user_connections=0<\/code><\/p>\n<p>Uma sa\u00edda l\u00f3gica foi checar de mais de perto o erro &#8220;Error when connecting to server: 2001 Can&#8217;t create UNIX socket (24)&#8221; que poderia estar limitando a cria\u00e7\u00e3o de mais threads, e por consequ\u00eancia mais usu\u00e1rios, no sistema operacional. Foi ent\u00e3o que achei o <a href=\"http:\/\/blog.dbadojo.com\/2008\/02\/mysql-vs-mysqlslap-round-3.html\" target=\"_blank\">MySQL Dojo<\/a>\u00a0aonde j\u00e1 haviam testado esses problemas e se baseavam no ulimit. Resumindo, explorar os valores configurados no ulimit, ou melhor, no arquivo limits.conf e aument\u00e1-los at\u00e9 que os testes fossem satisfat\u00f3rios. Ent\u00e3o foi assim:<\/p>\n<p><code>[root@server mysql-rpm]# ulimit -a mysql<br \/>\ncore file size (blocks, -c) 0<br \/>\ndata seg size (kbytes, -d) unlimited<br \/>\nscheduling priority (-e) 0<br \/>\nfile size (blocks, -f) unlimited<br \/>\npending signals (-i) 192031<br \/>\nmax locked memory (kbytes, -l) 64<br \/>\nmax memory size (kbytes, -m) unlimited<br \/>\nopen files (-n) 90000<br \/>\npipe size (512 bytes, -p) 8<br \/>\nPOSIX message queues (bytes, -q) 819200<br \/>\nreal-time priority (-r) 0<br \/>\nstack size (kbytes, -s) 90000<br \/>\ncpu time (seconds, -t) unlimited<br \/>\nmax user processes (-u) 90000<br \/>\nvirtual memory (kbytes, -v) unlimited<br \/>\nfile locks (-x) unlimited<\/code><\/p>\n<p><code>[root@server mysql-coms]# mysqlslap --user=root --auto-generate-sql --concurrency=1200 --number-of-queries=1<br \/>\nBenchmark<br \/>\nAverage number of seconds to run all queries: 5.775 seconds<br \/>\nMinimum number of seconds to run all queries: 5.775 seconds<br \/>\nMaximum number of seconds to run all queries: 5.775 seconds<br \/>\nNumber of clients running queries: 1200<br \/>\nAverage number of queries per client: 0<\/code><\/p>\n<p>E para provar que o MySQL est\u00e1 limitado somente pelo hardware ou ainda, neste caso, tamb\u00e9m pelas configura\u00e7\u00f5es do sistema operacional&#8230;<\/p>\n<p><code>[root@server mysql-coms]# mysqlslap --user=root --auto-generate-sql --concurrency=<strong>2000<\/strong> --number-of-queries=1<br \/>\nBenchmark<br \/>\nAverage number of seconds to run all queries: 18.367 seconds<br \/>\nMinimum number of seconds to run all queries: 18.367 seconds<br \/>\nMaximum number of seconds to run all queries: 18.367 seconds<br \/>\nNumber of clients running queries: <strong>2000<\/strong><br \/>\nAverage number of queries per client: 0<\/code><\/p>\n<p><code>[root@server mysql-coms]# mysqlslap --user=root --auto-generate-sql --concurrency=3000 --number-of-queries=1<br \/>\nBenchmark<br \/>\nAverage number of seconds to run all queries: 41.411 seconds<br \/>\nMinimum number of seconds to run all queries: 41.411 seconds<br \/>\nMaximum number of seconds to run all queries: 41.411 seconds<br \/>\nNumber of clients running queries: 3000<br \/>\nAverage number of queries per client: 0<\/code><\/p>\n<p>E assim, finalizo mais uma aventura com o MySQL e com miss\u00e3o cumprida! At\u00e9 breve&#8230;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Essa semana tive um problema grave em um cliente que precisava escalar o n\u00fameros de conex\u00f5es simult\u00e2neas no MySQL de forma que estas conex\u00f5es superassem o n\u00famero de 2000. V\u00e1rios problemas foram analisados, desde pontos b\u00e1sicos como configura\u00e7\u00f5es do\u00a0pr\u00f3prio\u00a0servidor de bancos de dados MySQL como alguns pontos relacionados ao Kernel. Somente para situar o leitor [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[17,1],"tags":[],"_links":{"self":[{"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/243"}],"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=243"}],"version-history":[{"count":22,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/243\/revisions"}],"predecessor-version":[{"id":313,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/243\/revisions\/313"}],"wp:attachment":[{"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=243"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=243"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/wagnerbianchi.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=243"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}