Why BootDev — Controlling Cache headers

From AWS document, when u want to cache objects at browser, From S3 or from Cloudfront, at the same time support CORs resources like font, You can use a parameter MaxAgeSeconds: http://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html

With all the tests i tried Chrome don’t really respect MaxAgeSeconds , you still need traditional Cache-Control: Max-age=xxx AND Expires: into header. When using AWS Cloudfront as your edge cache / CDN, and especially adding S3 as your origin, you take special care of your cache headers.

You can use API / CLI / UI to change the cache header at the metadata session of S3.

Screen Shot 2015-07-10 at 3.41.24 PM

And at your bucket policy’s permission, set CORs

Screen Shot 2015-07-10 at 3.43.35 PM

Once you success in setting up those things, you can curl -I -H to test your settings. If you use Chrome to test, REMEMBER

  1. DONT click refresh
  2. DONT click CMD +R
  3. Click another link in your website to test 

Otherwise, you will end up in lots of confusion !

run command:

curl -I http://xxxxxx.example.com/fonts/Neutra2Display-Titling.woff -H “Origin: xxxx.example.com”

Screen Shot 2015-07-10 at 3.47.35 PMScreen Shot 2015-07-10 at 3.47.59 PM

first time u will see “Miss From Cloudfront”, if it is your production site url, you may ask why ? You should have many people visiting this obejcy. As the header is different than normal browser, Cloudfront treat it as a new object. So, no worry.

At the second time you curl, you will see “HIT from cloudfront”. So with this setup your resource (this time is font), will be cached on Cloudfront a long time and then once downloaded to browser, it will locally cached as the Cache-control: max-age set.

P.S. Cloudfront respect Cache-Control, so how long your browser will cache = how long your object will stay on Cloudfront.

With MaxAgeSeconds only, your resource can keep at browser with 304.

With Cache-control and expires header, your resource can keep at 200, from cache.

Question: So what does MaxAgeSeconds do here ? Any special require that we always want 304 but not 200, from cache ? I need someone to answer me as well 🙂

Why Bootdev — Dynamic CDN

In the old days, we put images, css / js, woff etc any assets to CDN, so that clients can download somewhere that geographically optimised.

Around end of 2012 – early 2013, new idea comes out like we should CDN everything, so that we can reduce the complex architecture with memcache, page cache cluster (Varnish) or even microccache etc. Just 1 layer cache and having everything to CDN. Like architecture below.

dnamic cdn

Your website domain name will directly point to CDN with CNAME. And then the CDN will point to your load balancer address or your web server. So it is like a proxy. When you do create, it will 100% bypass CDN and goes to web server, when u do UPDATE, the CDN will update from web server then invalidate itself, when you do DELETE, the CDN will bypass request to web server and invalidate its cache. When you read, it read from the CDN, not from web server. So the CRUD action can be completed.

You will need your own cache invalidation strategy, like send update to cloudfront / using versioning object or url.

Here is a sample conf of how we bypass some URLs to go to web server, and making Drupal works.

E1EB6A9C-17EC-446D-AD59-80B471A4F962 62367506-DDC3-4E5C-8F05-24E2D20DBBBB

With AWS cloudfront, you can bypass header ORIGIN, so that you can preform CORs actions. Also you can use similar header bypass feature to detect mobile/PC. With such architecture well setup, theoretically, you can have unlimited PV, as your server wont be really hitted. Your bound will be write DB bound only, which is not a concern in most case.

If you don’t want to understand all these, but want to lower your cost and have higher traffic and faster response, contact bootdev at founders@bootdev.com ! We can deploy Dynamic CDN to you in minutes no matter you are using AWS or not. We can point our CloudFront account to your server, it can be Azure, Linode, or any bare-meter. It just need to be Drupal, and you can enjoy the best performance ever.

ref: https://media.amazonwebservices.com/blog/cloudfront_dynamic_web_sites_full_1.jpg

Why bootdev — Nginx conf extended

