SlideShare une entreprise Scribd logo
1  sur  164
Télécharger pour lire hors ligne
DICAS DE PERFORMANCE
WEB
Fabio Akita @AkitaOnRails
Back EndBrowser
Front End
Render
External
Services
9 DICAS
SLIDESHARE.NET/
AKITAONRAILS
MONITORING
1.4 MILHOES DEVISITANTES
UNICOS!!
Ruby 2.1
Ruby 2.2
CACHING
def	
  sitemap	
  
	
  	
  sleep	
  3	
  
	
  	
  @posts	
  =	
  Post.select([	
  :id,	
  :slug,	
  :updated_at,	
  :published_at	
  ]).published	
  
	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  format.xml	
  {	
  render	
  layout:	
  false	
  }	
  
	
  	
  end	
  
end
Processing	
  by	
  ArchivesController#sitemap	
  as	
  XML	
  
	
  	
  Rendered	
  archives/sitemap.xml.builder	
  (785.5ms)	
  
Completed	
  200	
  OK	
  in	
  3879.4ms	
  (Views:	
  770.4ms	
  |	
  ActiveRecord:	
  18.7ms	
  |	
  Solr:	
  0.0ms)
def	
  sitemap	
  
	
  	
  @posts	
  =	
  cache('sitemap',	
  :expires_in	
  =>	
  12.hours)	
  {	
  
	
  	
  	
  	
  sleep	
  3	
  
	
  	
  	
  	
  Post.select([	
  :id,	
  :slug,	
  :updated_at,	
  :published_at	
  ]).published	
  
	
  	
  }	
  
	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  format.xml	
  {	
  render	
  layout:	
  false	
  }	
  
	
  	
  end	
  
end
Processing	
  by	
  ArchivesController#sitemap	
  as	
  XML	
  
	
  	
  Rendered	
  archives/sitemap.xml.builder	
  (763.3ms)	
  
Completed	
  200	
  OK	
  in	
  842.4ms	
  (Views:	
  754.2ms	
  |	
  ActiveRecord:	
  13.3ms	
  |	
  Solr:	
  0.0ms)
def	
  sitemap	
  
	
  	
  @posts	
  =	
  cache('sitemap',	
  :expires_in	
  =>	
  12.hours)	
  {	
  
	
  	
  	
  	
  Post.select([	
  :id,	
  :slug,	
  :updated_at,	
  :published_at	
  ]).published	
  
	
  	
  }	
  
	
  	
  if	
  stale?(last_modified:	
  @posts.first.updated_at.utc,	
  
	
  	
  	
  	
  etag:	
  "posts/#{@posts.count}-­‐#{@posts.first.updated_at.utc}")	
  
	
  	
  	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  	
  	
  format.xml	
  {	
  render	
  layout:	
  false	
  }	
  
	
  	
  	
  	
  end	
  
	
  	
  end	
  
end
Processing	
  by	
  ArchivesController#sitemap	
  as	
  XML	
  
Completed	
  304	
  Not	
  Modified	
  in	
  6.2ms	
  (ActiveRecord:	
  1.7ms)
2s!
198ms!
ASSET PIPELINE
}
}
UPLOADS
Browser
1s
BackendBrowser
1s
Image
Magick
BackendBrowser
1s
S3
Image
Magick
BackendBrowser
1s
S3
Image
Magick
BackendBrowser
1s 2 segundos
Browser
1s
Browser
1s
S3
BackendBrowser
1s
S3
BackendBrowser
1s 200 ms
S3
BackendBrowser
1s 200 ms
S3
Image
Magick
700 ms
#	
  Gemfile	
  
gem	
  'cloudinary'	
  
gem	
  'attachinary'
#	
  Gemfile	
  
gem	
  'cloudinary'	
  
gem	
  'attachinary'
#	
  config/cloudinary.yml	
  
production:	
  
	
  	
  cloud_name:	
  "sample"	
  
	
  	
  api_key:	
  "874837483274837"	
  
	
  	
  api_secret:	
  "a676b67565c6767a6767d6767f676fe1"
#	
  Gemfile	
  
gem	
  'cloudinary'	
  
gem	
  'attachinary'
#	
  config/cloudinary.yml	
  
production:	
  
	
  	
  cloud_name:	
  "sample"	
  
	
  	
  api_key:	
  "874837483274837"	
  
	
  	
  api_secret:	
  "a676b67565c6767a6767d6767f676fe1"#	
  app/models/user.rb	
  
class	
  User	
  <	
  ActiveRecord::Base	
  
	
  	
  attr_accessible	
  :name	
  
	
  	
  	
  
	
  	
  has_attachment	
  	
  :avatar	
  
	
  	
  has_attachments	
  :photos,	
  maximum:	
  3	
  
end
#	
  Gemfile	
  
gem	
  'cloudinary'	
  
gem	
  'attachinary'
#	
  config/cloudinary.yml	
  
production:	
  
	
  	
  cloud_name:	
  "sample"	
  
	
  	
  api_key:	
  "874837483274837"	
  
	
  	
  api_secret:	
  "a676b67565c6767a6767d6767f676fe1"#	
  app/models/user.rb	
  
class	
  User	
  <	
  ActiveRecord::Base	
  
	
  	
  attr_accessible	
  :name	
  
	
  	
  	
  
	
  	
  has_attachment	
  	
  :avatar	
  
	
  	
  has_attachments	
  :photos,	
  maximum:	
  3	
  
end
#	
  app/views/users/_form.html.slim	
  
=	
  form_for(@user)	
  do	
  |user_form|	
  
	
  	
  	
  	
  =	
  user_form.text_field(:name)	
  
	
  	
  	
  	
  =	
  attachinary_file_field_tag	
  ‘user[avatar]',	
  
	
  	
  	
  	
  	
  	
  @user,	
  :avatar	
  
	
  	
  	
  	
  =	
  attachinary_file_field_tag	
  ‘user[photos]’,	
  
	
  	
  	
  	
  	
  	
  @user,	
  :photos	
  
	
  	
  	
  	
  =	
  user_form.submit("Save")
#	
  Gemfile	
  
gem	
  'cloudinary'	
  
gem	
  'attachinary'
#	
  config/cloudinary.yml	
  
production:	
  
	
  	
  cloud_name:	
  "sample"	
  
	
  	
  api_key:	
  "874837483274837"	
  
	
  	
  api_secret:	
  "a676b67565c6767a6767d6767f676fe1"#	
  app/models/user.rb	
  
class	
  User	
  <	
  ActiveRecord::Base	
  
	
  	
  attr_accessible	
  :name	
  
	
  	
  	
  
	
  	
  has_attachment	
  	
  :avatar	
  
	
  	
  has_attachments	
  :photos,	
  maximum:	
  3	
  
end
#	
  app/views/users/_form.html.slim	
  
=	
  form_for(@user)	
  do	
  |user_form|	
  
	
  	
  	
  	
  =	
  user_form.text_field(:name)	
  
	
  	
  	
  	
  =	
  attachinary_file_field_tag	
  ‘user[avatar]',	
  
	
  	
  	
  	
  	
  	
  @user,	
  :avatar	
  
	
  	
  	
  	
  =	
  attachinary_file_field_tag	
  ‘user[photos]’,	
  
	
  	
  	
  	
  	
  	
  @user,	
  :photos	
  
	
  	
  	
  	
  =	
  user_form.submit("Save")
#	
  app/controllers/users_controller.rb	
  
...	
  
	
  	
  def	
  create	
  
	
  	
  	
  	
  @user	
  =	
  User.new(params[:user])	
  
	
  	
  	
  	
  @user.save!	
  
	
  	
  end
#	
  app/views/users/show.html.slim	
  
-­‐	
  if	
  user.avatar.present?	
  
	
  	
  =	
  cl_image_tag(user.avatar.path,	
  width:	
  80,	
  height:	
  100,	
  crop:	
  :thumb,	
  gravity:	
  :face)	
  
	
  	
  -­‐	
  user.photos.each	
  do	
  |photo|	
  
	
  	
  	
  	
  =	
  cl_image_tag(photo.path,	
  size:	
  '70x50',	
  crop:	
  :fill,	
  radius:	
  20)
#	
  Gemfile	
  
gem	
  'cloudinary'	
  
gem	
  'attachinary'
#	
  config/cloudinary.yml	
  
production:	
  
	
  	
  cloud_name:	
  "sample"	
  
	
  	
  api_key:	
  "874837483274837"	
  
	
  	
  api_secret:	
  "a676b67565c6767a6767d6767f676fe1"#	
  app/models/user.rb	
  
class	
  User	
  <	
  ActiveRecord::Base	
  
	
  	
  attr_accessible	
  :name	
  
	
  	
  	
  
	
  	
  has_attachment	
  	
  :avatar	
  
	
  	
  has_attachments	
  :photos,	
  maximum:	
  3	
  
