Publicado por Levy Carneiro Jr. em 18 de February de 2009
Um adaptador MySQL para escalar sua aplicação
O sempre popular MySQL é muito usado por aplicações Rails. E como você sabe o adaptador padrão que geralmente usamos em uma aplicação Rails é o ruby mysql:
production:
adapter: mysql
database: myapp_production
username: root
password:
host: localhost
Este adaptador faz um lock no interpretador MRI (o interpretador Ruby mais utilizado), fazendo com que sua aplicação fique esperando o resultado da consulta ao banco para poder continuar. Então mesmo que você crie várias threads, cada uma com uma conexão ao MySQL simplesmente esperando por uma query SQL, quando a query for realmente enviada ao banco de dados o adaptador ruby mysql vai segurar a onda, "travando" a aplicação, e só retornando quando uma query for concluída. Por que isso acontece? Porque esta biblioteca é síncrona. Bom, isto não escala muito bem, certo?
A boa notícia é que foi lançada a primeira versão de produção de um novo adaptador para o MySQL, chamada mysqlplus. Com este adaptador, as operações no banco de dados são feitas de forma assíncrona, deixando a aplicação livre para processar outras instruções.
E já que desde a versão 2.2 do Rails, temos o recurso de connection pooling, e o framework também é ThreadSafe (o framework, não o código criado pelo usuário, ou plugins e gems) podemos usar:
config.threadsafe!
Esta configuração remove o lock global do Dispatcher, e permite que à cada requisição seja designada uma conexão do pool.
Finalmente para poder utilizar o adaptador mysqlplus você precisa trocar mysql por mysqlplus em seu arquivo database.yml:
production:
adapter: mysqlplus
database: myapp_production
username: root
password:
host: localhost
pool: 10
Existem diversos recursos oferecidos com esta nova biblioteca. Dentre eles temos o Warmup, que permite que as conexões do pool sejam estabelecidas com antecedência, para sites com muito tráfego. Deferrable Results possibilita que o controller envie uma query ao banco de dados para ser rodada em background, retornando o processamento à aplicação, mas referenciando o resultado na view, dessa forma permitindo que o controller tenha um fôlego adicional (de alguns milisegundos) para terminar de rodar a renderização do template (na verdade tudo que acontecer entre o Post.find() e a renderização da view, por exemplo). Isto é muito interessante para escalar sites, aumentando a responsividade de uma página. Você também pode desabilitar o Garbage Collector do MySQL, que por padrão roda a cada 20 queries.
O adaptador expõe seus métodos assíncronos através da instância de conexão:
MysqlUser.connection.send_query( "SELECT * FROM mysql.user WHERE User = 'root'" ) # Retorna no mesmo instante, sem espera por operações de IO
MysqlUser.connection.get_result # Retorna o resultado da query assíncrona prévia
Existe um pequeno cuidado que deve ser tomado:
Model.connection.send_query( "first query" )
Model.connection.send_query( "second query" )
Model.connection.get_result # Retorna o resultado de "second query"
Para mais informações sobre a biblioteca, vá direto ao repositório no Github.

Clique aqui para adicionar ao del.icio.us

19 de February de 2009 às 17:22
Eu ganho alguma vantagem com esse adapter usando o Ruby 1.8?
19 de February de 2009 às 23:30
Pablo, sim.
Como na realidade este adapter precisa de threads, você precisa usar Rails 2.2 ou maior.
06 de March de 2009 às 12:01
[...] entra Lourens Naudé, o mesmo criador do mysqlplus_adapter, que criou um plugin chamado [...]