Developing applications for performance

Leon Fayer
Leon FayerTechnologist | Public Speaker | Author | DevOps [something]
@papa_fire
Developing Applications
for Performance
by Leon Fayer
@papa_fire
{me}
‣ developer ++
‣ i drink and i fix code
‣ vp @ OmniTI
‣ make slow go fast
@papa_fire
disclaimers
@papa_fire
disclaimers
1. performance is technology agnostic
@papa_fire
disclaimers
1. performance is technology agnostic
2. performance != scalability
@papa_fire
disclaimers
1. performance is technology agnostic
2. performance != scalability
3. there is more to performance
@papa_fire
disclaimers
1. performance is technology agnostic
2. performance != scalability
3. there is more to performance
4. it’s (almost) all about web
@papa_fire
why performance?
@papa_fire
it improves user experience
@papa_fire
(and as a result)
it effects business
@papa_fire
“
Just a 100-millisecond delay
in load time hurt conversion
rate by 7%
https://www.soasta.com/wp-content/uploads/2017/04/State-of-Online-Retail-Performance-Spring-2017.pdf
@papa_fire
it saves money
(in production)
@papa_fire
50 users/sec
served by 2 web servers
costing $300/month
x
x
$600/month
@papa_fire
1000 users/sec
served by 40 web servers
costing $300/month
x
x
$12,000/month
@papa_fire
this is why cloud doesn’t solve
all your problems
@papa_fire
only slide on scalability
‣ don’t scale instead of improving
performance
‣ keep scaling in mind during design
@papa_fire
what can you optimize?
@papa_fire
everything!
@papa_fire
<front end>
@papa_fire
High Performance
Web Sites
by Steve Souders
@papa_fire
SPOF
(single point of failure)
@papa_fire
(in the world of web)
service integrations
@papa_fire
ngm.com
@papa_fire
codercruise.com
http://requestmap.webperf.tools
@papa_fire
what happens when they fail?
@papa_fire
http://www.webpagetest.org/
@papa_fire
3rd party = no control
@papa_fire
one failure is enough
@papa_fire
- site implement Facebook Connect
- site implement Facebook Connect incorrectly
- site load times increase 4x
- Facebook has issues
- Facebook keeps connections open
- site load times increase 500x (until timeout)
- Facebook crashes
- site crashes
- game over
@papa_fire
services can be your own
PSA
@papa_fire
tips
@papa_fire
tips
only connect to the services you need
@papa_fire
tips
only connect to the services you need
avoid external connection on critical path
@papa_fire
tips
only connect to the services you need
avoid external connection on critical path
make external calls asynchronously
@papa_fire
tips
only connect to the services you need
avoid external connection on critical path
make external calls asynchronously
trap errors and timeouts
@papa_fire
tips
only connect to the services you need
avoid external connection on critical path
make external calls asynchronously
trap errors and timeouts
have a fallback plan
@papa_fire
</front end>
@papa_fire
<database>
@papa_fire
http://use-the-index-luke.com
Markus Winand
@papa_fire
n+1
@papa_fire
$blog = new Blog(‘leon’);
$posts = $blog->get_all_posts();
foreach ($posts as $post) {
$post->comments = $post->get_comments();
}
@papa_fire
$dbh = new DB(…);
$sth = $dbh->prepare("select * from posts where author = ?”);
$sth->execute(‘leon’);
$posts = array();
foreach ($sth->fetchAll() as $p) {
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
array_push($posts, $post);
}
foreach ($posts as $post) {
$dbh2 = new DB(…);
$sth_comm = $dbh2->prepare("select * from post_comments where post_id = ?");
$sth_comm->execute($post->post_id);
foreach(sth_comm->fetchAll() as $c) {
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
}
@papa_fire
$dbh = new DB(…);
$sth = $dbh->prepare("select * from blogs where username = ?”);
$sth->execute(‘leon’);
$posts = array();
foreach ($sth->fetchAll() as $p) {
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
array_push($posts, $post);
}
foreach ($posts as $post) {
$dbh2 = new DB(…);
$sth_comm = $dbh2->prepare("select * from post_comments where post_id = ?");
$sth_comm->execute($post->post_id);
foreach(sth_comm->fetchAll() as $c) {
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
}
$sth = $dbh->prepare("select * from posts where author = ?”);
@papa_fire
$dbh = new DB(…);
$sth = $dbh->prepare("select * from posts where author = ?”);
$sth->execute(‘leon’);
$posts = array();
foreach ($sth->fetchAll() as $p) {
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
array_push($posts, $post);
}
foreach ($posts as $post) {
$dbh2 = new DB(…);
$sth_comm = $dbh2->prepare("select * from post_comments where post_id = ?");
$sth_comm->execute($post->post_id);
foreach(sth_comm->fetchAll() as $c) {
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
}
$sth_comm = $dbh2->prepare("select * from post_comments where post_id = ?");
@papa_fire
$dbh = new DB(…);
$sth = $dbh->prepare("select * from posts where author = ?”);
$sth->execute(‘leon’);
$posts = array();
foreach ($sth->fetchAll() as $p) {
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
array_push($posts, $post);
}
foreach ($posts as $post) {
$dbh2 = new DB(…);
$sth_comm = $dbh2->prepare("select * from post_comments where post_id = ?");
$sth_comm->execute($post->post_id);
foreach(sth_comm->fetchAll() as $c) {
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
}
$sth_comm = $dbh2->prepare("select * from post_comments where post_id = ?");
foreach ($posts as $post) {
@papa_fire
1 post = 2 queries
10 posts = 11 queries
100 posts = 101 queries
…
@papa_fire
but that’s not all
@papa_fire
$dbh = new DB(…);
$sth = $dbh->prepare("select * from posts where author = ?”);
$sth->execute(‘leon’);
$posts = array();
foreach ($sth->fetchAll() as $p) {
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
array_push($posts, $post);
}
foreach ($posts as $post) {
$dbh2 = new DB(…);
$sth_comm = $dbh2->prepare("select * from post_comments where post_id = ?");
$sth_comm->execute($post->post_id);
foreach(sth_comm->fetchAll() as $c) {
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
}
$dbh = new DB(…);
$dbh2 = new DB(…);
@papa_fire
@papa_fire
@papa_fire
the right way
@papa_fire
$dbh = new DB(…);
$sth = $dbh->prepare("select [list columns you need] from posts p, post_comments c
where p.id = c.post_id
and p.username = ?
order by p.id DESC”);
$sth->execute(‘leon’);
$posts = array();
$post = new Post();
$active_pid = 0;
foreach ($sth->fetchAll() as $p) {
if ($post->id != $active_pid) { // if this row is for the post we’re working on
if ($post->id) {
array_push($posts, $post);
}
$active_pid = $post->id; // getting comments for this post
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
}
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
@papa_fire
$dbh = new DB(…);
$sth = $dbh->prepare("select [list columns you need] from posts p, post_comments c
where p.id = c.post_id
and p.username = ?
order by p.id DESC”);
$sth->execute(‘leon’);
$posts = array();
$post = new Post();
$active_pid = 0;
foreach ($sth->fetchAll() as $p) {
if ($post->id != $active_pid) { // if this row is for the post we’re working on
if ($post->id) {
array_push($posts, $post);
}
$active_pid = $post->id; // getting comments for this post
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
}
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
$dbh = new DB(…);
$sth = $dbh->prepare("select [list columns you need]
from posts p, post_comments c
where p.id = c.post_id
and p.username = ?
order by p.id DESC”);
@papa_fire
1 post = 1 query
10 posts = 1 query
100 posts = 1 query
…
@papa_fire
Common Table Expressions (CTE)
to further reduce a number of
queries
http://omniti.com/seeds/writable-ctes-improve-performance
PSA
@papa_fire
$blog = new Blog(‘leon’);
$posts = $blog->get_all_posts_with_comments();
@papa_fire
$posts = $blog->get_all_posts_with_comments();
$dbh = new DB(…);
$sth = $dbh->prepare("select [list columns you need]
from posts p, post_comments c
where p.id = c.post_id
and p.username = ?
order by p.id DESC”);
$sth->execute(‘leon’);
$posts = array();
$post = new Post();
$active_pid = 0;
foreach ($sth->fetchAll() as $p) {
if ($post->id != $active_pid) { // if this row is for the post we’re
if ($post->id) {
array_push($posts, $post);
}
$active_pid = $post->id; // getting comments for this post
$post = new Post();
$post->id = $p->[‘id’];
$post->title = $p->[‘title’];
$post->author = $p->[‘author’];
$post->body = $p->[‘body’];
}
$comment = new Comment();
$comment->id = $c->[‘id’];
$comment->author = $c->[‘author’];
$comment->body = $c->[‘body’];
array_push($post->comments, $comment);
}
@papa_fire
that’s awesome!
(right?)
@papa_fire
do you know what’s
under the hood?
@papa_fire
ORMs are evil
@papa_fire
you have no idea how they work
@papa_fire
1. machine-generated
2. object construction overhead
3. false sense of control
@papa_fire
“
think about ORM as the
most junior developer you’ve
ever worked with
@papa_fire
select * from
(
select bannerid, caption, client_url, image_file, sponsorid, weight from
(
select V.bannerid, V.impressions, B.caption, B.client_url, B.image_file, s.sponsorid,
s.weight,
row_number() over (partition by s.sponsorid order by s.weight desc) ranking
FROM
(
-- This level gives me a list of banners sorted by least seen,and then by highest
weight
select valid.bannerid, valid.totalweight, count(I.timestamp) as impressions FROM
(
-- This level gets me a list of banners that are valid for display
select b.bannerid,
-- Add up the weight from 4 sources. Banner weight, and weight for
each data item they match
decode( decode(bitand(u.STATE_BM1,b.STATE_BM1),0,0,1) +
decode(bitand(u.STATE_BM2,b.STATE_BM2),0,0,1) +
decode(bitand(u.STATE_BM3,b.STATE_BM3),0,0,1),
0,0,b.STATE_WT
) +
decode(bitand(u.AGE_BM,b.AGE_BM),0,0,b.AGE_WT)+
decode(bitand(u.GENDER_BM,b.GENDER_BM),0,0,b.GENDER_WT)+
b.weight as totalweight
from tgif.tbl_users u, tgif.tbl_banners b, tgif.tbl_bannerstats bs
where
-- I only care about ME!
u.userid= 1
-- Don't show inactive banners
and b.inactive != 1
-- Only show banners that are currently running
and sysdate < b.end_date and sysdate >=b.start_date
-- Only get the type of banner i'm looking for
and b.type= 3
-- Join on the total stats, and only display banners that
haven't reached their per banner maximums
and b.bannerid = bs.bannerid
and ( b.max_impressions IS NULL OR bs.total_impressions
< b.max_impressions )
and ( b.max_clicks IS NULL OR bs.total_clicks <
b.max_clicks )
and ( b.max_conversions IS NULL OR bs.total_conversions
< b.max_conversions )
-- Ignore any banners that don't match their demographics (ie,
male banner won't go to females)
and ( b.AGE_BM IS NULL OR b.AGE_BM = 0 OR
bitand(u.AGE_BM, b.AGE_BM) != 0 )
and ( b.GENDER_BM IS NULL OR b.GENDER_BM =0 OR
bitand(u.GENDER_BM, b.GENDER_BM) != 0 )
and ( b.STATE_BM1 IS NULL OR b.STATE_BM1 =0 OR
bitand(u.STATE_BM1, b.STATE_BM1) != 0 )
and ( b.STATE_BM2 IS NULL OR b.STATE_BM2 =0 OR
bitand(u.STATE_BM2, b.STATE_BM2) != 0 )
and ( b.STATE_BM3 IS NULL OR b.STATE_BM3 =0 OR
bitand(u.STATE_BM3, b.STATE_BM3) != 0 )
-- But don't show me any banners that I have already signed up
and b.bannerid NOT IN (
SELECT B.bannerid FROM tgif.tbl_bannerconversions C,
tgif.tbl_banners B, tgif.tbl_sponsors sp
WHERE C.USERID=1
AND C.bannerid=B.bannerid
AND B.sponsorid=sp.sponsorid
-- unless they have a conversion interval, and that
interval has expired
AND ( sp.conversion_interval = 0 OR sysdate >
C.timestamp+sp.conversion_interval )
)
-- Don't show me any banners that have SPONSORS that have
reached their maximums
and b.sponsorid NOT IN (
-- I believe this would be better done using HAVING
clauses, but I can't figure it out
-- Take the banners for a sponsor in the bannerstats
table, and get the totals per sponsor
-- return anything that has reached it's maximum
select sponsorid FROM
(
SELECT S.sponsorid, S.max_impressions,
S.max_conversions, S.max_clicks,
sum(total_impressions) as imps,
sum(total_conversions) as convs, sum(total_clicks)
as clicks
FROM tgif.tbl_sponsors S, tgif.tbl_banners B,
tgif.tbl_bannerstats bs
WHERE S.sponsorid=B.sponsorid
AND B.bannerid=bs.bannerid
GROUP BY S.Sponsorid, S.max_impressions,
S.max_conversions, S.max_clicks
) exclude
WHERE ( imps > max_impressions OR convs >=
max_conversions OR clicks > max_clicks )
)
) valid, tgif.tbl_bannerimpressions I
where
valid.bannerid=I.bannerid(+)
and I.userid(+)=1
group by valid.bannerid, valid.totalweight
-- I want to see banners I haven't seen yet, sorted by highest weight, so we sort by number
-- of times that this user has seen this particular banner, then we sort by weight
order by impressions, totalweight DESC
) V, tgif.tbl_banners B, tgif.tbl_sponsors S
where B.bannerid=V.bannerid
and B.sponsorid=S.sponsorid
and S.inactive != 1
and s.sponsorid not in (
) valid, tgif.tbl_bannerimpressions I
where
valid.bannerid=I.bannerid(+)
and I.userid(+)=1
group by valid.bannerid, valid.totalweight
-- I want to see banners I haven't seen yet, sorted by highest weight, so we sort by number
-- of times that this user has seen this particular banner, then we sort by weight
order by impressions, totalweight DESC
) V, tgif.tbl_banners B, tgif.tbl_sponsors S
where B.bannerid=V.bannerid
and B.sponsorid=S.sponsorid
and S.inactive != 1
and s.sponsorid not in (
-- Check the user impression cap to make sure it hasn't been passed by the user
select s.sponsorid from tgif.tbl_banners b, tgif.tbl_sponsors s,
tgif.TBL_BANNERIMPRESSIONS i
where s.sponsorid = b.sponsorid
and b.bannerid = i.bannerid
and i.timestamp >= sysdate - nvl(user_impression_cap_days,100)
and userid = 1
group by s.sponsorid
having count(*) >= max(nvl(user_impression_cap,1000000000))
)
-- Make sure the sponsor is still in the valid table. This table is updated hourly
-- and contains the sponsors that have not gone over their sponsor level frequencies for
-- impressions/conversions/clicks
and s.sponsorid in (select sponsorid from tgif.tbl_active_sponsors)
)
where ranking=1
--Order the banners by sponsor weight, which is handled by the ranking
--order by S.weight
order by impressions, weight desc
)
where rownum <= 10;
would you trust
a junior with
this query?
@papa_fire
object construction is very expensive
@papa_fire
METHOD REAL USER SYS PCPU
Base ORM 6.330 5.771 0.212 94.51
@papa_fire
METHOD REAL USER SYS PCPU
Base ORM 6.330 5.771 0.212 94.51
SQL without
objects
0.664 0.274 0.120 59.35
@papa_fire
METHOD REAL USER SYS PCPU
Base ORM 6.330 5.771 0.212 94.51
SQL without
objects
0.664 0.274 0.120 59.35
SQL with ORM
objects
6.354 5.797 0.197 94.34
@papa_fire
get_all_* are the worst
@papa_fire
#	return	a	collection	with	all	articles	
articles	=	Article.all
@papa_fire
#	return	a	collection	with	all	articles	
articles	=	Article.all	
#	class/object	definition	
class	Article	
		has_many	:authors	
		has_many	:images,		
		has_many	:comments	
		has_many	:related_articles	
end
@papa_fire
ORMs are bad
for high-traffic production
for replacing SQL skills
@papa_fire
“
I have yet to find a tool built to
avoid using SQL that doesn’t
become more complicated to use
than just learning SQL
John Simone (@j_simone)
@papa_fire
ORMs are not bad
for prototyping
for low-traffic systems
for non-public traffic
@papa_fire
PSA
lazy loading doesn’t solve
all your problems
@papa_fire
</database>
@papa_fire
if you can’t optimize the problem
hide the problem
@papa_fire
<caching>
@papa_fire
“
there are only two hard
things in Computer Science:
cache invalidation and
naming things Phil Karlton
@papa_fire
is stale content > slow content?
@papa_fire
stale is relative
@papa_fire
how valuable is 1 minute?
@papa_fire
100 request/sec
served by 2 web servers
1 minute cache (60 seconds)
x
x
11,998 “cheap” reqs/min
2 “expensive” reqs/min
@papa_fire
① browser
② on-disk
③ in-memory
@papa_fire
① browser
② on-disk
③ in-memory
@papa_fire
remote
@papa_fire
cache-control header
@papa_fire
.htaccess
# cache all pages for one month
Header set Cache-Control "max-age=2628000, public"
@papa_fire
.htaccess
# cache static assets for one month
<filesMatch ".(jpg|jpeg|png|gif|js|ico)$">
Header set Cache-Control "max-age=2628000, public"
</filesMatch>
@papa_fire
php
# cache this page for one minute
<? header("Cache-Control: max-age=60"); ?>
@papa_fire
you don’t control browsers
@papa_fire
progressive web applications
(service workers)
https://www.youtube.com/watch?v=3ol3-kvCNeQ
Patrick Meenan, Velocity
@papa_fire
① browser
② on-disk
③ in-memory
@papa_fire
local, persistant
@papa_fire
read content from file
@papa_fire
… external source (API, database)
… processing content again
read content from file
instead of …
@papa_fire
returnContent() {
return generateContent();
}
@papa_fire
returnContent() {
if (has_cache($cache_file, $cache_ttl)) {
return _read_cache($cache_file);
} else {
return _write_cache($cache_file);
}
}
@papa_fire
###### FS caching
sub _read_cache {
my $cache_file = shift;
open (my $fh, '<', $cache_file)
or die "Can't open file doe reading $!";
read $fh, my $cache_content, -s $fh;
close $fh;
return $cache_content;
}
sub _write_cache {
my $cache_file = shift;
my $content = generateContent();
open(my $fh, '>', $cache_file)
or die "Could not open file '$cache_file' $!";
print $fh $content;
close $fh;
return $cache_content;
}
@papa_fire
have to manage your own ttl
@papa_fire
sub has_cache {
my $cache_file = shift;
my $cache_ttl = shift; #in seconds
if (-f $cache_file) {
# in seconds
my $last_updated = (stat($cache_file))[9];
my $now = int (gettimeofday);
my $diff = $now - $last_updated;
return 1 if ($now - $last_updated <= $cache_ttl);
}
return 0;
}
@papa_fire
① browser
② on-disk
③ in-memory
@papa_fire
memcache, redis
@papa_fire
local or distributed
@papa_fire
function returnContent($article_id) {
$memcache = new Memcache;
$cacheAvailable = $memcache->connect(MEMCACHED_HOST, MEMCACHED_PORT);
if ($cacheAvailable) {
$cached_article = $memcache->get(‘article-’.$article_id);
if (!$cached_article) {
$article = getArticle($article_id);
$memcache->set(‘article-‘.$article_id, $article);
return $article;
} else {
return $cached_article;
}
}
}
@papa_fire
function returnContent($article_id) {
$memcache = new Memcache;
$cacheAvailable = $memcache->connect(MEMCACHED_HOST, MEMCACHED_PORT);
if ($cacheAvailable) {
$cached_article = $memcache->get(‘article-’.$article_id);
if (!$cached_article) {
$article = getArticle($article_id);
$memcache->set(‘article-‘.$article_id, $article);
return $article;
} else {
return $cached_article;
}
}
}
$cached_article = $memcache->get(‘article-’.$article_id);
$memcache = new Memcache;
$memcache->set(‘article-‘.$p->[‘article_id’], $article);
if (!$cached_article) {
@papa_fire
returnContent() {
$content = read_cache($cache_key);
if (!$content) {
$content = generateContent();
write_cache($cache_key, $content);
}
return $content;
}
@papa_fire
remember /get/articles/all ?
(multi-nested ORM function)
@papa_fire
METHOD BASE LOAD
20x TRAFFIC
SPIKE
Base call 5.782 s 12.127 s
@papa_fire
METHOD BASE LOAD
20x TRAFFIC
SPIKE
Base call 5.782 s 12.127 s
Base call with memcache 0.867 s 0.922 s
@papa_fire
not just for db results
@papa_fire
$memcache->set($uri, $html);
@papa_fire
doesn’t have to be 100% static
@papa_fire
don’t forget to purge
@papa_fire
careful what you cache
@papa_fire
“pretty” urls
@papa_fire
“pretty” urls
/my/profile
@papa_fire
“ugly” urls
@papa_fire
“ugly” urls
/prodlist.php?SID=a3e9590a-6598-11e7-907b-a6006ad3dba0
@papa_fire
external cache
@papa_fire
reverse HTTP proxy
@papa_fire
Apache Traffic Server, Varnish
@papa_fire
CDN
Akamai, Fastly
@papa_fire
rule-based controls
@papa_fire
use as many or as few
@papa_fire
</caching>
@papa_fire
<queueing>
@papa_fire
remember the part about critical path?
@papa_fire
anything not related
to the immediate outcome
should not be
in the critical path
@papa_fire
router.post('/register', function(req, res){
var user = new User(req.body);
user.save( function(err) {
if (!err) {
user.savePreferences(req.pref);
user.sendWelcomeEmail();
res.render(‘first_time_welcome',
{ title: 'Welcome' + user.name,
errors: [err] });
}
});
});
@papa_fire
router.post('/register', function(req, res){
var user = new User(req.body);
user.save( function(err) {
if (!err) {
user.savePreferences(req.pref);
user.sendWelcomeEmail();
res.render(‘first_time_welcome',
{ title: 'Welcome' + user.name,
errors: [err] });
}
});
});
user.sendWelcomeEmail();
@papa_fire
User.sendWelcomeEmail = function(callback){
if (!do_not_email(user.email) {
var email = new Email();
email.subject = "Welcome " + user.firstname;
email.cta = getDealoftheDay();
email.secondary = getOffers(user);
email.generateBody(user, function() {
email.send();
});
}
};
@papa_fire
does it have to be done now?
@papa_fire
router.post('/register', function(req, res){
var user = new User(req.body);
user.save( function(err) {
if (!err) {
user.savePreferences(req.pref);
sendToQueue(‘welcome email’,user);
res.render(‘first_time_welcome',
{ title: 'Welcome' + user.name,
errors: [err] });
}
});
});
sendToQueue(‘welcome email’,user);
@papa_fire
queueing (v.) - putting things
somewhere else
to deal with later
@papa_fire
where?
1. in-memory (RabbitMQ, SQS)
2. persistant (database)
@papa_fire
</queueing>
@papa_fire
so …
@papa_fire
optimize everything
(right?)
@papa_fire
“premature optimization
is the root of all evil
Donald Knuth
@papa_fire
improvements should be …
1. needed
@papa_fire
improvements should be …
1. needed
2. incremental
@papa_fire
improvements should be …
1. needed
2. incremental
3. measurable
@papa_fire
that said
@papa_fire
always think about
performance
@papa_fire
there is an exception
to every rule
parting tip
@papa_fire
thank you
questions?
1 of 147

Recommended

PHP performance 101: so you need to use a database by
PHP performance 101: so you need to use a databasePHP performance 101: so you need to use a database
PHP performance 101: so you need to use a databaseLeon Fayer
1.7K views41 slides
Database performance 101 by
Database performance 101Database performance 101
Database performance 101Leon Fayer
1.2K views49 slides
Wp query by
Wp queryWp query
Wp querySavita Soni
6.6K views33 slides
Difference between mysql_fetch_array and mysql_fetch_assoc in PHP by
Difference between mysql_fetch_array and mysql_fetch_assoc in PHPDifference between mysql_fetch_array and mysql_fetch_assoc in PHP
Difference between mysql_fetch_array and mysql_fetch_assoc in PHPVineet Kumar Saini
2.3K views4 slides
How else can you write the code in PHP? by
How else can you write the code in PHP?How else can you write the code in PHP?
How else can you write the code in PHP?Maksym Hopei
171 views32 slides
Simple Ways To Be A Better Programmer (OSCON 2007) by
Simple Ways To Be A Better Programmer (OSCON 2007)Simple Ways To Be A Better Programmer (OSCON 2007)
Simple Ways To Be A Better Programmer (OSCON 2007)Michael Schwern
971 views177 slides

More Related Content

What's hot

You don’t know query - WordCamp UK Edinburgh 2012 by
You don’t know query - WordCamp UK Edinburgh 2012You don’t know query - WordCamp UK Edinburgh 2012
You don’t know query - WordCamp UK Edinburgh 2012l3rady
978 views53 slides
WordPress London 16 May 2012 - You don’t know query by
WordPress London 16 May 2012 - You don’t know queryWordPress London 16 May 2012 - You don’t know query
WordPress London 16 May 2012 - You don’t know queryl3rady
1.1K views53 slides
16.mysql stored procedures in laravel by
16.mysql stored procedures in laravel16.mysql stored procedures in laravel
16.mysql stored procedures in laravelRazvan Raducanu, PhD
948 views19 slides
Perl6 grammars by
Perl6 grammarsPerl6 grammars
Perl6 grammarsAndrew Shitov
10.1K views89 slides
Php functions by
Php functionsPhp functions
Php functionsJIGAR MAKHIJA
289 views15 slides

What's hot(20)

You don’t know query - WordCamp UK Edinburgh 2012 by l3rady
You don’t know query - WordCamp UK Edinburgh 2012You don’t know query - WordCamp UK Edinburgh 2012
You don’t know query - WordCamp UK Edinburgh 2012
l3rady978 views
WordPress London 16 May 2012 - You don’t know query by l3rady
WordPress London 16 May 2012 - You don’t know queryWordPress London 16 May 2012 - You don’t know query
WordPress London 16 May 2012 - You don’t know query
l3rady1.1K views
PHPUnit でよりよくテストを書くために by Yuya Takeyama
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
Yuya Takeyama9.7K views
Getting Creative with WordPress Queries by DrewAPicture
Getting Creative with WordPress QueriesGetting Creative with WordPress Queries
Getting Creative with WordPress Queries
DrewAPicture4.8K views
Perl6 Regexen: Reduce the line noise in your code. by Workhorse Computing
Perl6 Regexen: Reduce the line noise in your code.Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
WordCamp Portland 2018: PHP for WordPress by Alena Holligan
WordCamp Portland 2018: PHP for WordPressWordCamp Portland 2018: PHP for WordPress
WordCamp Portland 2018: PHP for WordPress
Alena Holligan278 views
Pim Elshoff "Final Class Aggregate" by Fwdays
Pim Elshoff "Final Class Aggregate"Pim Elshoff "Final Class Aggregate"
Pim Elshoff "Final Class Aggregate"
Fwdays240 views
Writing Maintainable Perl by tinypigdotcom
Writing Maintainable PerlWriting Maintainable Perl
Writing Maintainable Perl
tinypigdotcom1.3K views
DBIx::Class beginners by leo lapworth
DBIx::Class beginnersDBIx::Class beginners
DBIx::Class beginners
leo lapworth26.1K views
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway by ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
ichikaway7.4K views
Getting Creative with WordPress Queries, Again by DrewAPicture
Getting Creative with WordPress Queries, AgainGetting Creative with WordPress Queries, Again
Getting Creative with WordPress Queries, Again
DrewAPicture515 views
Introducing CakeEntity by Basuke Suzuki
Introducing CakeEntityIntroducing CakeEntity
Introducing CakeEntity
Basuke Suzuki1.9K views

Viewers also liked

Web Performance 2017: Myths and Truths (php[world] 2017) by
Web Performance 2017: Myths and Truths (php[world] 2017)Web Performance 2017: Myths and Truths (php[world] 2017)
Web Performance 2017: Myths and Truths (php[world] 2017)Christian Wenz
347 views31 slides
Create a PHP Library the right way by
Create a PHP Library the right wayCreate a PHP Library the right way
Create a PHP Library the right wayChristian Varela
1.4K views177 slides
Inheritance: Vertical or Horizontal by
Inheritance: Vertical or HorizontalInheritance: Vertical or Horizontal
Inheritance: Vertical or HorizontalMark Niebergall
1.6K views95 slides
Essential Tools for Modern PHP by
Essential Tools for Modern PHPEssential Tools for Modern PHP
Essential Tools for Modern PHPAlex Weissman
1.2K views44 slides
Leveraging a distributed architecture to your advantage by
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantageMichelangelo van Dam
1.5K views66 slides
Webpack Encore Symfony Live 2017 San Francisco by
Webpack Encore Symfony Live 2017 San FranciscoWebpack Encore Symfony Live 2017 San Francisco
Webpack Encore Symfony Live 2017 San FranciscoRyan Weaver
2.8K views94 slides

Viewers also liked(9)

Web Performance 2017: Myths and Truths (php[world] 2017) by Christian Wenz
Web Performance 2017: Myths and Truths (php[world] 2017)Web Performance 2017: Myths and Truths (php[world] 2017)
Web Performance 2017: Myths and Truths (php[world] 2017)
Christian Wenz347 views
Create a PHP Library the right way by Christian Varela
Create a PHP Library the right wayCreate a PHP Library the right way
Create a PHP Library the right way
Christian Varela1.4K views
Inheritance: Vertical or Horizontal by Mark Niebergall
Inheritance: Vertical or HorizontalInheritance: Vertical or Horizontal
Inheritance: Vertical or Horizontal
Mark Niebergall1.6K views
Essential Tools for Modern PHP by Alex Weissman
Essential Tools for Modern PHPEssential Tools for Modern PHP
Essential Tools for Modern PHP
Alex Weissman1.2K views
Leveraging a distributed architecture to your advantage by Michelangelo van Dam
Leveraging a distributed architecture to your advantageLeveraging a distributed architecture to your advantage
Leveraging a distributed architecture to your advantage
Webpack Encore Symfony Live 2017 San Francisco by Ryan Weaver
Webpack Encore Symfony Live 2017 San FranciscoWebpack Encore Symfony Live 2017 San Francisco
Webpack Encore Symfony Live 2017 San Francisco
Ryan Weaver2.8K views
A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017 by Carlos Buenosvinos
A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017
A Journey from Hexagonal Architecture to Event Sourcing - SymfonyCon Cluj 2017
Carlos Buenosvinos3.4K views
Advanced MySQL Query Optimizations by Dave Stokes
Advanced MySQL Query OptimizationsAdvanced MySQL Query Optimizations
Advanced MySQL Query Optimizations
Dave Stokes796 views
MySQL 8.0 Preview: What Is Coming? by Gabriela Ferrara
MySQL 8.0 Preview: What Is Coming?MySQL 8.0 Preview: What Is Coming?
MySQL 8.0 Preview: What Is Coming?
Gabriela Ferrara4.8K views

Similar to Developing applications for performance

wget.pl by
wget.plwget.pl
wget.plYasuhiro Onishi
1.2K views23 slides
Drupal Development (Part 2) by
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)Jeff Eaton
2.1K views79 slides
The History of PHPersistence by
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
2.3K views75 slides
Tidy Up Your Code by
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your CodeAbbas Ali
3 views52 slides
mro-every.pdf by
mro-every.pdfmro-every.pdf
mro-every.pdfWorkhorse Computing
7 views69 slides
DBI by
DBIDBI
DBIabrummett
616 views51 slides

Similar to Developing applications for performance(20)

Drupal Development (Part 2) by Jeff Eaton
Drupal Development (Part 2)Drupal Development (Part 2)
Drupal Development (Part 2)
Jeff Eaton2.1K views
The History of PHPersistence by Hugo Hamon
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon2.3K views
Tidy Up Your Code by Abbas Ali
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
Abbas Ali3 views
PHPSpec - the only Design Tool you need - 4Developers by Kacper Gunia
PHPSpec - the only Design Tool you need - 4DevelopersPHPSpec - the only Design Tool you need - 4Developers
PHPSpec - the only Design Tool you need - 4Developers
Kacper Gunia37.3K views
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need by Kacper Gunia
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Kacper Gunia50.4K views
Perl Bag of Tricks - Baltimore Perl mongers by brian d foy
Perl Bag of Tricks  -  Baltimore Perl mongersPerl Bag of Tricks  -  Baltimore Perl mongers
Perl Bag of Tricks - Baltimore Perl mongers
brian d foy2.3K views
Extbase and Beyond by Jochen Rau
Extbase and BeyondExtbase and Beyond
Extbase and Beyond
Jochen Rau4.4K views
Mike King - Storytelling by Numbers MKTFEST 2014 by Marketing Festival
Mike King - Storytelling by Numbers MKTFEST 2014Mike King - Storytelling by Numbers MKTFEST 2014
Mike King - Storytelling by Numbers MKTFEST 2014
Marketing Festival3.9K views
Storytelling By Numbers by Michael King
Storytelling By NumbersStorytelling By Numbers
Storytelling By Numbers
Michael King25.4K views
Advanced php testing in action by Jace Ju
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
Jace Ju2.1K views
Operation Oriented Web Applications / Yokohama pm7 by Masahiro Nagano
Operation Oriented Web Applications / Yokohama pm7Operation Oriented Web Applications / Yokohama pm7
Operation Oriented Web Applications / Yokohama pm7
Masahiro Nagano1.9K views
Internationalizing CakePHP Applications by Pierre MARTIN
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
Pierre MARTIN5.8K views

More from Leon Fayer

What kids can teach us about building effective teams by
What kids can teach us about building effective teamsWhat kids can teach us about building effective teams
What kids can teach us about building effective teamsLeon Fayer
14 views20 slides
Как измерить успех by
Как измерить успехКак измерить успех
Как измерить успехLeon Fayer
391 views109 slides
Bias in tech by
Bias in techBias in tech
Bias in techLeon Fayer
858 views20 slides
Building the right architecture for you by
Building the right architecture for youBuilding the right architecture for you
Building the right architecture for youLeon Fayer
2.1K views20 slides
Lost art of troubleshooting by
Lost art of troubleshootingLost art of troubleshooting
Lost art of troubleshootingLeon Fayer
2.2K views78 slides
Adventures in public speaking by
Adventures in public speakingAdventures in public speaking
Adventures in public speakingLeon Fayer
2.4K views20 slides

More from Leon Fayer(12)

What kids can teach us about building effective teams by Leon Fayer
What kids can teach us about building effective teamsWhat kids can teach us about building effective teams
What kids can teach us about building effective teams
Leon Fayer14 views
Как измерить успех by Leon Fayer
Как измерить успехКак измерить успех
Как измерить успех
Leon Fayer391 views
Bias in tech by Leon Fayer
Bias in techBias in tech
Bias in tech
Leon Fayer858 views
Building the right architecture for you by Leon Fayer
Building the right architecture for youBuilding the right architecture for you
Building the right architecture for you
Leon Fayer2.1K views
Lost art of troubleshooting by Leon Fayer
Lost art of troubleshootingLost art of troubleshooting
Lost art of troubleshooting
Leon Fayer2.2K views
Adventures in public speaking by Leon Fayer
Adventures in public speakingAdventures in public speaking
Adventures in public speaking
Leon Fayer2.4K views
BizOps and you by Leon Fayer
BizOps and youBizOps and you
BizOps and you
Leon Fayer5.7K views
On call for developers by Leon Fayer
On call for developersOn call for developers
On call for developers
Leon Fayer2.3K views
Production testing through monitoring by Leon Fayer
Production testing through monitoringProduction testing through monitoring
Production testing through monitoring
Leon Fayer7K views
What DevOps is Not by Leon Fayer
What DevOps is NotWhat DevOps is Not
What DevOps is Not
Leon Fayer2.7K views
Breaking social dependency by Leon Fayer
Breaking social dependencyBreaking social dependency
Breaking social dependency
Leon Fayer826 views
Improving DevOps through better monitoring by Leon Fayer
Improving DevOps through better monitoringImproving DevOps through better monitoring
Improving DevOps through better monitoring
Leon Fayer3K views

Recently uploaded

DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ... by
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...Deltares
11 views32 slides
SAP FOR TYRE INDUSTRY.pdf by
SAP FOR TYRE INDUSTRY.pdfSAP FOR TYRE INDUSTRY.pdf
SAP FOR TYRE INDUSTRY.pdfVirendra Rai, PMP
24 views3 slides
Copilot Prompting Toolkit_All Resources.pdf by
Copilot Prompting Toolkit_All Resources.pdfCopilot Prompting Toolkit_All Resources.pdf
Copilot Prompting Toolkit_All Resources.pdfRiccardo Zamana
8 views4 slides
.NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra... by
.NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra....NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra...
.NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra...Marc Müller
38 views62 slides
Sprint 226 by
Sprint 226Sprint 226
Sprint 226ManageIQ
5 views18 slides
FIMA 2023 Neo4j & FS - Entity Resolution.pptx by
FIMA 2023 Neo4j & FS - Entity Resolution.pptxFIMA 2023 Neo4j & FS - Entity Resolution.pptx
FIMA 2023 Neo4j & FS - Entity Resolution.pptxNeo4j
7 views26 slides

Recently uploaded(20)

DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ... by Deltares
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
DSD-INT 2023 Wave-Current Interaction at Montrose Tidal Inlet System and Its ...
Deltares11 views
Copilot Prompting Toolkit_All Resources.pdf by Riccardo Zamana
Copilot Prompting Toolkit_All Resources.pdfCopilot Prompting Toolkit_All Resources.pdf
Copilot Prompting Toolkit_All Resources.pdf
Riccardo Zamana8 views
.NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra... by Marc Müller
.NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra....NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra...
.NET Developer Conference 2023 - .NET Microservices mit Dapr – zu viel Abstra...
Marc Müller38 views
Sprint 226 by ManageIQ
Sprint 226Sprint 226
Sprint 226
ManageIQ5 views
FIMA 2023 Neo4j & FS - Entity Resolution.pptx by Neo4j
FIMA 2023 Neo4j & FS - Entity Resolution.pptxFIMA 2023 Neo4j & FS - Entity Resolution.pptx
FIMA 2023 Neo4j & FS - Entity Resolution.pptx
Neo4j7 views
Dapr Unleashed: Accelerating Microservice Development by Miroslav Janeski
Dapr Unleashed: Accelerating Microservice DevelopmentDapr Unleashed: Accelerating Microservice Development
Dapr Unleashed: Accelerating Microservice Development
Miroslav Janeski10 views
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium... by Lisi Hocke
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Team Transformation Tactics for Holistic Testing and Quality (Japan Symposium...
Lisi Hocke30 views
SUGCON ANZ Presentation V2.1 Final.pptx by Jack Spektor
SUGCON ANZ Presentation V2.1 Final.pptxSUGCON ANZ Presentation V2.1 Final.pptx
SUGCON ANZ Presentation V2.1 Final.pptx
Jack Spektor22 views
DSD-INT 2023 Leveraging the results of a 3D hydrodynamic model to improve the... by Deltares
DSD-INT 2023 Leveraging the results of a 3D hydrodynamic model to improve the...DSD-INT 2023 Leveraging the results of a 3D hydrodynamic model to improve the...
DSD-INT 2023 Leveraging the results of a 3D hydrodynamic model to improve the...
Deltares6 views
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko... by Deltares
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...
DSD-INT 2023 Simulation of Coastal Hydrodynamics and Water Quality in Hong Ko...
Deltares14 views
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with... by sparkfabrik
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...
20231129 - Platform @ localhost 2023 - Application-driven infrastructure with...
sparkfabrik5 views
DSD-INT 2023 Exploring flash flood hazard reduction in arid regions using a h... by Deltares
DSD-INT 2023 Exploring flash flood hazard reduction in arid regions using a h...DSD-INT 2023 Exploring flash flood hazard reduction in arid regions using a h...
DSD-INT 2023 Exploring flash flood hazard reduction in arid regions using a h...
Deltares5 views
DSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - Geertsema by Deltares
DSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - GeertsemaDSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - Geertsema
DSD-INT 2023 Delft3D FM Suite 2024.01 1D2D - Beta testing programme - Geertsema
Deltares17 views
Quality Engineer: A Day in the Life by John Valentino
Quality Engineer: A Day in the LifeQuality Engineer: A Day in the Life
Quality Engineer: A Day in the Life
John Valentino6 views
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J... by Deltares
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...
DSD-INT 2023 3D hydrodynamic modelling of microplastic transport in lakes - J...
Deltares9 views
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -... by Deltares
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...
DSD-INT 2023 Simulating a falling apron in Delft3D 4 - Engineering Practice -...
Deltares6 views

Developing applications for performance