Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Dog Pile Effect - QCon Sao Paulo

Dog Pile Effect - QCon Sao Paulo

Plataformatec

March 08, 2012
Tweet

More Decks by Plataformatec

Other Decks in Technology

Transcript

  1. 1

  2. “There are only two hard problems in Computer Science: cache

    invalidation and naming things.” — Phil Karlton
  3. 2 1 request ativa geração de cache. As outras requests

    são servidas com o cache antigo. http://blog.plataformatec.com.br/2009/09/how-to-avoid-dog-pile-effect-rails-app/
  4. 2

  5. module ActiveSupport module Cache class SmartMemCacheStore < MemCacheStore alias_method :orig_read,

    :read alias_method :orig_write, :write def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil? lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end end end end
  6. module ActiveSupport module Cache class SmartMemCacheStore < MemCacheStore alias_method :orig_read,

    :read alias_method :orig_write, :write def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil? lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end end end end
  7. def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if

    !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end
  8. def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if

    !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end
  9. def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if

    !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end Agora são: 12:00 expires_at: 12:05
  10. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end
  11. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end
  12. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end Todas requests antes de 12:05 recebem cache hit do cache válido
  13. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end
  14. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end Ao 12:06 o cache vai estar stale
  15. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end request salva um lock no cache
  16. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end
  17. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end novas requests percebem que tem um lock criado
  18. def read(key, options = nil) lock_expires_in = options.delete(:lock_expires_in) if !options.nil?

    lock_expires_in ||= 30 response = orig_read(key, options) return nil if response.nil? data, expires_at = response if Time.now > expires_at && !orig_read("lock_#{key}").present? orig_write("lock_#{key}", true, :expires_in => lock_expires_in) return nil else data end end elas serão servidas com o cache antigo novas requests percebem que tem um lock criado
  19. def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if

    !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end
  20. def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if

    !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end cria o novo cache
  21. def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if

    !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end
  22. def write(key, value, options = nil) expires_delta = options.delete(:expires_delta) if

    !options.nil? expires_delta ||= 300 expires_at = Time.now + expires_delta package = [value, expires_at] orig_write(key, package, options) delete("lock_#{key}") end deleta o lock