Rails Performance Michael Koziarski michael@koziarski.com Rails - - PowerPoint PPT Presentation

rails performance
SMART_READER_LITE
LIVE PREVIEW

Rails Performance Michael Koziarski michael@koziarski.com Rails - - PowerPoint PPT Presentation

Rails Performance Michael Koziarski michael@koziarski.com Rails Performance Relax Programmers Love Optimisation Science Based Objective Provable Opportunity Cost Is this optimisation really the best use of your time? Two Justifications


slide-1
SLIDE 1

Rails Performance

Michael Koziarski michael@koziarski.com

slide-2
SLIDE 2

Rails Performance

slide-3
SLIDE 3

Relax

slide-4
SLIDE 4

Programmers Love Optimisation

slide-5
SLIDE 5

Science Based

slide-6
SLIDE 6

Objective

slide-7
SLIDE 7

Provable

slide-8
SLIDE 8

Opportunity Cost

slide-9
SLIDE 9

Is this optimisation really the best use of your time?

slide-10
SLIDE 10

Two Justifications

slide-11
SLIDE 11

Hardware Costs

slide-12
SLIDE 12

Responsiveness

slide-13
SLIDE 13

Hardware Costs

slide-14
SLIDE 14

Profits = Revenue - Costs

slide-15
SLIDE 15

Hardware isn’t all of your costs

slide-16
SLIDE 16

Hardware costs are not continuous

slide-17
SLIDE 17

Hardware costs are not continuous

Unless you’re huge

slide-18
SLIDE 18

Hardware costs are not continuous

Unless you’re huge You’re not huge

slide-19
SLIDE 19

Hardware is basically free

slide-20
SLIDE 20

Hardware is basically free

Compared to staff

slide-21
SLIDE 21

Hardware Cost Driven Optimisation

slide-22
SLIDE 22

Example.com

  • 4 Servers at $299/mo
  • Total hosting of ~ $1,200/mo
slide-23
SLIDE 23

Example.com

  • 10% performance improvement across the

board!

  • Leads to a $120/mo saving...
slide-24
SLIDE 24

Example.com

  • Staff costing 60-80k/yr
  • $28-$38/hr
slide-25
SLIDE 25

It almost certainly wasn’t worth it

slide-26
SLIDE 26

Responsiveness

slide-27
SLIDE 27

Much more Important

slide-28
SLIDE 28

Slow applications are no fun to use

slide-29
SLIDE 29

No Users

slide-30
SLIDE 30

No Revenue

slide-31
SLIDE 31

No Business

slide-32
SLIDE 32
slide-33
SLIDE 33

Not about requests per second

slide-34
SLIDE 34

Seconds per request

slide-35
SLIDE 35

Perceived Performance

slide-36
SLIDE 36
slide-37
SLIDE 37
slide-38
SLIDE 38
slide-39
SLIDE 39

853ms

slide-40
SLIDE 40

3:00

slide-41
SLIDE 41

PHP is 0.4% of the total

slide-42
SLIDE 42

Assume it gets 50% faster

slide-43
SLIDE 43

The net saving is 0.2%

slide-44
SLIDE 44

Not Noticeable

slide-45
SLIDE 45

Frontend Performance should be your Priority

slide-46
SLIDE 46

YSlow

slide-47
SLIDE 47
slide-48
SLIDE 48
slide-49
SLIDE 49
slide-50
SLIDE 50
slide-51
SLIDE 51

Fix all of these

slide-52
SLIDE 52

I’ve done all that!

slide-53
SLIDE 53

Optimisation Procedure

slide-54
SLIDE 54

Optimisation Procedure

  • 1. Figure out what’s slow
slide-55
SLIDE 55

Optimisation Procedure

  • 1. Figure out what’s slow
  • 2. Figure out why it’s slow
slide-56
SLIDE 56

Optimisation Procedure

  • 1. Figure out what’s slow
  • 2. Figure out why it’s slow
  • 3. Make it faster
slide-57
SLIDE 57
  • 1. Find What’s Slow
slide-58
SLIDE 58

Choose your target

slide-59
SLIDE 59

Choose your target

  • Slower than the rest
slide-60
SLIDE 60

Choose your target

  • Slower than the rest
  • Heavily used
slide-61
SLIDE 61
slide-62
SLIDE 62
slide-63
SLIDE 63
slide-64
SLIDE 64
slide-65
SLIDE 65
slide-66
SLIDE 66
slide-67
SLIDE 67
slide-68
SLIDE 68

Grep your Logs