end
#	
  app/views/users/_form.html.slim	
  
=	
  form_for(@user)	
  do	
  |user_form|	
  
	
  	
  	
  	
  =	
  user_form.text_field(:name)	
  
	
  	
  	
  	
  =	
  attachinary_file_field_tag	
  ‘user[avatar]',	
  
	
  	
  	
  	
  	
  	
  @user,	
  :avatar	
  
	
  	
  	
  	
  =	
  attachinary_file_field_tag	
  ‘user[photos]’,	
  
	
  	
  	
  	
  	
  	
  @user,	
  :photos	
  
	
  	
  	
  	
  =	
  user_form.submit("Save")
#	
  app/controllers/users_controller.rb	
  
...	
  
	
  	
  def	
  create	
  
	
  	
  	
  	
  @user	
  =	
  User.new(params[:user])	
  
	
  	
  	
  	
  @user.save!	
  
	
  	
  end
CDN
AssetsRailsBrowser
1s 5 segundos
Assets
RailsBrowser
1s 200 ms
4 segundos
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://www.mydomain.com/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://www.mydomain.com/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://www.mydomain.com/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://www.mydomain.com/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://d3vam04na8c92l.cloudfront.net/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
http://www.mydomain.com/stylesheets/application-6502e5a88f02b90aeb32c2dd21ea37ab.css
#	
  config/environments/production.rb	
  
config.action_controller.asset_host	
  =	
  "d3vam04na8c92l.cloudfront.net"
<%=	
  stylesheet_link_tag	
  	
  	
  	
  "application",	
  :media	
  =>	
  "all"	
  %>	
  
<%=	
  javascript_include_tag	
  "application"	
  %>	
  
<%=	
  image_tag("rails.png")	
  %>
<link	
  href="http://d3vam04na8c92l.cloudfront.net/stylesheets/application-­‐6502e5a88f02b90aeb32c2dd21ea37ab.css"	
  rel="stylesheet"	
  />
DATABASE
#	
  Gemfile	
  
gem	
  "lol_dba",	
  group:	
  :development	
  
#	
  no	
  Terminal	
  
bundle	
  install	
  
bundle	
  exec	
  rake	
  db:find_indexes
#	
  app/controllers/posts_controller.rb	
  
def	
  index	
  
	
  	
  @posts	
  =	
  Post.all	
  
	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  format.html	
  #	
  index.html.erb	
  
	
  	
  	
  	
  format.xml	
  	
  {	
  render	
  :xml	
  =>	
  @posts	
  }	
  
	
  	
  end	
  
end
#	
  app/controllers/posts_controller.rb	
  
def	
  index	
  
	
  	
  @posts	
  =	
  Post.all	
  
	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  format.html	
  #	
  index.html.erb	
  
	
  	
  	
  	
  format.xml	
  	
  {	
  render	
  :xml	
  =>	
  @posts	
  }	
  
	
  	
  end	
  
end
<%	
  @posts.each	
  do	
  |post|	
  %>	
  
	
  	
  <tr>	
  
	
  	
  	
  	
  <td><%=	
  post.name	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  post.comments.size	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Show',	
  post	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Edit',	
  edit_post_path(post)	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Destroy',	
  post,	
  confirm:	
  'Are	
  you	
  sure?',	
  method:	
  :delete	
  %></td>	
  
	
  	
  </tr>	
  
<%	
  end	
  %>
#	
  app/controllers/posts_controller.rb	
  
def	
  index	
  
	
  	
  @posts	
  =	
  Post.all	
  
	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  format.html	
  #	
  index.html.erb	
  
	
  	
  	
  	
  format.xml	
  	
  {	
  render	
  :xml	
  =>	
  @posts	
  }	
  
	
  	
  end	
  
end
<%	
  @posts.each	
  do	
  |post|	
  %>	
  
	
  	
  <tr>	
  
	
  	
  	
  	
  <td><%=	
  post.name	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  post.comments.size	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Show',	
  post	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Edit',	
  edit_post_path(post)	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Destroy',	
  post,	
  confirm:	
  'Are	
  you	
  sure?',	
  method:	
  :delete	
  %></td>	
  
	
  	
  </tr>	
  
<%	
  end	
  %>
Started	
  GET	
  "/posts/"	
  for	
  192.168.47.2	
  at	
  2015-­‐03-­‐23	
  18:31:11	
  +0000	
  
Cannot	
  render	
  console	
  from	
  192.168.47.2!	
  Allowed	
  networks:	
  127.0.0.1,	
  ::1,	
  127.0.0.0/127.255.255.255	
  
	
  	
  ActiveRecord::SchemaMigration	
  Load	
  (0.1ms)	
  	
  SELECT	
  "schema_migrations".*	
  FROM	
  "schema_migrations"	
  
Processing	
  by	
  PostsController#index	
  as	
  HTML	
  
	
  	
  Post	
  Load	
  (0.2ms)	
  	
  SELECT	
  "posts".*	
  FROM	
  "posts"	
  
	
  	
  Comment	
  Load	
  (0.2ms)	
  	
  SELECT	
  "comments".*	
  FROM	
  "comments"	
  WHERE	
  "comments"."post_id"	
  =	
  ?	
  	
  [["post_id",	
  1]]	
  
	
  	
  Comment	
  Load	
  (0.1ms)	
  	
  SELECT	
  "comments".*	
  FROM	
  "comments"	
  WHERE	
  "comments"."post_id"	
  =	
  ?	
  	
  [["post_id",	
  2]]	
  
	
  	
  Rendered	
  posts/index.html.erb	
  within	
  layouts/application	
  (25.3ms)	
  
Completed	
  200	
  OK	
  in	
  679ms	
  (Views:	
  666.4ms	
  |	
  ActiveRecord:	
  1.0ms)
#	
  app/controllers/posts_controller.rb	
  
def	
  index	
  
	
  	
  @posts	
  =	
  Post.all	
  
	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  format.html	
  #	
  index.html.erb	
  
	
  	
  	
  	
  format.xml	
  	
  {	
  render	
  :xml	
  =>	
  @posts	
  }	
  
	
  	
  end	
  
end
<%	
  @posts.each	
  do	
  |post|	
  %>	
  
	
  	
  <tr>	
  
	
  	
  	
  	
  <td><%=	
  post.name	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  post.comments.size	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Show',	
  post	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Edit',	
  edit_post_path(post)	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Destroy',	
  post,	
  confirm:	
  'Are	
  you	
  sure?',	
  method:	
  :delete	
  %></td>	
  
	
  	
  </tr>	
  
<%	
  end	
  %>
Started	
  GET	
  "/posts/"	
  for	
  192.168.47.2	
  at	
  2015-­‐03-­‐23	
  18:31:11	
  +0000	
  
Cannot	
  render	
  console	
  from	
  192.168.47.2!	
  Allowed	
  networks:	
  127.0.0.1,	
  ::1,	
  127.0.0.0/127.255.255.255	
  
	
  	
  ActiveRecord::SchemaMigration	
  Load	
  (0.1ms)	
  	
  SELECT	
  "schema_migrations".*	
  FROM	
  "schema_migrations"	
  
Processing	
  by	
  PostsController#index	
  as	
  HTML	
  
	
  	
  Post	
  Load	
  (0.2ms)	
  	
  SELECT	
  "posts".*	
  FROM	
  "posts"	
  
	
  	
  Comment	
  Load	
  (0.2ms)	
  	
  SELECT	
  "comments".*	
  FROM	
  "comments"	
  WHERE	
  "comments"."post_id"	
  =	
  ?	
  	
  [["post_id",	
  1]]	
  
	
  	
  Comment	
  Load	
  (0.1ms)	
  	
  SELECT	
  "comments".*	
  FROM	
  "comments"	
  WHERE	
  "comments"."post_id"	
  =	
  ?	
  	
  [["post_id",	
  2]]	
  
	
  	
  Rendered	
  posts/index.html.erb	
  within	
  layouts/application	
  (25.3ms)	
  
Completed	
  200	
  OK	
  in	
  679ms	
  (Views:	
  666.4ms	
  |	
  ActiveRecord:	
  1.0ms)
Started	
  GET	
  "/posts/"	
  for	
  192.168.47.2	
  at	
  2015-­‐03-­‐23	
  18:37:31	
  +0000	
  
Cannot	
  render	
  console	
  from	
  192.168.47.2!	
  Allowed	
  networks:	
  127.0.0.1,	
  ::1,	
  127.0.0.0/127.255.255.255	
  
	
  	
  ActiveRecord::SchemaMigration	
  Load	
  (0.1ms)	
  	
  SELECT	
  "schema_migrations".*	
  FROM	
  "schema_migrations"	
  
