busca_1 Atendimento   (11) 3681-1177   busca_3 busca_4
Logo Centro de Treinamento especializado em Ruby e Ruby on Rails rubyonrails

Pdf

Performance, escalabilidade, ruby-vms e nossa experiência

Sem dúvida este é o ano da promessa para as Ruby Machines. Este assunto já me interessava, mas quando tivemos solucionar o problema de consumo de memória do site de um cliente em Ruby on Rails o assunto teve que ser estudado a fundo. Gargabe Collector, Tuning no Rails, etc. E não só isso, vários testes sobre o MRI (versão oficial do Ruby 1.8.6) e sobre o JRuby foram feitos a ponto de massacrar um servidor de testes. A partir dai ganhamos uma experiência nova, sempre aprendemos mais com os problemas e quero compartilhar essa experiência com você !
 O problema !
Bom, tudo começou quando o servidor de um cliente que possue nosso ERP (que atualmente está 40% migrado para Rails), esteve com problemas de uso absurdo de memória. É um servidor Linux, e a swap chegava a ser usada a ponto de inviabilizar seu uso. Era uma daquelas situações que só dando um restart nos servidos resolveria o problema. Além do ERP o servidor possuia o E-commerce integrado a ele. Este totalmente escrito em Ruby on Rails.
 Investigando...
Resolvi então examinar onde era o problema, e após colocar o site na minha máquina utilizei o monit (vou falar dele logo a frente) para verificar o consumo de memória. Com um script bem simples carregava a index do site várias vezes. E para minha surpresa o site em apenas 10 minutos ele consumia 100 mb. O mesmo site coloquei em nosso servidor de testes e após 44 minutos ele consumia 300 mega de swap. A máquina possuia 512 mb de ram.
Não havia dúvidas que o problema era o site, então criei um index em branco com um render :text => 'alguma coisa' e efetuei os testes. A memória simplesmente não subia. Minha idéia era verificar se havia algum prolbema com o mongrel ou alguma customização do rails feita por nós. Então depois de vários testes descobrimos os gargalos. Uma consulta no ActiveRecord fazia uma busca de Produto onde possuia vários relacionamentos e o pior é que o Produto possuia uma relação has_many (1 para muitos) para Preco e Estoque. O resultado de nossa consulta era perfeita para trabalharmos pois ele retorna uma instancia de produto que podiamos fazer produto.precos[0].custo, ou, produto.estoques[0].quantidade. E a consulta garantia que viria apenas um registro de Preco/Estoque.
Outro gargalo era uma consulta pelo ActiveRecord de Categoria e Sub-Categoria onde era feita um each dentro de outro each para localizar as categorias.
 A solução !
Esta parte foi até simples, substituimos a consulta feita pelo ActiveRecor::Base.find, por uma em SQL. Mas também NÃO utilizamos find_by_sql. Por quê ? Porque em find_by_sql ele retorna uma instancia do objeto que você está consultando exemplo: Produto.find_by_sql "SELECT *...", o resultado é um array contendo nele instâncias de Produto. Caso exista um relacionamento de belongs_to ou has_many você não conseguirá acessar valores que na consulta sql tenham o mesmo nome do relacionamento, exemplo:

class Produto
has_many :estoque
end

Produto.find_by_sql "SELECT produto.id, estoque.quantidade as estoque"

O campo nomeado como estoque possue o mesmo nome do relacionamento assim eles "trobam", isso pode parecer contornável, mas em query extremamentes complexas isto sim pode gerar problemas.
 Hash ao invés de instâncias
Além do problema de colisão de nomes, existe o overhead de instanciar um objeto Produto para cada registro encontrado, então utilizamos:
ActiveRecord::Base.connection.select_all
você pode utilizar internamente em suas classes fazendo:

class Produto
def find_em_promocao(data)
connection.select_all 'SELECT * ...'
end
end

Isso retornará um Array, e dentro de cada array uma hash com uma string como indice.
Esta é uma solução que propõem plugins como hash_extension. http://enterpriserails.rubyforge.org/hash_extension No link abaixo título é interessante: "ActiveRecord is slow. Hashes are fast" que pode ser conferido aqui: http://blog.chak.org/tag/hash/
Primeira_offAnterior_off 1 2 3 Proxima_onUltima_on
Object Training
Rua Carlos da Costa Ramalho Junior, 201
Próximo as estações Osasco e Pres. Altino do Trem.
COPYRIGHT