slide-69
SLIDE 69

Grep your Logs

Completed in 220ms (View: 72, DB: 5)

slide-70
SLIDE 70

Grep your Logs

Completed in 220ms (View: 72, DB: 5) X-Runtime: 0.00783

slide-71
SLIDE 71

PL Analyze

slide-72
SLIDE 72
  • 1b. Cheat
slide-73
SLIDE 73

Caching!

slide-74
SLIDE 74

HTTP Caching

slide-75
SLIDE 75

ETags

slide-76
SLIDE 76

ETags

ETag: b4c2fedde6926a5ee6ed8cd5cc995592

slide-77
SLIDE 77

ETags

ETag: b4c2fedde6926a5ee6ed8cd5cc995592 If-None-Match: b4c2fedde6926a5ee6ed8cd5cc995592

slide-78
SLIDE 78

ETags

ETag: b4c2fedde6926a5ee6ed8cd5cc995592 If-None-Match: b4c2fedde6926a5ee6ed8cd5cc995592





def
handle_etag 





etag!
[@user.id,
@user.updated_at] 



end

slide-79
SLIDE 79

Last-Modified

slide-80
SLIDE 80

Last-Modified

Last-Modified: Sun, 28 Sep 2008 19:38:05 GMT

slide-81
SLIDE 81

Last-Modified

Last-Modified: Sun, 28 Sep 2008 19:38:05 GMT If-Not-Modified-Since: Sun, 28 Sep 2008 19:38:05 GMT

slide-82
SLIDE 82

Last-Modified

Last-Modified: Sun, 28 Sep 2008 19:38:05 GMT If-Not-Modified-Since: Sun, 28 Sep 2008 19:38:05 GMT





def
handle_last_modified 





last_modified!
@user.updated_at 



end

slide-83
SLIDE 83

Expires





def
add_expires 





response.headers["Expires"]
=
@user.updated_at
+
1.hour 



end

slide-84
SLIDE 84

Rails Caching

slide-85
SLIDE 85

Fragment Caching

<%
cache
[@user,
"dashboard"]
do
%> 

<%=
render
:partial=>"complex_expensive_dashboard"
%> <%
end
%>

slide-86
SLIDE 86

Action Caching

caches_action
:index

slide-87
SLIDE 87

Model Caching

class
Comment
<
ActiveRecord::Base 

acts_as_cached
:ttl=>1.hour end

slide-88
SLIDE 88

Memcache

  • Seriously Fast
  • Seriously Scalable
  • LRU Cache Expunging
slide-89
SLIDE 89

Cache Generations

There are only two hard things in Computer Science: cache invalidation and naming things

slide-90
SLIDE 90

Cache Generations

There are only two hard things in Computer Science: cache invalidation and naming things So let’s not explicitly invalidate anything

slide-91
SLIDE 91

Cache Generations

cache
["user",
@user.id]

cache
["user_profile",
@user.id]


slide-92
SLIDE 92

Cache Generations

cache
["user",
@user.id,
@user.generation]

cache
["user_profile",
@user.id,
@user.generation]


slide-93
SLIDE 93

Cache Generations

class
User
<
ActiveRecord::Base 

before_save
:increment_generation 

 

def
increment_generation 



self.generation
+=
1
 

end end

slide-94
SLIDE 94

Cache Generations

class
Friendship
<
ActiveRecord::Base 

belongs_to
:owner,
:class_name=>"User" 

belongs_to
:friend,
:class_name=>"User" 

before_save
:increment_both_users 

 

def
increment_both_users 



[owner,
friend].map
&:increment_generation 

end end

slide-95
SLIDE 95
  • 2. Figure out why it’s

slow

slide-96
SLIDE 96

Never Guess

slide-97
SLIDE 97

You’re never right

slide-98
SLIDE 98

Slow Trac

slide-99
SLIDE 99

Slow Trac

  • Use a new PostgreSQL driver
slide-100
SLIDE 100

Slow Trac

  • Use a new PostgreSQL driver
  • Use mod_python, not tracd
slide-101
SLIDE 101

Slow Trac

  • Use a new PostgreSQL driver
  • Use mod_python, not tracd
  • It’s spammers, add a better spam plugin
slide-102
SLIDE 102

Slow Trac

@project.head_revision

slide-103
SLIDE 103

Slow Trac

SELECT
max(rev)
FROM
rev;

slide-104
SLIDE 104

Slow Trac

SELECT
rev
FROM
rev
 ORDER
BY
‐LENGTH(rev),
rev
 LIMIT