Processing	
  by	
  PostsController#index	
  as	
  HTML	
  
	
  	
  Post	
  Load	
  (0.2ms)	
  	
  SELECT	
  "posts".*	
  FROM	
  "posts"	
  
	
  	
  Comment	
  Load	
  (0.2ms)	
  	
  SELECT	
  "comments".*	
  FROM	
  "comments"	
  WHERE	
  "comments"."post_id"	
  IN	
  (1,	
  2)	
  
	
  	
  Rendered	
  posts/index.html.erb	
  within	
  layouts/application	
  (25.8ms)	
  
Completed	
  200	
  OK	
  in	
  109ms	
  (Views:	
  96.4ms	
  |	
  ActiveRecord:	
  0.9ms)
#	
  app/controllers/posts_controller.rb	
  
def	
  index	
  
	
  	
  @posts	
  =	
  Post.includes(:comments).all	
  
	
  	
  respond_to	
  do	
  |format|	
  
	
  	
  	
  	
  format.html	
  #	
  index.html.erb	
  
	
  	
  	
  	
  format.xml	
  	
  {	
  render	
  :xml	
  =>	
  @posts	
  }	
  
	
  	
  end	
  
end
<%	
  @posts.each	
  do	
  |post|	
  %>	
  
	
  	
  <tr>	
  
	
  	
  	
  	
  <td><%=	
  post.name	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  post.comments.size	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Show',	
  post	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Edit',	
  edit_post_path(post)	
  %></td>	
  
	
  	
  	
  	
  <td><%=	
  link_to	
  'Destroy',	
  post,	
  confirm:	
  'Are	
  you	
  sure?',	
  method:	
  :delete	
  %></td>	
  
	
  	
  </tr>	
  
<%	
  end	
  %>
SEARCH
ASYNC JOBS
Browser
1s
BackendBrowser
1s
Tarefa DemoradaBackendBrowser
1s
Tarefa DemoradaBackendBrowser
1s 4 segundos
Browser
1s
BackendBrowser
1s
BackendBrowser
1s
Redis
BackendBrowser
1s 200 ms
Redis
BackendBrowser
1s 200 ms
Redis
Tarefa Demorada
(Worker)
3.8 segundos
class	
  VerySlowJob	
  <	
  ActiveJob::Base	
  
	
  	
  queue_as	
  :default	
  
	
  	
  
	
  	
  def	
  perform(*args)	
  
	
  	
  	
  	
  #	
  Tarefa	
  Demorada	
  
	
  	
  end	
  
end
class	
  VerySlowJob	
  <	
  ActiveJob::Base	
  
	
  	
  queue_as	
  :default	
  
	
  	
  
	
  	
  def	
  perform(*args)	
  
	
  	
  	
  	
  #	
  Tarefa	
  Demorada	
  
	
  	
  end	
  
end
VerySlowJob.perform_later	
  record
class	
  VerySlowJob	
  <	
  ActiveJob::Base	
  
	
  	
  queue_as	
  :default	
  
	
  	
  
	
  	
  def	
  perform(*args)	
  
	
  	
  	
  	
  #	
  Tarefa	
  Demorada	
  
	
  	
  end	
  
end
VerySlowJob.perform_later	
  record
VerySlowJob.set(wait_until:	
  
Date.tomorrow.noon).perform_later(record)
class	
  VerySlowJob	
  <	
  ActiveJob::Base	
  
	
  	
  queue_as	
  :default	
  
	
  	
  
	
  	
  def	
  perform(*args)	
  
	
  	
  	
  	
  #	
  Tarefa	
  Demorada	
  
	
  	
  end	
  
end
VerySlowJob.set(wait:	
  1.week).perform_later(record)
VerySlowJob.perform_later	
  record
VerySlowJob.set(wait_until:	
  
Date.tomorrow.noon).perform_later(record)
#	
  app/workers/report_job.rb	
  
class	
  ReportJob	
  <	
  ActiveJob::Base	
  
	
  	
  queue_as	
  :default	
  
	
  	
  
	
  	
  def	
  perform(email,	
  from_date	
  =	
  nil,	
  to_date	
  =	
  nil)	
  
	
  	
  	
  	
  now	
  =	
  Time.zone.now	
  
	
  	
  	
  	
  from_date	
  ||=	
  now	
  -­‐	
  1.year	
  
	
  	
  	
  	
  to_date	
  	
  	
  ||=	
  now	
  
	
  	
  	
  	
  file_path	
  =	
  ModelGigante.generate_excel(from_date,	
  to_date)	
  
	
  	
  	
  	
  NotifyReportMailer.send(email,	
  file_path)	
  
	
  	
  end	
  
end
#	
  app/controllers/reports_controller.rb	
  
#	
  ...	
  
def	
  create	
  
	
  	
  ReportJob.perform_later(params[:email],	
  
	
  	
  	
  	
  params[:from_date],	
  params[:to_date])	
  
	
  	
  flash[:notice]	
  =	
  "Report	
  is	
  being	
  generated.	
  
	
  	
  	
  	
  It	
  will	
  be	
  sent	
  to	
  your	
  email."	
  
	
  	
  redirect_to	
  reports_path	
  
end	
  
#	
  ...
#	
  app/workers/report_job.rb	
  
class	
  ReportJob	
  <	
  ActiveJob::Base	
  
	
  	
  queue_as	
  :default	
  
	
  	
  
	
  	
  def	
  perform(email,	
  from_date	
  =	
  nil,	
  to_date	
  =	
  nil)	
  
	
  	
  	
  	
  now	
  =	
  Time.zone.now	
  
	
  	
  	
  	
  from_date	
  ||=	
  now	
  -­‐	
  1.year	
  
	
  	
  	
  	
  to_date	
  	
  	
  ||=	
  now	
  
	
  	
  	
  	
  file_path	
  =	
  ModelGigante.generate_excel(from_date,	
  to_date)	
  
	
  	
  	
  	
  NotifyReportMailer.send(email,	
  file_path)	
  
	
  	
  end	
  
end
ASYNC MESSAGES
http://blog.tryneighborly.com/amazon-sns-for-apns-on-rails/
<!-­‐-­‐	
  chat.html	
  -­‐-­‐>	
  
<script	
  src="//js.pusher.com/2.2/pusher.min.js"></script>	
  
<script>	
  
$(function()	
  {	
  
	
  	
  	
  	
  var	
  pusher	
  =	
  new	
  Pusher('YOUR_APP_KEY');	
  
	
  	
  	
  	
  var	
  channel	
  =	
  pusher.subscribe('my-­‐app-­‐chat');	
  
	
  	
  	
  	
  channel.bind('new-­‐message',	
  function(data)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $('#chat-­‐box').append(data.message);	
  
	
  	
  	
  	
  });	
  
})	
  
</script>
<!-­‐-­‐	
  chat.html	
  -­‐-­‐>	
  
<script	
  src="//js.pusher.com/2.2/pusher.min.js"></script>	
  
<script>	
  
$(function()	
  {	
  
	
  	
  	
  	
  var	
  pusher	
  =	
  new	
  Pusher('YOUR_APP_KEY');	
  
	
  	
  	
  	
  var	
  channel	
  =	
  pusher.subscribe('my-­‐app-­‐chat');	
  
	
  	
  	
  	
  channel.bind('new-­‐message',	
  function(data)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $('#chat-­‐box').append(data.message);	
  
	
  	
  	
  	
  });	
  
})	
  
</script>
#	
  config/initializer/pusher.rb	
  
Pusher.app_id	
  =	
  ENV['PUSHER_APP_ID']	
  
Pusher.key	
  	
  	
  	
  =	
  ENV['PUSHER_APP_KEY']	
  
Pusher.secret	
  =	
  ENV['PUSHER_APP_SECRET']	
  
<!-­‐-­‐	
  chat.html	
  -­‐-­‐>	
  
<script	
  src="//js.pusher.com/2.2/pusher.min.js"></script>	
  
<script>	
  
$(function()	
  {	
  
	
  	
  	
  	
  var	
  pusher	
  =	
  new	
  Pusher('YOUR_APP_KEY');	
  
	
  	
  	
  	
  var	
  channel	
  =	
  pusher.subscribe('my-­‐app-­‐chat');	
  
	
  	
  	
  	
  channel.bind('new-­‐message',	
  function(data)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $('#chat-­‐box').append(data.message);	
  
	
  	
  	
  	
  });	
  
})	
  
</script>
#	
  config/initializer/pusher.rb	
  
Pusher.app_id	
  =	
  ENV['PUSHER_APP_ID']	
  
Pusher.key	
  	
  	
  	
  =	
  ENV['PUSHER_APP_KEY']	
  
Pusher.secret	
  =	
  ENV['PUSHER_APP_SECRET']	
  
#	
  app/workers/new_message_worker.rb	
  
require	
  'pusher'	
  
