Slide 1

Slide 1 text

WHY I HATE CACHING AND THE THINGS I'M TRYING TO DO TO CHANGE IT @nettofarah 1 / 65

Slide 2

Slide 2 text

nettofarah github.com/nettofarah @nettofarah http://bit.ly/kashmir-netto 2 / 65

Slide 3

Slide 3 text

Senior Product Engineer @ IFTTT 3 / 65

Slide 4

Slide 4 text

IFTTT Connect the Apps you Love 4 / 65

Slide 5

Slide 5 text

IFTTT Millions of Users Website (desktop & mobile) 8 Apps (IF & DO) Billions of Requests and Transactions every day 5 / 65

Slide 6

Slide 6 text

Rails doesn't Scale Said someone in the Past. For whatever reason. 6 / 65

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

Background Jobs 8 / 65

Slide 9

Slide 9 text

With a lot of Processes or With Threads 9 / 65

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Easy and beautiful at first 11 / 65

Slide 12

Slide 12 text

Incredibly tricky after some time 12 / 65

Slide 13

Slide 13 text

Caching is like Cocaine 13 / 65

Slide 14

Slide 14 text

What is Caching Anyway? 14 / 65

Slide 15

Slide 15 text

The 2 Hardest Problems in Computer Science 15 / 65

Slide 16

Slide 16 text

Cache Invalidation and Naming Things 16 / 65

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Oops, we forgot to remove it from the cache 18 / 65

Slide 19

Slide 19 text

Just ask them to clear the browser cache 19 / 65

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Oh shoot! I forgot to add the line that removes it from the cache 22 / 65

Slide 23

Slide 23 text

Which leads to frustration... 23 / 65

Slide 24

Slide 24 text

24 / 65

Slide 25

Slide 25 text

25 / 65

Slide 26

Slide 26 text

26 / 65

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

And Some other design problems like 28 / 65

Slide 29

Slide 29 text

Cache Invalidation in callback hooks 29 / 65

Slide 30

Slide 30 text

Inconsistent TTLs 30 / 65

Slide 31

Slide 31 text

Inconsistent Cache Keys 31 / 65

Slide 32

Slide 32 text

Nested Caching 32 / 65

Slide 33

Slide 33 text

N+1 Queries from cache 33 / 65

Slide 34

Slide 34 text

Unrealistic Experience 34 / 65

Slide 35

Slide 35 text

What happens if your cache box dies? 35 / 65

Slide 36

Slide 36 text

I'm not saying you should abandon caching altogether But maybe there is a better way 36 / 65

Slide 37

Slide 37 text

What if I told you That some times looking up memcached could be slower than performing a lookup in your database 37 / 65

Slide 38

Slide 38 text

Step 0 Understand your bottlenecks 38 / 65

Slide 39

Slide 39 text

Most performance challenges are IO bound 39 / 65

Slide 40

Slide 40 text

That might not be true sometimes, though 40 / 65

Slide 41

Slide 41 text

Step 1 Understand your Database 41 / 65

Slide 42

Slide 42 text

EXPLAIN and SLOW LOG are your best friends 42 / 65

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Redis SLOWLOG can save you 45 / 65

Slide 46

Slide 46 text

Step 2 Use the best tool for the job 46 / 65

Slide 47

Slide 47 text

Still not convinced? 47 / 65

Slide 48

Slide 48 text

How to Cache? 48 / 65

Slide 49

Slide 49 text

HTTP Caching My favorite kind. If used wisely. Headers Varnish / Instart Logic 49 / 65

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Model Caching Hard to design 52 / 65

Slide 53

Slide 53 text

53 / 65

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

And Many More Examples https://github.com/IFTTT/kashmir 56 / 65

Slide 57

Slide 57 text

Cache Layers 57 / 65

Slide 58

Slide 58 text

58 / 65

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

Prevents N+1 Queries 60 / 65

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

Expiration Trickiest part. 63 / 65

Slide 64

Slide 64 text

Advanced Use Cases Rest APIs GraphQL like endpoints 64 / 65

Slide 65

Slide 65 text

Questions? 65 / 65