Making an application scale and go faster is often seen as a wizardly task. We read the micro-optimisation tricks posted in tech blogs and apply them with unconditional trust and great hope, and then wonder why performances haven't improved that much ("Wait, I even replaced 'print' with 'echo'!!!").
In this talk we'll see how we can take easy, practical steps we can apply over and over that really make a difference, by analysing what our application does under the hood, measuring how and where the different resources are used, eliminating the real bottlenecks and restructuring critical components to handle growing loads.
6. Awareness is the
Know your targets
Know what it will take to meet them
Know your constraints
4
7. Tools: Profilers
Tools are just tools
They are absolutely essential
to doing your job
They will never do your job for you
Tools will never replace
experience and discipline
But tools can help you
maintain discipline
Theo Schlossnagle
5
13. XHProf UI Report - Web interface
Function Name
Calls
Wall Time (inclusive / exclusive)
CPU (inclusive / exclusive)
Memory (inclusive / exclusive)
Peak Memory Use (inclusive / exclusive)
# and %
8
18. Know Your Framework
Measure the baseline
Shortcuts aren’t always “free”
When there are two ways of doing something,
usually one is much better
Loading (classes, resources) is expensive
12
20. Know Your Framework
Measure the baseline
Shortcuts aren’t always “free”
When there are two ways of doing something,
usually one is much better
Loading (classes, resources) is expensive
14
21. Shortcuts - The Real Cost
public function doSomething(array $data) {
// Zend_Config object
$config = $this->getConfig();
$var = $config->aaa->bbb->ccc;
// ...
}
15
22. Shortcuts - The Real Cost
public function doSomething(array $data) {
// Zend_Config object
$config = $this->getConfig();
$var = $config->aaa->bbb->ccc;
// ...
}
15
23. Shortcuts - The Real Cost
public function doSomething(array $data) {
// Zend_Config object
$config = $this->getConfig();
$var = $config->aaa->bbb->ccc;
// ...
}
15
24. Shortcuts - The Real Cost
public function doSomething(array $data) {
// Zend_Config object
$config = $this->getConfig();
$var = $config->aaa->bbb->ccc;
// ...
}
2
1
3
15
25. Know Your Framework
Measure the baseline
Shortcuts aren’t always “free”
When there are two ways of doing something,
usually one is much better
Loading (classes, resources) is expensive
16
36. Know Your Framework
Measure the baseline
Shortcuts aren’t always “free”
When there are two ways of doing something,
usually one is much better
Loading (classes, resources) is expensive
20
43. Rules of thumb
Profile / Measure
Sort by [ Excl. CPU | Memory | Time | Calls ]
Start from the TOP of the list
Analyse, refactor, optimise
Measure improvement
Start over
24
44. Rules of thumb
Profile / Measure
Sort by [ Excl. CPU | Memory | Time | Calls ]
Start from the TOP of the list
Analyse, refactor, optimise
Measure improvement
Start over
Again, and again, and again.
24
54. Refactoring hints
PHP is FAST
...but do you really need to call strtolower()
15000 times?
29
55. Refactoring hints
PHP is FAST
...but do you really need to call strtolower()
15000 times?
Re-think why you’re doing something,
if it’s the right place to do it,
and if possible reduce the amount of data you
need to process
29
56. Code smells
Immutable functions called within loops
Same content being generated twice
Content that does not change being generated every time
Content being generated even if not used
30
57. Code smells
Immutable functions called within loops
Same content being generated twice
Content that does not change being generated every time
Content being generated even if not used
Sometimes it’s less obvious than it might seem
30
59. Caching (computational reuse)
Static variables
APC / Zend Server Cache / ...
Memcached
Reverse proxies
Browser
Do no work at all, if you can avoid it
31
76. Watch your error log!
Warning: Undefined index: NAME in file.php on line 1269
Warning: Undefined index: DESC in file.php on line 1270
Warning: Undefined variable: $str in a.php on line 341
Warning: Undefined index: DESC in file.php on line 1270
@
Error suppression is bad
http://derickrethans.nl/five-reasons-why-the-shutop-operator-should-be-avoided.html
40
77. Watch your error log!
Warning: Undefined index: NAME in file.php on line 1269
Warning: Undefined index: DESC in file.php on line 1270
Warning: Undefined variable: $str in a.php on line 341
Warning: Undefined index: DESC in file.php on line 1270
@
Error suppression is bad
http://derickrethans.nl/five-reasons-why-the-shutop-operator-should-be-avoided.html
40
80. Analyse logs (Observability)
[HTTP] GET http://myservice.com/list/somelist
[HTTP] GET http://myservice.com/id/1
[HTTP] PUT http://myservice.com/id/3/value/xyz
[HTTP] GET http://myservice.com/list/somelist
[HTTP] GET http://myservice.com/list/somelist
[DB] SELECT * FROM mytable;
[DB] SELECT name FROM cities ORDER BY name;
[DB] SELECT name FROM cities ORDER BY name;
[DB] SELECT name FROM cities ORDER BY name;
[DB] UPDATE mytable SET name=‘xyz’ WHERE id=3;
Consider caching frequent requests
42
81. Profile under load
Collect profile data from a sample of random requests
if (0 == mt_rand(0, 1000)) {
// collect profile data
}
43
82. Profile under load
Collect profile data from a sample of random requests
if (0 == mt_rand(0, 1000)) {
// collect profile data
}
Monitor resource usage in real time (top / htop / vmstat)
43
83. Profile under load
Collect profile data from a sample of random requests
if (0 == mt_rand(0, 1000)) {
// collect profile data
}
Monitor resource usage in real time (top / htop / vmstat)
Analyse graphs
JMeter
The Grinder
43
84. Performance Counters
Used / available memory (local, shared)
Pages / sec
Response time & Time-outs
Successful / failed transactions
Open sockets / connections
Bandwidth (internal network too!)
CPU
All the resources are limited
...
44
87. Circuit Breaker
public function fetchData($key) {
return $this->callService($key);
}
47
88. Circuit Breaker
public function fetchData($key) {
$config = array(
'check_timeout' => 10,
'failure_threshold' => 10,
);
$cb = new Circuit_Breaker('name', $config);
if ($cb->isClosed()) {
$ok = $this->callService($key);
public function fetchData($key) {
if ($ok) {
return $this->callService($key);
} $cb->success();
} else {
//increment failures count
$cb->fail();
}
}
}
47
89. Poor man’s circuit breaker
public function fetchData($key) {
static $failures = 0;
if ($failures < self::MAX_FAILURES) {
$ok = $this->callService($key);
if ($ok) {
--$failures;
} else {
++$failures;
}
}
}
Save the counter in memcached
instead of a static variable, if possible
48
92. Performance Checklist
Deep understanding of the problem at hand
Good architecture / design / data structures / algorithms
Do the absolute minimum
Use the right tools, always validate assumptions
Monitor resource usage (!), with many metrics
Spread the load uniformly across the resources
Decouple services
Good caching strategy strategies (sharing / reuse)
51