class	
  NewMessageWorker	
  
	
  	
  include	
  Sidekiq::Worker	
  
	
  	
  	
  
	
  	
  def	
  perform(message_id)	
  
	
  	
  	
  	
  @message	
  =	
  Message.find(message_id)	
  
	
  	
  	
  	
  Pusher.trigger('my-­‐app-­‐chat',	
  'new-­‐message',	
  {:message	
  =>	
  @message})	
  
	
  	
  end	
  
end
<!-­‐-­‐	
  chat.html	
  -­‐-­‐>	
  
<script	
  src="//js.pusher.com/2.2/pusher.min.js"></script>	
  
<script>	
  
$(function()	
  {	
  
	
  	
  	
  	
  var	
  pusher	
  =	
  new	
  Pusher('YOUR_APP_KEY');	
  
	
  	
  	
  	
  var	
  channel	
  =	
  pusher.subscribe('my-­‐app-­‐chat');	
  
	
  	
  	
  	
  channel.bind('new-­‐message',	
  function(data)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $('#chat-­‐box').append(data.message);	
  
	
  	
  	
  	
  });	
  
})	
  
</script>
#	
  app/controllers/messages_controller.rb	
  
#	
  ...	
  
def	
  create	
  
	
  	
  @message	
  =	
  Message.new(params[:message])	
  
	
  	
  if	
  @messsage.save	
  
	
  	
  	
  	
  NewMessageWorker.perform_async(@message.id)	
  
	
  	
  	
  	
  #	
  ...	
  
end	
  
#	
  ...
#	
  config/initializer/pusher.rb	
  
Pusher.app_id	
  =	
  ENV['PUSHER_APP_ID']	
  
Pusher.key	
  	
  	
  	
  =	
  ENV['PUSHER_APP_KEY']	
  
Pusher.secret	
  =	
  ENV['PUSHER_APP_SECRET']	
  
#	
  app/workers/new_message_worker.rb	
  
require	
  'pusher'	
  
class	
  NewMessageWorker	
  
	
  	
  include	
  Sidekiq::Worker	
  
	
  	
  	
  
	
  	
  def	
  perform(message_id)	
  
	
  	
  	
  	
  @message	
  =	
  Message.find(message_id)	
  
	
  	
  	
  	
  Pusher.trigger('my-­‐app-­‐chat',	
  'new-­‐message',	
  {:message	
  =>	
  @message})	
  
	
  	
  end	
  
end
TUNING RUBY
http://www.infoq.com/news/2014/12/ruby-2.2.0-released
http://www.infoq.com/news/2014/12/ruby-2.2.0-released
• Mark and Sweep GC (1.8+)
http://www.infoq.com/news/2014/12/ruby-2.2.0-released
• Mark and Sweep GC (1.8+)
• Bitmap Marking GC (1.9.3+)
http://www.infoq.com/news/2014/12/ruby-2.2.0-released
• Mark and Sweep GC (1.8+)
• Bitmap Marking GC (1.9.3+)
• Lazy Sweep GC (2.0.0+)
http://www.infoq.com/news/2014/12/ruby-2.2.0-released
• Mark and Sweep GC (1.8+)
• Bitmap Marking GC (1.9.3+)
• Lazy Sweep GC (2.0.0+)
• Restricted Generational GC (RGenGC 2.1.0+)
http://www.infoq.com/news/2014/12/ruby-2.2.0-released
• Mark and Sweep GC (1.8+)
• Bitmap Marking GC (1.9.3+)
• Lazy Sweep GC (2.0.0+)
• Restricted Generational GC (RGenGC 2.1.0+)
• Restricted Incremental GC (RIncGC 2.2.0+)
http://www.infoq.com/news/2014/12/ruby-2.2.0-released
TRADE-OFF:
+ GC OU + RAM
#	
  Gemfile	
  
source	
  'https://rubygems.org'	
  
ruby	
  "2.2.1"	
  
#	
  performance	
  tuning	
  
gem	
  'escape_utils'	
  
gem	
  'fast_blank'	
  
gem	
  'oj'	
  
gem	
  'oj_mimic_json'
http://marianposaceanu.com/articles/improve-rails-performance-by-adding-a-few-gems
#	
  Gemfile	
  
source	
  'https://rubygems.org'	
  
if	
  ENV['RAILS_ENV']	
  ==	
  'production'	
  
	
  	
  ruby	
  '1.9.3',	
  :engine	
  =>	
  'jruby',	
  :engine_version	
  =>	
  '1.7.18'	
  
else	
  
	
  	
  ruby	
  '2.2.1'	
  
end	
  
gem	
  'rails',	
  '4.2.0'	
  
gem	
  'rails-­‐api'	
  
gem	
  'srt'	
  
gem	
  'pg',	
  platforms:	
  'mri'	
  
gem	
  'activerecord-­‐jdbcpostgresql-­‐adapter',	
  platforms:	
  'jruby'	
  
gem	
  'sidekiq'	
  
gem	
  'dalli'	
  
gem	
  'puma'	
  
gem	
  'rack-­‐cache'	
  
gem	
  'rack-­‐cors',	
  require:	
  'rack/cors'	
  
gem	
  'rails_12factor'	
  
gem	
  'newrelic_rpm'
#	
  Gemfile	
  
source	
  'https://rubygems.org'	
  
if	
  ENV['RAILS_ENV']	
  ==	
  'production'	
  
	
  	
  ruby	
  '1.9.3',	
  :engine	
  =>	
  'jruby',	
  :engine_version	
  =>	
  '1.7.18'	
  
else	
  
	
  	
  ruby	
  '2.2.1'	
  
end	
  
gem	
  'rails',	
  '4.2.0'	
  
gem	
  'rails-­‐api'	
  
gem	
  'srt'	
  
gem	
  'pg',	
  platforms:	
  'mri'	
  
gem	
  'activerecord-­‐jdbcpostgresql-­‐adapter',	
  platforms:	
  'jruby'	
  
gem	
  'sidekiq'	
  
gem	
  'dalli'	
  
gem	
  'puma'	
  
gem	
  'rack-­‐cache'	
  
gem	
  'rack-­‐cors',	
  require:	
  'rack/cors'	
  
gem	
  'rails_12factor'	
  
gem	
  'newrelic_rpm'
#	
  Gemfile	
  
source	
  'https://rubygems.org'	
  
if	
  ENV['RAILS_ENV']	
  ==	
  'production'	
  
	
  	
  ruby	
  '1.9.3',	
  :engine	
  =>	
  'jruby',	
  :engine_version	
  =>	
  '1.7.18'	
  
else	
  
	
  	
  ruby	
  '2.2.1'	
  
end	
  
gem	
  'rails',	
  '4.2.0'	
  
gem	
  'rails-­‐api'	
  
gem	
  'srt'	
  
gem	
  'pg',	
  platforms:	
  'mri'	
  
gem	
  'activerecord-­‐jdbcpostgresql-­‐adapter',	
  platforms:	
  'jruby'	
  
gem	
  'sidekiq'	
  
gem	
  'dalli'	
  
gem	
  'puma'	
  
gem	
  'rack-­‐cache'	
  
gem	
  'rack-­‐cors',	
  require:	
  'rack/cors'	
  
gem	
  'rails_12factor'	
  
gem	
  'newrelic_rpm'
#	
  Gemfile	
  
source	
  'https://rubygems.org'	
  
if	
  ENV['RAILS_ENV']	
  ==	
  'production'	
  
	
  	
  ruby	
  '1.9.3',	
  :engine	
  =>	
  'jruby',	
  :engine_version	
  =>	
  '1.7.18'	
  
else	
  
	
  	
  ruby	
  '2.2.1'	
  
end	
  
gem	
  'rails',	
  '4.2.0'	
  
gem	
  'rails-­‐api'	
  
gem	
  'srt'	
  
gem	
  'pg',	
  platforms:	
  'mri'	
  
gem	
  'activerecord-­‐jdbcpostgresql-­‐adapter',	
  platforms:	
  'jruby'	
  
gem	
  'sidekiq'	
  
gem	
  'dalli'	
  
gem	
  'puma'	
  
gem	
  'rack-­‐cache'	
  
gem	
  'rack-­‐cors',	
  require:	
  'rack/cors'	
  
gem	
  'rails_12factor'	
  
gem	
  'newrelic_rpm'
9 DICAS
Monitoring New Relic
Monitoring New Relic
Caching Memcache, ETAG
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Database PostgreSQL
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Database PostgreSQL
Search Elastic
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Database PostgreSQL
Search Elastic
Async Jobs Sidekiq, Redis
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Database PostgreSQL
Search Elastic
Async Jobs Sidekiq, Redis
Async Messages pusher.com
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Database PostgreSQL
Search Elastic
Async Jobs Sidekiq, Redis
Async Messages pusher.com
Auto scale HireFire,AdeptScale
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Database PostgreSQL
Search Elastic
Async Jobs Sidekiq, Redis
Async Messages pusher.com
Auto scale HireFire,AdeptScale
Rubies Ruby 2.2.1, JRuby
Monitoring New Relic
Caching Memcache, ETAG
Assets CloudFlare, Cloudinary
Database PostgreSQL
Search Elastic
Async Jobs Sidekiq, Redis
Async Messages pusher.com
Auto scale HireFire,AdeptScale
Rubies Ruby 2.2.1, JRuby
Deployment Heroku
OBRIGADO
slideshare.net/akitaonrails