Recently, one of our Drupal stack really high CPU, It do monthly increased 30% RPM (request per minute) from new relic. BTW, i think its CPU wont increase like 40%. During my investigation,

  1. some robots scan can somehow eat your CPU. Like many robots will look for wp-login as it guess you are wordpress site and more.
  2. Your CDN may pull your data but goes to a wrong URL and have a ERROR in your php-fpm log
  3. robot from same IP address(es) keep scan your site

We here added some conf which help about 6-7% CPU decrease for a 300-400 RPM Drupal site.

#Set a limit connection zone
limit_conn_zone $binary_remote_addr zone=gulag:5m;

#Check robot
map $http_user_agent $is_bot {
default  ”;
~*crawl|goog|yahoo|yandex|spider|bot|tracker|click|parser is_bot;
}
###
### Send all known bots to $args free URLs.
###
location @nobots {
if ($is_bot) {
rewrite ^ $scheme://$host$uri? permanent;
}
rewrite ^/(.*)$  /index.php?q=$1 last;
}

#In CDN Config and Advagg conf of Drupal nginx,
#add below to restrict same IP only allow 32 connections
limit_conn gulag 32;
#Block connection if it is robots (Put anywhere u like)
try_files  $uri @nobots;

#Block wordpress scan attack
location ~ ^/(wp-admin|wp-login\.php) {
deny all;
}

The block wordpress scan thing can add anything that u find strange from php-fpm/error.log by just changing the path pattern

I have load balancer setup with 2 web server, one with and one without config above. The different on Amazon m3.large is about 6% in a 300-400RPM website, in which both server throughput the same RPM.

Of coz, the above settings is updated into BootDev Nginx conf.

Enjoy 🙂

Why bootdev — Caching (2)

Last time we talked about the 3 level of cache in Drupal + AWS.

This time we go down to more details of APC (Alternative PHP Cache). There are kinds of code level cache (OPcache) for php. Most common are OPCache (default PHP5.5), Xcache, APC. Mostly Drupal sites use APC.

There is also a Drupal APC module , in most case, that is not necessary to be installed. Unless you want to share some Drupal Cache table into APC. For bootdev, we don’t do this. Cache tables should be in a standalone cache instead of the web server, so that, while scale up servers, metadata can share across servers. So your system is ready for horizontal scaling.

You can simply install APC with pecl, the package manager of PHP

pecl install apc

Here I share the APC configure for EC2 m3.large machine which is 7.5GB memory

; configuration for php apc module
extension=apc.so
apc.enabled=1
apc.shm_segments=1
apc.shm_size="256M"
;Relative to the number of cached files (you may need to watch your stats for a day or two to find out a good number)
apc.num_files_hint=7000

;Relative to the size of site
apc.user_entries_hint=4096

;The number of seconds a cache entry is allowed to idle in a slot before APC dumps the cache
apc.ttl=7200
apc.user_ttl=7200
apc.gc_ttl=3600

;Setting this to 0 will give you the best performance, as APC will
;not have to check the IO for changes. However, you must clear 
;the APC cache to recompile already cached files. If you are still
;developing, updating your site daily in WP-ADMIN, and running W3TC
;set this to 1
apc.stat=0

;This MUST be 0, WP can have errors otherwise! Drupal can set to 1
apc.include_once_override=1

;Only set to 1 while debugging
apc.enable_cli=1

;Allow 2 seconds after a file is created before it is cached to prevent users from seeing half-written/weird pages
apc.file_update_protection=2

;Leave at 2M or lower. Site does't have any file sizes close to 2M
apc.max_file_size=2M

apc.cache_by_default=1
apc.use_request_time=1
apc.slam_defense=0
apc.mmap_file_mask=/tmp/php_apc.XXXXXX
apc.stat_ctime=0
apc.canonicalize=1
apc.write_lock=1
apc.report_autofilter=0
apc.rfc1867=0
apc.rfc1867_prefix =upload_
apc.rfc1867_name=APC_UPLOAD_PROGRESS
apc.rfc1867_freq=0
apc.rfc1867_ttl=3600
apc.lazy_classes=0
apc.lazy_functions=0

You can have apc.php inside somewhere of /usr/share/php-apc depends on which server you are using.

Copy this file to your web root and access it, you can see the performance after tunning.

Screen Shot 2014-12-26 at 11.31.32 AM