otimizando aplicações em rails

Post on 15-Jul-2015

1.122 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Otimizando Aplicações em Rails

essa palestra será rápida

 ServidorActive Record / SQLRuby / RailsCacheBackgrounDRb MetalHTML, JS & CSS

Nginx, Apache

balanceadores de carga

joeandmotorboat.com/2008/02/28/apache-vs-nginx-web-server-performance-deathmatch/

Mongrel, Thin, Passenger

servidores de aplicação

http://izumi.plan99.net/blog/index.php/2008/03/31/benchmark-passenger-mod_rails-vs-mongrel-vs-thin/

Active Record / SQL

for list in List.all ... do some ... for contact in list.contacts ... do some ... endend

INCLUDE

for list in List.all(:include => :contacts) ... do some ... for contacts in list.contacts ... do some ... endend

INCLUDE

Rails não adiciona índices nas tabelasEXPLAIN ANALYZE SELECT * FROM contacts WHERE email = 'foo@bar.com';>> cost=0.00..25.38CREATE INDEX contacts_email_idx    ON contacts(email);>> cost=0.00..1.06

ÍNDICES

Newsletter#history>> Buscava dados de mais de 100 mensagens (total de envios, acessos, cliques, descadastros, informações geográficas...) em uma view e apresentava um gráfico.

Tempo médio do método: 18s CREATE TABLE messages_complete_history AS SELECT * FROM view_messages_complete_history;

Tempo médio do método: 0.3s >> Criação agendada para a madrugada com BackgroundRB   

TABELAS CONSOLIDADAS

COPY (SELECT * FROM contacts) TO 'path' WITH DELIMITER ';' CSV HEADER

Muitas ordens de magnitude mais rápido do que AR + FasterCSV

CSV EXPORT

postgres_timestamps pluginsobrescreve comportamento de created_at e updated_at do ARcria defaults e triggers automaticamente nas migraçõesbenchmarks que fiz: de 2 a 5% mais rápido em 1000 inserts. até 10% mais rápido em 1000 updates;

 >> Prometo para ainda este ano!  

WORKING ON

Ruby / Rails

require 'benchmark' Benchmark.bm do |x|x.report('foo') { ... code ... }x.report('bar') { ... code ... }end

BENCHMARK

def calculate_something @something = do_some_heavy_calculation end

||=

def calculate_something(*args) do_some_heavy_calculationendmemoize :calculate_something calculate_something(1) #Hit calculate_something(1) #Cachecalculate_something(1) #Cache calculate_something(2) #Hit

MEMOIZE

# environment startup file require 'geoip_city'GEOIPDB = GeoIPCity::Database.new('file.dat') # some controller or modelGEOIPDB.look_up(ip)

RAILS STARTUP

ids = @contacts.map(&:id) #badids = @contacts.map{|c| c.id} #ugly, but good

str = str.gsub(/java/, 'ruby')#badstr.gsub!(/java/, 'ruby') #good

DICAS GERAIS

Cache

# site controllercaches_page :index

PAGE CACHE

# login controllerbefore_filter :get_clientcaches_action :index

ACTION CACHE

# some view- cache :action_suffix => 'comments' do = render :partial => 'comments' # no controller...def create_comment ... expire_fragment :action => 'show_post', :action_suffix => 'comments'end

FRAGMENT CACHE

# some view- cache :key => @contact.updated_at do = render :partial => 'contact_info'# Expira automático, mas gera alguns arquivos ...

FRAGMENT CACHE

fresh_when    :last_modified => @product.published_at.utc,    :etag => @article

HTTP CLIENT CACHE

http://github.com/nkallen/cache-money/tree/master

  >> Try it out and tell us... 

CACHE-MONEY PLUGIN

Metal

class Go def self.call(env) if env["PATH_INFO"] =~ /^\/go\/view\/(\d+)/ id = $1 request = Rack::Request.new(env) delivery = Delivery.find id View.create :contact_id => delivery.contact_id, :message_id => delivery.message_id, :ip => request.ip delivery.contact.confirm! [200, {"Content-Type" => "text/html"}, [""]] else [404, {"Content-Type" => "text/html"}, ["Not Found"]] end endend

METAL

2-5x faster>> NÃO DEVERIA SE CHAMAR SPEED METAL?

METAL

BackgrounDRb

Pode executar tarefas em bg;Pode agendar tarefas para executar em bg;Pode executar tarefas periodicamente em bg;Pode até conversar via TCP;

class ContactsWorker < BackgrounDRb::MetaWorker set_worker_name :contacts_worker def delete(args) total = args[:contacts].size cache[:total] = total cache[:curr] = 0 cache[:msg] = Contact.delete_many(args[:contacts]) do cache[:curr] += 1 end endend # start worker on controller MiddleMan.worker(:contacts_worker).async_delete(:args => {:contacts => @contacts}, :job_key => @job_key)

# verify worker status via Ajaxt = MiddleMan.worker(:contacts_worker).ask_result(:total)c = MiddleMan.worker(:contacts_worker).ask_result(:curr)return render :json => [t, c]

EXECUTANDO UMA TAREFA

Média antes: 13s (muitas FKs! milhares de contatos!)Média depois: 0.1s (usuário pode trabalhar durante processo)

EXECUTANDO UMA TAREFA

MiddleMan.worker(:messenger_worker).enq_send_messages( :args => @message.id, :scheduled_at => @message.scheduled_at, :job_key => "message_#{@message.id}")

EXECUTANDO UMA TAREFA AGENDADA

# backgroundrb.yml:schedules: :table_cache_worker: :table_cache: :trigger_args: 0 30 4 * * * *

EXECUTANDO UMA TAREFA PERIÓDICA

HTML, JS & CSS

CSS PLEASE DONT USE FONT TAG

SPRITES *JSMINGZIP

HTTP CLIENT CACHE (304!)return render :nothing => true, :status => 304

Cloud Storage e CDN

static.mailee.me

top related