Contenu connexe

Tendances

Chef 0.10 Overview
Chef 0.10 OverviewChef 0.10 Overview
Chef 0.10 OverviewMatt Ray
 
Programming simple games with a raspberry pi and
Programming simple games with a raspberry pi andProgramming simple games with a raspberry pi and
Programming simple games with a raspberry pi andKellyn Pot'Vin-Gorman
 
An introduction to Rex - FLOSS UK DevOps York 2015
An introduction to Rex - FLOSS UK DevOps York 2015An introduction to Rex - FLOSS UK DevOps York 2015
An introduction to Rex - FLOSS UK DevOps York 2015Andy Beverley
 
Ansible leveraging 2.0
Ansible leveraging 2.0Ansible leveraging 2.0
Ansible leveraging 2.0bcoca
 
RMOUG QEW Family Coding Event- Raspberry PI
RMOUG QEW Family Coding Event-  Raspberry PIRMOUG QEW Family Coding Event-  Raspberry PI
RMOUG QEW Family Coding Event- Raspberry PIKellyn Pot'Vin-Gorman
 
Investigating Python Wats
Investigating Python WatsInvestigating Python Wats
Investigating Python WatsAmy Hanlon
 
Hacking ansible
Hacking ansibleHacking ansible
Hacking ansiblebcoca
 
Stupid Video Tricks (CocoaConf DC, March 2014)
Stupid Video Tricks (CocoaConf DC, March 2014)Stupid Video Tricks (CocoaConf DC, March 2014)
Stupid Video Tricks (CocoaConf DC, March 2014)Chris Adamson
 
Getting Started with PoolParty and EC2
Getting Started with PoolParty and EC2Getting Started with PoolParty and EC2
Getting Started with PoolParty and EC2Nate Murray
 
Stupid Video Tricks, CocoaConf Seattle 2014
Stupid Video Tricks, CocoaConf Seattle 2014Stupid Video Tricks, CocoaConf Seattle 2014
Stupid Video Tricks, CocoaConf Seattle 2014Chris Adamson
 
AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -
AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -
AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -Yasuyuki Sugai
 
Puppet at janrain
Puppet at janrainPuppet at janrain
Puppet at janrainPuppet
 
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)Video Killed the Rolex Star (CocoaConf Columbus, July 2015)
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)Chris Adamson
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with SlimRaven Tools
 
Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)
Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)
Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)akira6592
 
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardHow I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardSV Ruby on Rails Meetup
 

Tendances (20)

Chef 0.10 Overview
Chef 0.10 OverviewChef 0.10 Overview
Chef 0.10 Overview
 
Programming simple games with a raspberry pi and
Programming simple games with a raspberry pi andProgramming simple games with a raspberry pi and
Programming simple games with a raspberry pi and
 
Ansible - Crash course
Ansible - Crash courseAnsible - Crash course
Ansible - Crash course
 
An introduction to Rex - FLOSS UK DevOps York 2015
An introduction to Rex - FLOSS UK DevOps York 2015An introduction to Rex - FLOSS UK DevOps York 2015
An introduction to Rex - FLOSS UK DevOps York 2015
 
Refactoring Infrastructure Code
Refactoring Infrastructure CodeRefactoring Infrastructure Code
Refactoring Infrastructure Code
 
Ansible leveraging 2.0
Ansible leveraging 2.0Ansible leveraging 2.0
Ansible leveraging 2.0
 
RMOUG QEW Family Coding Event- Raspberry PI
RMOUG QEW Family Coding Event-  Raspberry PIRMOUG QEW Family Coding Event-  Raspberry PI
RMOUG QEW Family Coding Event- Raspberry PI
 
Investigating Python Wats
Investigating Python WatsInvestigating Python Wats
Investigating Python Wats
 
Hacking ansible
Hacking ansibleHacking ansible
Hacking ansible
 
ES6: Features + Rails
ES6: Features + RailsES6: Features + Rails
ES6: Features + Rails
 
Stupid Video Tricks (CocoaConf DC, March 2014)
Stupid Video Tricks (CocoaConf DC, March 2014)Stupid Video Tricks (CocoaConf DC, March 2014)
Stupid Video Tricks (CocoaConf DC, March 2014)
 
Getting Started with PoolParty and EC2
Getting Started with PoolParty and EC2Getting Started with PoolParty and EC2
Getting Started with PoolParty and EC2
 
Stupid Video Tricks, CocoaConf Seattle 2014
Stupid Video Tricks, CocoaConf Seattle 2014Stupid Video Tricks, CocoaConf Seattle 2014
Stupid Video Tricks, CocoaConf Seattle 2014
 
AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -
AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -
AnsibleではじめるNW設定の自動化について - Cisco(VIRL)編 -
 
Puppet at janrain
Puppet at janrainPuppet at janrain
Puppet at janrain
 
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)Video Killed the Rolex Star (CocoaConf Columbus, July 2015)
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)
 
Keeping It Small with Slim
Keeping It Small with SlimKeeping It Small with Slim
Keeping It Small with Slim
 
Symfony2 meets propel 1.5
Symfony2 meets propel 1.5Symfony2 meets propel 1.5
Symfony2 meets propel 1.5
 
Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)
Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)
Ansibleではじめるサーバー・ネットワークの自動化(2019/02版)
 
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine YardHow I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
How I Learned to Stop Worrying and Love the Cloud - Wesley Beary, Engine Yard
 

Similaire à QConSP 2015 - Dicas de Performance para Aplicações Web

09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)Igor Bronovskyy
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTPMustafa TURAN
 
Heroku pop-behind-the-sense
Heroku pop-behind-the-senseHeroku pop-behind-the-sense
Heroku pop-behind-the-senseBen Lin
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsAlessandro Molina
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdevFrank Rousseau
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesLindsay Holmwood
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'sAntônio Roberto Silva
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexyananelson
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSAntonio Peric-Mazar
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...Fabio Franzini
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gearsdion
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30fiyuer
 
WebcampZG - Rails 4
WebcampZG - Rails 4WebcampZG - Rails 4
WebcampZG - Rails 4shnikola
 

Similaire à QConSP 2015 - Dicas de Performance para Aplicações Web (20)

Play vs Rails
Play vs RailsPlay vs Rails
Play vs Rails
 
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
09 - express nodes on the right angle - vitaliy basyuk - it event 2013 (5)
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Re-Design with Elixir/OTP
Re-Design with Elixir/OTPRe-Design with Elixir/OTP
Re-Design with Elixir/OTP
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
Heroku pop-behind-the-sense
Heroku pop-behind-the-senseHeroku pop-behind-the-sense
Heroku pop-behind-the-sense
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable Applications
 
20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev20130528 solution linux_frousseau_nopain_webdev
20130528 solution linux_frousseau_nopain_webdev
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websites
 
using Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API'susing Mithril.js + postgREST to build and consume API's
using Mithril.js + postgREST to build and consume API's
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Refresh Austin - Intro to Dexy
Refresh Austin - Intro to DexyRefresh Austin - Intro to Dexy
Refresh Austin - Intro to Dexy
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Future of Web Apps: Google Gears
Future of Web Apps: Google GearsFuture of Web Apps: Google Gears
Future of Web Apps: Google Gears
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
 
WebcampZG - Rails 4
WebcampZG - Rails 4WebcampZG - Rails 4
WebcampZG - Rails 4
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 

Plus de Fabio Akita

Devconf 2019 - São Carlos
Devconf 2019 - São CarlosDevconf 2019 - São Carlos
Devconf 2019 - São CarlosFabio Akita
 
Meetup Nerdzão - English Talk about Languages
Meetup Nerdzão  - English Talk about LanguagesMeetup Nerdzão  - English Talk about Languages
Meetup Nerdzão - English Talk about LanguagesFabio Akita
 
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018Fabio Akita
 
Desmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SPDesmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SPFabio Akita
 
Desmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter GoianiaDesmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter GoianiaFabio Akita
 
Blockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7MastersBlockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7MastersFabio Akita
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG CampinasFabio Akita
 
Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017Fabio Akita
 
30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to Ruby30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to RubyFabio Akita
 
Uma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TIUma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TIFabio Akita
 
THE CONF - Opening Keynote
THE CONF - Opening KeynoteTHE CONF - Opening Keynote
THE CONF - Opening KeynoteFabio Akita
 
A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017Fabio Akita
 
Desmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - APDesmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - APFabio Akita
 
A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017Fabio Akita
 
A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017Fabio Akita
 
A Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech DayA Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech DayFabio Akita
 
A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016Fabio Akita
 
Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016Fabio Akita
 
Conexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização PrematuraConexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização PrematuraFabio Akita
 
The Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All EvilThe Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All EvilFabio Akita
 

Plus de Fabio Akita (20)

Devconf 2019 - São Carlos
Devconf 2019 - São CarlosDevconf 2019 - São Carlos
Devconf 2019 - São Carlos
 
Meetup Nerdzão - English Talk about Languages
Meetup Nerdzão  - English Talk about LanguagesMeetup Nerdzão  - English Talk about Languages
Meetup Nerdzão - English Talk about Languages
 
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
Desmistificando Blockchains p/ Developers - Criciuma Dev Conf 2018
 
Desmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SPDesmistificando Blockchains - 20o Encontro Locaweb SP
Desmistificando Blockchains - 20o Encontro Locaweb SP
 
Desmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter GoianiaDesmistificando Blockchains - Insiter Goiania
Desmistificando Blockchains - Insiter Goiania
 
Blockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7MastersBlockchain em 7 minutos - 7Masters
Blockchain em 7 minutos - 7Masters
 
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
Elixir  -Tolerância a Falhas para Adultos - GDG CampinasElixir  -Tolerância a Falhas para Adultos - GDG Campinas
Elixir -Tolerância a Falhas para Adultos - GDG Campinas
 
Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017Desmistificando Mitos de Tech Startups - Intercon 2017
Desmistificando Mitos de Tech Startups - Intercon 2017
 
30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to Ruby30 Days to Elixir and Crystal and Back to Ruby
30 Days to Elixir and Crystal and Back to Ruby
 
Uma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TIUma Discussão sobre a Carreira de TI
Uma Discussão sobre a Carreira de TI
 
THE CONF - Opening Keynote
THE CONF - Opening KeynoteTHE CONF - Opening Keynote
THE CONF - Opening Keynote
 
A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017A Journey through New Languages - Rancho Dev 2017
A Journey through New Languages - Rancho Dev 2017
 
Desmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - APDesmistificando Mitos de Startups - Sebrae - AP
Desmistificando Mitos de Startups - Sebrae - AP
 
A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017A Journey through New Languages - Guru Sorocaba 2017
A Journey through New Languages - Guru Sorocaba 2017
 
A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017A Journey through New Languages - Insiter 2017
A Journey through New Languages - Insiter 2017
 
A Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech DayA Journey through New Languages - Locaweb Tech Day
A Journey through New Languages - Locaweb Tech Day
 
A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016A Journey through new Languages - Intercon 2016
A Journey through new Languages - Intercon 2016
 
Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016Premature Optimization 2.0 - Intercon 2016
Premature Optimization 2.0 - Intercon 2016
 
Conexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização PrematuraConexão Kinghost - Otimização Prematura
Conexão Kinghost - Otimização Prematura
 
The Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All EvilThe Open Commerce Conference - Premature Optimisation: The Root of All Evil
The Open Commerce Conference - Premature Optimisation: The Root of All Evil
 

Dernier

Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 

Dernier (20)

Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 