1;

slide-105
SLIDE 105

Slow Trac

SELECT
max(rev::integer)
FROM
rev;

slide-106
SLIDE 106

Slow Trac

CREATE
INDEX
rev_as_INT
 ON
rev(rev::integer);

slide-107
SLIDE 107

Performance Tests

New in 2.2

slide-108
SLIDE 108

Performance Tests

require
'performance/test_helper' class
SessionActionsTest
<
ActionController::PerformanceTest

slide-109
SLIDE 109

Performance Test



def
test_fetching_index 



get
"/sessions" 

end 

def
test_fetching_index_all 



get
"/sessions?all=true" 

end

slide-110
SLIDE 110

Performance Test

rake test:benchmark

slide-111
SLIDE 111

Performance Test

rake test:benchmark

SessionActionsTest#test_fetching_index
(54
ms
warmup) 







process_time:
70
ms 













memory:
0.00
KB 












objects:
0 












gc_runs:
0 












gc_time:
0
ms

slide-112
SLIDE 112

Performance Test



def
setup 



u
=
users(:koz) 



post
authenticate_url,
... 



50.times
do
|i| 





u.sessions.create! 



end 

end

slide-113
SLIDE 113

Performance Tests

SessionActionsTest#test_fetching_index
(254
ms
warmup) 







process_time:
270
ms 













memory:
0.00
KB 












objects:
0 












gc_runs:
0 












gc_time:
0
ms

slide-114
SLIDE 114

Performance Tests

rake test:profile

slide-115
SLIDE 115

Performance Tests

SessionActionsTest#test_fetching_index_process_time_graph.html

slide-116
SLIDE 116

Performance Tests

slide-117
SLIDE 117

Performance Tests

slide-118
SLIDE 118

Performance Tests

slide-119
SLIDE 119

Performance Tests

SessionActionsTest#test_fetching_index_all_objects_graph.html

slide-120
SLIDE 120

Performance Tests

slide-121
SLIDE 121

Performance Tests

slide-122
SLIDE 122

Performance Tests

slide-123
SLIDE 123

Performance Tests

slide-124
SLIDE 124
  • 3. Make it Faster
slide-125
SLIDE 125

<%=
image_tag
"red.png"
%>

<img
src="/images/red.png?1212215830"
/>

slide-126
SLIDE 126

<%=
image_tag
"onepixel.gif"
%>

slide-127
SLIDE 127

Route Generation

<p>Have
you
considered
<%=
link_to
"Paying
me
money",
 


































awesome_consultant_url
%></p>

slide-128
SLIDE 128

Route Generation

<p>Have
you
considered
<%=
link_to
"Paying
me
money",
 


































awesome_consultant_url
%></p>

slide-129
SLIDE 129

N+1 Queries

<%
@user.posts.each
do
|post|
%> 



<p><%=
link_to
post.title,
post_url(post)
%></p> <%
end
%>

slide-130
SLIDE 130

N+1 Queries

User.find(params[:id],
:include=>[:posts])

slide-131
SLIDE 131

N+1 Queries

<%
@user.posts.each
do
|post|
%> 



<p> 







<%=
link_to
post.title,
post_url(post)
%> 








by
 







<%=
post.author.name
%> 



</p> <%
end
%>

slide-132
SLIDE 132

Garbage Collection

PageShowTest#test_show
(246
ms
warmup) 







process_time:
183
ms 













memory:
1696.26
KB 












objects:
116280 












gc_runs:
0 












gc_time:
42
ms

22% in GC

slide-133
SLIDE 133

Garbage Collection

http://github.com/skaes/railsbench

slide-134
SLIDE 134

Garbage Collection

#
greatly
increase
initial
heap
slots
available
(60x
more)
 RUBY_HEAP_MIN_SLOTS=600000
 #
ensure
lots
of
heap
slots
are
freed
after
GC
(25x
more)
 RUBY_HEAP_FREE_MIN=100000
 #
and
don’t
run
GC
unless
we're
over
60MB
heap
(7.5x
more)
 RUBY_GC_MALLOC_LIMIT=60000000

slide-135
SLIDE 135

Conclusion

slide-136
SLIDE 136

Fix Frontend Performance First

slide-137
SLIDE 137

Use HTTP

slide-138
SLIDE 138

Cache with memcache

slide-139
SLIDE 139

Profile, don’t guess

slide-140
SLIDE 140

Don’t forget GC when profiling

slide-141
SLIDE 141

Questions?

Michael Koziarski michael@koziarski.com