Why I hate Caching. And the Things I'm Trying to do to Change it.

Why I hate Caching. And the Things I'm Trying to do to Change it.

D3247e8f4b25f6041ab71da426f1c86e?s=128

Ivayr Farah Netto

September 24, 2015
Tweet

Transcript

  1. WHY I HATE CACHING AND THE THINGS I'M TRYING TO

    DO TO CHANGE IT @nettofarah 1 / 65
  2. nettofarah github.com/nettofarah @nettofarah http://bit.ly/kashmir-netto 2 / 65

  3. Senior Product Engineer @ IFTTT 3 / 65

  4. IFTTT Connect the Apps you Love 4 / 65

  5. IFTTT Millions of Users Website (desktop & mobile) 8 Apps

    (IF & DO) Billions of Requests and Transactions every day 5 / 65
  6. Rails doesn't Scale Said someone in the Past. For whatever

    reason. 6 / 65
  7. Scaling Web (Rails) Apps You can do it! 7 /

    65
  8. Background Jobs 8 / 65

  9. With a lot of Processes or With Threads 9 /

    65
  10. Scaling Web (Rails) Apps with Rails.cache 10 / 65

  11. Easy and beautiful at first 11 / 65

  12. Incredibly tricky after some time 12 / 65

  13. Caching is like Cocaine 13 / 65

  14. What is Caching Anyway? 14 / 65

  15. The 2 Hardest Problems in Computer Science 15 / 65

  16. Cache Invalidation and Naming Things 16 / 65

  17. Ok, so you're still not convinced 17 / 65

  18. Oops, we forgot to remove it from the cache 18

    / 65
  19. Just ask them to clear the browser cache 19 /

    65
  20. Oh, that number is off because of our cache 20

    / 65
  21. No worries, our cache should be clear in about 4

    hours 21 / 65
  22. Oh shoot! I forgot to add the line that removes

    it from the cache 22 / 65
  23. Which leads to frustration... 23 / 65

  24. 24 / 65

  25. 25 / 65

  26. 26 / 65

  27. class: fake-middle, no-logo, image background-image: url(images/cache1.png) 27 / 65

  28. And Some other design problems like 28 / 65

  29. Cache Invalidation in callback hooks 29 / 65

  30. Inconsistent TTLs 30 / 65

  31. Inconsistent Cache Keys 31 / 65

  32. Nested Caching 32 / 65

  33. N+1 Queries from cache 33 / 65

  34. Unrealistic Experience 34 / 65

  35. What happens if your cache box dies? 35 / 65

  36. I'm not saying you should abandon caching altogether But maybe

    there is a better way 36 / 65
  37. What if I told you That some times looking up

    memcached could be slower than performing a lookup in your database 37 / 65
  38. Step 0 Understand your bottlenecks 38 / 65

  39. Most performance challenges are IO bound 39 / 65

  40. That might not be true sometimes, though 40 / 65

  41. Step 1 Understand your Database 41 / 65

  42. EXPLAIN and SLOW LOG are your best friends 42 /

    65
  43. Spend some time analyzing your indexes specially compound ones 43

    / 65
  44. Search Engines (SOLR, ElasticSearch) Try and understand how indexes are

    constructed. When commit operations are performed, analyze your indexes at write and read time. 44 / 65
  45. Redis SLOWLOG can save you 45 / 65

  46. Step 2 Use the best tool for the job 46

    / 65
  47. Still not convinced? 47 / 65

  48. How to Cache? 48 / 65

  49. HTTP Caching My favorite kind. If used wisely. Headers Varnish

    / Instart Logic 49 / 65
  50. Template Caching IMO, Doesn't sound like a great practice. 50

    / 65
  51. Controller Caching Very tricky and when it comes to state.

    51 / 65
  52. Model Caching Hard to design 52 / 65

  53. 53 / 65

  54. class Person include Kashmir def initialize(name, age) @name = name

    @age = age end representations do rep :name rep :age end end Person.new('Netto Farah', 27).represent(:name, :age) => {:name=>"Netto Farah", :age=>"27"} 54 / 65
  55. class Recipe < OpenStruct include Kashmir representations do rep(:title) rep(:chef)

    end end class Chef < OpenStruct include Kashmir representations do rep(:name) end end netto = Chef.new( name: 'Netto Farah' ) beef_stew = Recipe.new( title: 'Beef Stew', chef: netto ) beef_stew.represent( :title, { :chef => :name } ) => { :title => "Beef Stew", :chef => { :name => 'Netto Farah' } } 55 / 65
  56. And Many More Examples https://github.com/IFTTT/kashmir 56 / 65

  57. Cache Layers 57 / 65

  58. 58 / 65

  59. Database Query Planner Levarages ActiveRecord::Associations::Preloader 59 / 65

  60. Prevents N+1 Queries 60 / 65

  61. Chef.all.each do |chef| chef.recipes.to_a end SELECT * FROM chefs SELECT

    "recipes".* FROM "recipes" WHERE "recipes"."chef_id" = 1 SELECT "recipes".* FROM "recipes" WHERE "recipes"."chef_id" = 2 ... SELECT "recipes".* FROM "recipes" WHERE "recipes"."chef_id" = N 61 / 65
  62. Chef.all.represent([:recipes]) SELECT "chefs".* FROM "chefs" SELECT "recipes".* FROM "recipes" WHERE

    "recipes"."chef_id" IN (1, 2) 62 / 65
  63. Expiration Trickiest part. 63 / 65

  64. Advanced Use Cases Rest APIs GraphQL like endpoints 64 /

    65
  65. Questions? 65 / 65