QConSP 2015 - Dicas de Performance para Aplicações Web

  • 1. DICAS DE PERFORMANCE WEB Fabio Akita @AkitaOnRails
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 12.
  • 13.
  • 14.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 27.
  • 28.
  • 29.
  • 32.
  • 33.
  • 34.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40. def  sitemap      sleep  3      @posts  =  Post.select([  :id,  :slug,  :updated_at,  :published_at  ]).published      respond_to  do  |format|          format.xml  {  render  layout:  false  }      end   end Processing  by  ArchivesController#sitemap  as  XML      Rendered  archives/sitemap.xml.builder  (785.5ms)   Completed  200  OK  in  3879.4ms  (Views:  770.4ms  |  ActiveRecord:  18.7ms  |  Solr:  0.0ms)
  • 41. def  sitemap      @posts  =  cache('sitemap',  :expires_in  =>  12.hours)  {          sleep  3          Post.select([  :id,  :slug,  :updated_at,  :published_at  ]).published      }      respond_to  do  |format|          format.xml  {  render  layout:  false  }      end   end Processing  by  ArchivesController#sitemap  as  XML      Rendered  archives/sitemap.xml.builder  (763.3ms)   Completed  200  OK  in  842.4ms  (Views:  754.2ms  |  ActiveRecord:  13.3ms  |  Solr:  0.0ms)
  • 42. def  sitemap      @posts  =  cache('sitemap',  :expires_in  =>  12.hours)  {          Post.select([  :id,  :slug,  :updated_at,  :published_at  ]).published      }      if  stale?(last_modified:  @posts.first.updated_at.utc,          etag:  "posts/#{@posts.count}-­‐#{@posts.first.updated_at.utc}")          respond_to  do  |format|              format.xml  {  render  layout:  false  }          end      end   end Processing  by  ArchivesController#sitemap  as  XML   Completed  304  Not  Modified  in  6.2ms  (ActiveRecord:  1.7ms)
  • 43.
  • 44. 2s!
  • 45.
  • 47.
  • 48.
  • 49.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55. } }
  • 67.
  • 68.
  • 69. #  Gemfile   gem  'cloudinary'   gem  'attachinary'
  • 70. #  Gemfile   gem  'cloudinary'   gem  'attachinary' #  config/cloudinary.yml   production:      cloud_name:  "sample"      api_key:  "874837483274837"      api_secret:  "a676b67565c6767a6767d6767f676fe1"
  • 71. #  Gemfile   gem  'cloudinary'   gem  'attachinary' #  config/cloudinary.yml   production:      cloud_name:  "sample"      api_key:  "874837483274837"      api_secret:  "a676b67565c6767a6767d6767f676fe1"#  app/models/user.rb   class  User  <  ActiveRecord::Base      attr_accessible  :name            has_attachment    :avatar      has_attachments  :photos,  maximum:  3   end
  • 72. #  Gemfile   gem  'cloudinary'   gem  'attachinary' #  config/cloudinary.yml   production:      cloud_name:  "sample"      api_key:  "874837483274837"      api_secret:  "a676b67565c6767a6767d6767f676fe1"#  app/models/user.rb   class  User  <  ActiveRecord::Base      attr_accessible  :name            has_attachment    :avatar      has_attachments  :photos,  maximum:  3   end #  app/views/users/_form.html.slim   =  form_for(@user)  do  |user_form|          =  user_form.text_field(:name)          =  attachinary_file_field_tag  ‘user[avatar]',              @user,  :avatar          =  attachinary_file_field_tag  ‘user[photos]’,              @user,  :photos          =  user_form.submit("Save")
  • 73. #  Gemfile   gem  'cloudinary'   gem  'attachinary' #  config/cloudinary.yml   production:      cloud_name:  "sample"      api_key:  "874837483274837"      api_secret:  "a676b67565c6767a6767d6767f676fe1"#  app/models/user.rb   class  User  <  ActiveRecord::Base      attr_accessible  :name            has_attachment    :avatar      has_attachments  :photos,  maximum:  3   end #  app/views/users/_form.html.slim   =  form_for(@user)  do  |user_form|          =  user_form.text_field(:name)          =  attachinary_file_field_tag  ‘user[avatar]',              @user,  :avatar          =  attachinary_file_field_tag  ‘user[photos]’,              @user,  :photos          =  user_form.submit("Save") #  app/controllers/users_controller.rb   ...      def  create          @user  =  User.new(params[:user])          @user.save!      end
  • 74. #  app/views/users/show.html.slim   -­‐  if  user.avatar.present?      =  cl_image_tag(user.avatar.path,  width:  80,  height:  100,  crop:  :thumb,  gravity:  :face)      -­‐  user.photos.each  do  |photo|          =  cl_image_tag(photo.path,  size:  '70x50',  crop:  :fill,  radius:  20) #  Gemfile   gem  'cloudinary'   gem  'attachinary' #  config/cloudinary.yml   production:      cloud_name:  "sample"      api_key:  "874837483274837"      api_secret:  "a676b67565c6767a6767d6767f676fe1"#  app/models/user.rb   class  User  <  ActiveRecord::Base      attr_accessible  :name            has_attachment    :avatar      has_attachments  :photos,  maximum:  3   end #  app/views/users/_form.html.slim   =  form_for(@user)  do  |user_form|          =  user_form.text_field(:name)          =  attachinary_file_field_tag  ‘user[avatar]',              @user,  :avatar          =  attachinary_file_field_tag  ‘user[photos]’,              @user,  :photos          =  user_form.submit("Save") #  app/controllers/users_controller.rb   ...      def  create          @user  =  User.new(params[:user])          @user.save!      end
  • 75. CDN
  • 86. #  config/environments/production.rb   config.action_controller.asset_host  =  "d3vam04na8c92l.cloudfront.net" <%=  stylesheet_link_tag        "application",  :media  =>  "all"  %>   <%=  javascript_include_tag  "application"  %>   <%=  image_tag("rails.png")  %> <link  href="http://d3vam04na8c92l.cloudfront.net/stylesheets/application-­‐6502e5a88f02b90aeb32c2dd21ea37ab.css"  rel="stylesheet"  />
  • 88.
  • 89.
  • 90.
  • 91. #  Gemfile   gem  "lol_dba",  group:  :development   #  no  Terminal   bundle  install   bundle  exec  rake  db:find_indexes
  • 92.
  • 93. #  app/controllers/posts_controller.rb   def  index      @posts  =  Post.all      respond_to  do  |format|          format.html  #  index.html.erb          format.xml    {  render  :xml  =>  @posts  }      end   end
  • 94. #  app/controllers/posts_controller.rb   def  index      @posts  =  Post.all      respond_to  do  |format|          format.html  #  index.html.erb          format.xml    {  render  :xml  =>  @posts  }      end   end <%  @posts.each  do  |post|  %>      <tr>          <td><%=  post.name  %></td>          <td><%=  post.comments.size  %></td>          <td><%=  link_to  'Show',  post  %></td>          <td><%=  link_to  'Edit',  edit_post_path(post)  %></td>          <td><%=  link_to  'Destroy',  post,  confirm:  'Are  you  sure?',  method:  :delete  %></td>      </tr>   <%  end  %>
  • 95. #  app/controllers/posts_controller.rb   def  index      @posts  =  Post.all      respond_to  do  |format|          format.html  #  index.html.erb          format.xml    {  render  :xml  =>  @posts  }      end   end <%  @posts.each  do  |post|  %>      <tr>          <td><%=  post.name  %></td>          <td><%=  post.comments.size  %></td>          <td><%=  link_to  'Show',  post  %></td>          <td><%=  link_to  'Edit',  edit_post_path(post)  %></td>          <td><%=  link_to  'Destroy',  post,  confirm:  'Are  you  sure?',  method:  :delete  %></td>      </tr>   <%  end  %> Started  GET  "/posts/"  for  192.168.47.2  at  2015-­‐03-­‐23  18:31:11  +0000   Cannot  render  console  from  192.168.47.2!  Allowed  networks:  127.0.0.1,  ::1,  127.0.0.0/127.255.255.255      ActiveRecord::SchemaMigration  Load  (0.1ms)    SELECT  "schema_migrations".*  FROM  "schema_migrations"   Processing  by  PostsController#index  as  HTML      Post  Load  (0.2ms)    SELECT  "posts".*  FROM  "posts"      Comment  Load  (0.2ms)    SELECT  "comments".*  FROM  "comments"  WHERE  "comments"."post_id"  =  ?    [["post_id",  1]]      Comment  Load  (0.1ms)    SELECT  "comments".*  FROM  "comments"  WHERE  "comments"."post_id"  =  ?    [["post_id",  2]]      Rendered  posts/index.html.erb  within  layouts/application  (25.3ms)   Completed  200  OK  in  679ms  (Views:  666.4ms  |  ActiveRecord:  1.0ms)
  • 96.
  • 97. #  app/controllers/posts_controller.rb   def  index      @posts  =  Post.all      respond_to  do  |format|          format.html  #  index.html.erb          format.xml    {  render  :xml  =>  @posts  }      end   end <%  @posts.each  do  |post|  %>      <tr>          <td><%=  post.name  %></td>          <td><%=  post.comments.size  %></td>          <td><%=  link_to  'Show',  post  %></td>          <td><%=  link_to  'Edit',  edit_post_path(post)  %></td>          <td><%=  link_to  'Destroy',  post,  confirm:  'Are  you  sure?',  method:  :delete  %></td>      </tr>   <%  end  %> Started  GET  "/posts/"  for  192.168.47.2  at  2015-­‐03-­‐23  18:31:11  +0000   Cannot  render  console  from  192.168.47.2!  Allowed  networks:  127.0.0.1,  ::1,  127.0.0.0/127.255.255.255      ActiveRecord::SchemaMigration  Load  (0.1ms)    SELECT  "schema_migrations".*  FROM  "schema_migrations"   Processing  by  PostsController#index  as  HTML      Post  Load  (0.2ms)    SELECT  "posts".*  FROM  "posts"      Comment  Load  (0.2ms)    SELECT  "comments".*  FROM  "comments"  WHERE  "comments"."post_id"  =  ?    [["post_id",  1]]      Comment  Load  (0.1ms)    SELECT  "comments".*  FROM  "comments"  WHERE  "comments"."post_id"  =  ?    [["post_id",  2]]      Rendered  posts/index.html.erb  within  layouts/application  (25.3ms)   Completed  200  OK  in  679ms  (Views:  666.4ms  |  ActiveRecord:  1.0ms)
  • 98. Started  GET  "/posts/"  for  192.168.47.2  at  2015-­‐03-­‐23  18:37:31  +0000   Cannot  render  console  from  192.168.47.2!  Allowed  networks:  127.0.0.1,  ::1,  127.0.0.0/127.255.255.255      ActiveRecord::SchemaMigration  Load  (0.1ms)    SELECT  "schema_migrations".*  FROM  "schema_migrations"   Processing  by  PostsController#index  as  HTML      Post  Load  (0.2ms)    SELECT  "posts".*  FROM  "posts"      Comment  Load  (0.2ms)    SELECT  "comments".*  FROM  "comments"  WHERE  "comments"."post_id"  IN  (1,  2)      Rendered  posts/index.html.erb  within  layouts/application  (25.8ms)   Completed  200  OK  in  109ms  (Views:  96.4ms  |  ActiveRecord:  0.9ms) #  app/controllers/posts_controller.rb   def  index      @posts  =  Post.includes(:comments).all      respond_to  do  |format|          format.html  #  index.html.erb          format.xml    {  render  :xml  =>  @posts  }      end   end <%  @posts.each  do  |post|  %>      <tr>          <td><%=  post.name  %></td>          <td><%=  post.comments.size  %></td>          <td><%=  link_to  'Show',  post  %></td>          <td><%=  link_to  'Edit',  edit_post_path(post)  %></td>          <td><%=  link_to  'Destroy',  post,  confirm:  'Are  you  sure?',  method:  :delete  %></td>      </tr>   <%  end  %>
  • 100.
  • 101.
  • 102.
  • 103.
  • 105.
  • 114. BackendBrowser 1s 200 ms Redis Tarefa Demorada (Worker) 3.8 segundos
  • 115.
  • 116. class  VerySlowJob  <  ActiveJob::Base      queue_as  :default          def  perform(*args)          #  Tarefa  Demorada      end   end
  • 117. class  VerySlowJob  <  ActiveJob::Base      queue_as  :default          def  perform(*args)          #  Tarefa  Demorada      end   end VerySlowJob.perform_later  record
  • 118. class  VerySlowJob  <  ActiveJob::Base      queue_as  :default          def  perform(*args)          #  Tarefa  Demorada      end   end VerySlowJob.perform_later  record VerySlowJob.set(wait_until:   Date.tomorrow.noon).perform_later(record)
  • 119. class  VerySlowJob  <  ActiveJob::Base      queue_as  :default          def  perform(*args)          #  Tarefa  Demorada      end   end VerySlowJob.set(wait:  1.week).perform_later(record) VerySlowJob.perform_later  record VerySlowJob.set(wait_until:   Date.tomorrow.noon).perform_later(record)
  • 120. #  app/workers/report_job.rb   class  ReportJob  <  ActiveJob::Base      queue_as  :default          def  perform(email,  from_date  =  nil,  to_date  =  nil)          now  =  Time.zone.now          from_date  ||=  now  -­‐  1.year          to_date      ||=  now          file_path  =  ModelGigante.generate_excel(from_date,  to_date)          NotifyReportMailer.send(email,  file_path)      end   end
  • 121. #  app/controllers/reports_controller.rb   #  ...   def  create      ReportJob.perform_later(params[:email],          params[:from_date],  params[:to_date])      flash[:notice]  =  "Report  is  being  generated.          It  will  be  sent  to  your  email."      redirect_to  reports_path   end   #  ... #  app/workers/report_job.rb   class  ReportJob  <  ActiveJob::Base      queue_as  :default          def  perform(email,  from_date  =  nil,  to_date  =  nil)          now  =  Time.zone.now          from_date  ||=  now  -­‐  1.year          to_date      ||=  now          file_path  =  ModelGigante.generate_excel(from_date,  to_date)          NotifyReportMailer.send(email,  file_path)      end   end
  • 122.
  • 124.
  • 125.
  • 126.
  • 128. <!-­‐-­‐  chat.html  -­‐-­‐>   <script  src="//js.pusher.com/2.2/pusher.min.js"></script>   <script>   $(function()  {          var  pusher  =  new  Pusher('YOUR_APP_KEY');          var  channel  =  pusher.subscribe('my-­‐app-­‐chat');          channel.bind('new-­‐message',  function(data)  {                  $('#chat-­‐box').append(data.message);          });   })   </script>
  • 129. <!-­‐-­‐  chat.html  -­‐-­‐>   <script  src="//js.pusher.com/2.2/pusher.min.js"></script>   <script>   $(function()  {          var  pusher  =  new  Pusher('YOUR_APP_KEY');          var  channel  =  pusher.subscribe('my-­‐app-­‐chat');          channel.bind('new-­‐message',  function(data)  {                  $('#chat-­‐box').append(data.message);          });   })   </script> #  config/initializer/pusher.rb   Pusher.app_id  =  ENV['PUSHER_APP_ID']   Pusher.key        =  ENV['PUSHER_APP_KEY']   Pusher.secret  =  ENV['PUSHER_APP_SECRET']  
  • 130. <!-­‐-­‐  chat.html  -­‐-­‐>   <script  src="//js.pusher.com/2.2/pusher.min.js"></script>   <script>   $(function()  {          var  pusher  =  new  Pusher('YOUR_APP_KEY');          var  channel  =  pusher.subscribe('my-­‐app-­‐chat');          channel.bind('new-­‐message',  function(data)  {                  $('#chat-­‐box').append(data.message);          });   })   </script> #  config/initializer/pusher.rb   Pusher.app_id  =  ENV['PUSHER_APP_ID']   Pusher.key        =  ENV['PUSHER_APP_KEY']   Pusher.secret  =  ENV['PUSHER_APP_SECRET']   #  app/workers/new_message_worker.rb   require  'pusher'   class  NewMessageWorker      include  Sidekiq::Worker            def  perform(message_id)          @message  =  Message.find(message_id)          Pusher.trigger('my-­‐app-­‐chat',  'new-­‐message',  {:message  =>  @message})      end   end
  • 131. <!-­‐-­‐  chat.html  -­‐-­‐>   <script  src="//js.pusher.com/2.2/pusher.min.js"></script>   <script>   $(function()  {          var  pusher  =  new  Pusher('YOUR_APP_KEY');          var  channel  =  pusher.subscribe('my-­‐app-­‐chat');          channel.bind('new-­‐message',  function(data)  {                  $('#chat-­‐box').append(data.message);          });   })   </script> #  app/controllers/messages_controller.rb   #  ...   def  create      @message  =  Message.new(params[:message])      if  @messsage.save          NewMessageWorker.perform_async(@message.id)          #  ...   end   #  ... #  config/initializer/pusher.rb   Pusher.app_id  =  ENV['PUSHER_APP_ID']   Pusher.key        =  ENV['PUSHER_APP_KEY']   Pusher.secret  =  ENV['PUSHER_APP_SECRET']   #  app/workers/new_message_worker.rb   require  'pusher'   class  NewMessageWorker      include  Sidekiq::Worker            def  perform(message_id)          @message  =  Message.find(message_id)          Pusher.trigger('my-­‐app-­‐chat',  'new-­‐message',  {:message  =>  @message})      end   end
  • 133.
  • 136. • Mark and Sweep GC (1.8+) http://www.infoq.com/news/2014/12/ruby-2.2.0-released
  • 137. • Mark and Sweep GC (1.8+) • Bitmap Marking GC (1.9.3+) http://www.infoq.com/news/2014/12/ruby-2.2.0-released
  • 138. • Mark and Sweep GC (1.8+) • Bitmap Marking GC (1.9.3+) • Lazy Sweep GC (2.0.0+) http://www.infoq.com/news/2014/12/ruby-2.2.0-released
  • 139. • Mark and Sweep GC (1.8+) • Bitmap Marking GC (1.9.3+) • Lazy Sweep GC (2.0.0+) • Restricted Generational GC (RGenGC 2.1.0+) http://www.infoq.com/news/2014/12/ruby-2.2.0-released
  • 140. • Mark and Sweep GC (1.8+) • Bitmap Marking GC (1.9.3+) • Lazy Sweep GC (2.0.0+) • Restricted Generational GC (RGenGC 2.1.0+) • Restricted Incremental GC (RIncGC 2.2.0+) http://www.infoq.com/news/2014/12/ruby-2.2.0-released
  • 141.
  • 142.
  • 144.
  • 145. #  Gemfile   source  'https://rubygems.org'   ruby  "2.2.1"   #  performance  tuning   gem  'escape_utils'   gem  'fast_blank'   gem  'oj'   gem  'oj_mimic_json' http://marianposaceanu.com/articles/improve-rails-performance-by-adding-a-few-gems
  • 146.
  • 147. #  Gemfile   source  'https://rubygems.org'   if  ENV['RAILS_ENV']  ==  'production'      ruby  '1.9.3',  :engine  =>  'jruby',  :engine_version  =>  '1.7.18'   else      ruby  '2.2.1'   end   gem  'rails',  '4.2.0'   gem  'rails-­‐api'   gem  'srt'   gem  'pg',  platforms:  'mri'   gem  'activerecord-­‐jdbcpostgresql-­‐adapter',  platforms:  'jruby'   gem  'sidekiq'   gem  'dalli'   gem  'puma'   gem  'rack-­‐cache'   gem  'rack-­‐cors',  require:  'rack/cors'   gem  'rails_12factor'   gem  'newrelic_rpm'
  • 148. #  Gemfile   source  'https://rubygems.org'   if  ENV['RAILS_ENV']  ==  'production'      ruby  '1.9.3',  :engine  =>  'jruby',  :engine_version  =>  '1.7.18'   else      ruby  '2.2.1'   end   gem  'rails',  '4.2.0'   gem  'rails-­‐api'   gem  'srt'   gem  'pg',  platforms:  'mri'   gem  'activerecord-­‐jdbcpostgresql-­‐adapter',  platforms:  'jruby'   gem  'sidekiq'   gem  'dalli'   gem  'puma'   gem  'rack-­‐cache'   gem  'rack-­‐cors',  require:  'rack/cors'   gem  'rails_12factor'   gem  'newrelic_rpm'
  • 149. #  Gemfile   source  'https://rubygems.org'   if  ENV['RAILS_ENV']  ==  'production'      ruby  '1.9.3',  :engine  =>  'jruby',  :engine_version  =>  '1.7.18'   else      ruby  '2.2.1'   end   gem  'rails',  '4.2.0'   gem  'rails-­‐api'   gem  'srt'   gem  'pg',  platforms:  'mri'   gem  'activerecord-­‐jdbcpostgresql-­‐adapter',  platforms:  'jruby'   gem  'sidekiq'   gem  'dalli'   gem  'puma'   gem  'rack-­‐cache'   gem  'rack-­‐cors',  require:  'rack/cors'   gem  'rails_12factor'   gem  'newrelic_rpm'
  • 150. #  Gemfile   source  'https://rubygems.org'   if  ENV['RAILS_ENV']  ==  'production'      ruby  '1.9.3',  :engine  =>  'jruby',  :engine_version  =>  '1.7.18'   else      ruby  '2.2.1'   end   gem  'rails',  '4.2.0'   gem  'rails-­‐api'   gem  'srt'   gem  'pg',  platforms:  'mri'   gem  'activerecord-­‐jdbcpostgresql-­‐adapter',  platforms:  'jruby'   gem  'sidekiq'   gem  'dalli'   gem  'puma'   gem  'rack-­‐cache'   gem  'rack-­‐cors',  require:  'rack/cors'   gem  'rails_12factor'   gem  'newrelic_rpm'
  • 152.
  • 154. Monitoring New Relic Caching Memcache, ETAG
  • 155. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary
  • 156. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary Database PostgreSQL
  • 157. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary Database PostgreSQL Search Elastic
  • 158. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary Database PostgreSQL Search Elastic Async Jobs Sidekiq, Redis
  • 159. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary Database PostgreSQL Search Elastic Async Jobs Sidekiq, Redis Async Messages pusher.com
  • 160. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary Database PostgreSQL Search Elastic Async Jobs Sidekiq, Redis Async Messages pusher.com Auto scale HireFire,AdeptScale
  • 161. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary Database PostgreSQL Search Elastic Async Jobs Sidekiq, Redis Async Messages pusher.com Auto scale HireFire,AdeptScale Rubies Ruby 2.2.1, JRuby
  • 162. Monitoring New Relic Caching Memcache, ETAG Assets CloudFlare, Cloudinary Database PostgreSQL Search Elastic Async Jobs Sidekiq, Redis Async Messages pusher.com Auto scale HireFire,AdeptScale Rubies Ruby 2.2.1, JRuby Deployment Heroku
  • 163.