Improving Performance Perception with Pingdom and GTmetrix

存储架构 2018-06-23 阅读原文

This article is part of a series on building a sample application — a multi-image gallery blog — for performance benchmarking and optimizations. (View the repo here.)

In this article, we’ll analyze ourgallery application using the tools weexplained in the previous guide, and we’ll look at possible ways to further improve its performance.

As perthe previous post, please set up Ngrok and pipe to the locally hosted app through it, or host the app on a demo server of your own. This static URL will enable us to test our app with external tools like GTmetrix and Pingdom Tools.

We went and scanned our website with GTmetrix to see how we can improve it. We see that results, albeit not catastrophically bad, still have room for improvement.

The first tab — PageSpeed — contains a list of recommendations by Google . The first item under the PageSpeed tab — a warning about a consistent URL — pertains to our application outputting the images randomly, so that is an item we will skip. The next thing we can do something about is browser caching.

Browser Caching

We see that there is a main.css file that needs its Expires headers set, and the images in the gallery need the same thing. Now, the first idea for these static files would be to set this in our Nginx configuration:

location ~* .(?:ico|css|js|gif|jpe?g|png)$ {
    expires 14d;

We can simply put this inside our server block and leave it to Nginx, right?

Well, not really. This will take care of our static files, like CSS, but the /raw images we are being warned about aren’t really that static. So this snippet in our Nginx configuration won’t exactly fix this issue so easily. For our images, we have an actual controller that creates these on the fly, so it would be ideal if we could set our response headers right there, in the controller. For some reason, these weren’t being set properly byGlide.

Maybe we could set our Nginx directive in a way to include the raw resources, but we felt the controller approach to be more future-proof. This is because we aren’t sure what other content may end up with an raw suffix eventually — maybe some videos, or even audio files.

So, we opened /src/ImageController.php in our image gallery app, and dropped these two lines inside of our serveImageAction() , just before the line return $response :

// cache for 2 weeks
// (optional) set a custom Cache-Control directive
$response->headers->addCacheControlDirective('must-revalidate', true);

This will modify our dynamic image responses by adding the proper Cache Control and Expires headers.

Symfony has more comprehensive options for the caching of responses, as documented here .

Having restarted Nginx, we re-tested our app in GTmetrix, and lo and behold:


Next, GTmetrix gave us a warning about the size and compression of our resources:

In production, this is an insignificant thing, and improving on this wouldn’t make much of a difference in this particular case, with just a couple of kilobytes to spare. But, as these guides are here to show the way with other, more substantial applications, we’ll cover this improvement as well.

Images could be optimized in advance, but as these are dynamic images created with Glide , which we covered inanother article, we won’t be doing that. In fact, Glide provides ways to set image quality. But sometimes we won’t be using Glide to handle our images, so we’ll first try another approach here.

Inside of our Nginx server block, we’ll add a couple of lines that instruct Nginx to compress our content:

gzip on;
gzip_disable "msie6";

gzip_vary on;
gzip_proxied any;
gzip_comp_level 9;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/jpeg;

An explanation of each of these settings would be out of the scope of this article. Each of these items is explained on the Nginx website , but one thing worth discussing is gzip_comp_level .

With compression, the common wisdom is that there’s a tradeoff. We gain some on network bandwidth, by making our files smaller, but then we lose some in our server CPU cycles required to gzip our resources on and on, on every request. Or as this Cloudflare blog post (which we’ll come back to later on) says:

There is a tradeoff between compression speed and transfer speed. It is only beneficial to increase your compression ratio if you can reduce the number of bytes you have to transfer faster than you would actually transfer them.

This is why people rarely set gzip_comp_level to the maximum 9, like we did. They usually settle for something like 6. This way, visitors still get compressed resources, but the CPU still isn’t being put under a big strain, especially during traffic spikes.

But we won’t follow this common advice for two reasons: first, in production, odds are we would be deploying our application on aCDN, which would remove the burden from our server altogether, and second, even if we don’t use a CDN, we will use page caching, so this gzipping done by our server will — hopefully — be done just once per resource. And, with our browser caching fully on, even these cached gzipped resources won’t be requested so often.

So, this is the rationale to set our gzip_comp_level to 9, but in case we don’t intend to use page/HTTP caching, we would probably set this to a smaller number.

By doing this, we were able to improve our gzip result:

We weren’t able to achieve the same improvement with our images, though. So, we went back to the Glide documentation and found how to control the quality of our images: inside our serveImageAction() inside our ImageController , we found the line:

$cachePath = $glide->getGlide()->makeImage($file, ['w' => $size]);

We added a quality argument to the makeImage() second array argument:

$cachePath = $glide->getGlide()->makeImage($file, ['w' => $size, 'q' => 60]);

We didn’t want to set the image quality lower than that, because it wouldn’t look good:

Then we deleted all the images in our /var/uploads/cache folder, and retested. Our results on GTmetrix showed we were able to improve by 5%:

There’s still room for improvement, but in 99% cases, the steps we took to improve our images will be enough.

We also went to Pingdom Tools to check our website — and we were surprised to see that we got a 100% score. Although the page load time was still not what it should be, this was a significant improvement from the 92% score we got earlier:

These recommendations are a useful guideline, but our 100% score would be a mere vanity metric if our load time were to remain at 4.21 seconds, so we turned on Nginx caching we wrote about in Server-side Optimization with Nginx and pm-static . With caching enabled, our result was now 100% across all metrics, and our load time below 1 second:

We are attaching a HAR file of this test .


Although we achieved 100 out of 100 with Pingdom Tools, there are metrics which are not 100% satisfied both on YSlow and PageSpeed (GTmetrix). However, these things are out of our hands — like the minification of resources (jQuery and Bootstrap) served by other CDNs. We could download and minify them, but it’s questionable how useful this would be considering most people already have them downloaded in their browser due to the resources’ widespread adoption.

There are things we didn’t cover in this article which would be recommended in production — or at least worth exploring — like Brotli compression. The people over at Cloudflare have written an interesting blog post about their results with this compression algorithm. As with all other things, before actual implementation it would be necessary to test it thoroughly on different kinds of resources and visitors’ connections. In our opinion, with HTTP caching enabled, even the CPU compression cost possibly incurred by high a compression ratio would still pay off, because it’s a one-time cost.

Nginx’s module for Brotli compression can be found here . This topic is further explored in this article .

If you know of any other improvements that could significantly impact performance, let us know!

Meet the author

Tonino Jankov

Tonino is a web developer and IT consultant who's dived through open-source code for over a decade. He's also a crypto enthusiast, Linux fan, and moderate libertarian.




nginx支持在线播放mp4 nginx支持在线播放mp41.安装nginx时加参数 –prefix=/opt/nginx –with-http_gzip_static_module –with-http_flv_module –with-http_mp4_module 2.匹配处理 loca...
Nginx实战系列之功能篇—-后端节点健康检查... 公司前一段对业务线上的nginx做了整理,重点就是对nginx上负载均衡器的后端节点做健康检查。目前,nginx对后端节点健康检查的方式主要有3种,这里列出: 1、ngx_http_proxy_module 模块和ngx_http_upstream_module模块(自带)官网地址:...
nginx日志中$request_body 十六进制字符(x22x9Bx5Cx09x08…... 在使用nginx记录访问日志时,发现在含有 request_body 的 PUT , POST 请求时,日志中会含有 x22 x9B x5C x09 x08 字符,不利于阅读和处理。 具体 支持 request_body...
LVS负载均衡+动静分离+高可用(nginx+tomcat+keepalived)... 一、环境介绍 基于LVS(linux virtual server)linux虚拟服务器的http集群搭建 环境:使用VMware pro10,CentOS6.5 一共使用4台虚拟机,两台安装Ngnix,两台安装tomcat。 这四台服务器的作用分别是:其中一台nginx作为主服务器...
Nginx 教程(2):性能 大家好,分享即关爱,我们很乐意和你分享一些新的知识,我们准备了一个 Nginx 的教程,分为三个系列,如果你对 Nginx 有所耳闻,或者想增进 Nginx 方面的经验和理解,那么恭喜你来对地方了。 我们会告诉你 Nginx 如何工作及其背后的理念,还有如何优化以加快应用的性能,如何安...