Nginx Cache方面的设置

这里 Cache 有两种情况说明,一种是浏览器访问Nginx,浏览器会Cache;一种是Nginx 访问后端,Nginx 自己Cache 。

 

第一种情况

来个例子:

$ curl -I http://su.bdimg.com/static/superplus/css/super_min_2b5190eb.css
HTTP/1.1 200 OK
Server: JSP3/2.0.4
Date: Fri, 31 Oct 2014 07:28:20 GMT
Content-Type: text/css
Content-Length: 25076
Connection: keep-alive
ETag: “1121644245”
Last-Modified: Wed, 24 Sep 2014 15:50:22 GMT
Expires: Mon, 23 Mar 2015 16:29:25 GMT
Age: 3164335
Cache-Control: max-age=15552000
Accept-Ranges: bytes
Vary: Accept-Encoding

先多句嘴说说Date 和 Age 的意思,Date 的意思是服务器发送消息的时间; Age 的意思有点复杂,它的存在暗示你访问的服务器不是源服务器,而是一台缓存服务器,Age 的大小表示这个资源已经”存活了”多长时间,所以这个值不会大于 源服务器设置的最大缓存时间。

这里Expires 表示过期时间,Cache-Control 表示最大的存活时间,在服务器端的Nginx 我们可以用 expires 指令来定义这两项。

比如:
expire -1;
expire 0;
expire 1h;
expire max;
expire off;

这个指令表示在HTTP响应头中是否增加或修改Expires 和 Cache-Control ,仅当响应状态是200, 201, 204, 206, 301, 302, 303, 304, 或者 307的时候有效。

当expire 为负时,会在响应头增加Cache-Control: no-cache;

当为正或者0时,就表示Cache-Control: max-age=指定的时间(秒);

当为max时,会把Expires设置为 “Thu, 31 Dec 2037 23:55:55 GMT”, Cache-Control 设置到 10 年;

当为off时,表示不增加或修改Expires 和 Cache-Control 。

 

另外,浏览器可以通过两种方式来判断缓存文件是否被更新了,一种是 If-Modified-Since ,浏览器通过发送If-Modified-Since 头,带上「上一次请求获得的修改时间,(在Last-Modified头里)」发送到服务器,服务器会判断这个时间之后文件有没有改变,如果没有改变返回状态值304,如果有返回新文件,状态值200 。

还有一种是利用Etag(Entity Tag),它是实体内容的hash字符串(md5或者SHA1的算法计算出来的),这个方法更准确但是更消耗服务器的CPU,浏览器发送If-None-Match 头,里面是Etag值(浏览器之前请求文件时,服务器会返回Etag 头),服务器收到后做比较,如果一样就返回304,不一样也发送最新文件,返回值200。

 

第二种情况

 一般先在http 里面定义一个缓存路径:

[text]
proxy_buffering on;
proxy_cache_path $cache_path/m_wdjcdn_com levels=1:2 keys_zone=m_wdjcdn_com:512m inactive=20d max_size=300G;

[/text]

然后在server 的 location 里来使用缓存,比如:

[text]

proxy_cache m_wdjcdn_com;
proxy_cache_key "$scheme$host$request_uri";
proxy_cache_valid 200 301 302 20m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout invalid_header updating;
proxy_cache_min_uses 1;
proxy_cache_revalidate on;
[/text]

要注意,proxy_cache在proxy_buffering 开启之后才有效,否则不会缓存

proxy_cache_path 的levels 定义目录层次结构;inactive 表示数据没被访问多长时间后从缓存中删除;缓存大小超过max_size之后使用LRU算法删除数据。

proxy_cache 定义使用哪个zone;
proxy_cache_key 定义缓存key;
proxy_cache_valid 不同状态码缓存不同时间;
proxy_cache_use_stale 定义后端服务器在何种情况下Nginx 返回过期的缓存;
proxy_cache_min_uses 请求多少次之后才会被缓存;
proxy_cache_revalidate 表示资源过期后是否使用If-Modified-Since 和If-None-Match来确认资源是否改变。

另外,还有一个指令 proxy_cache_purge,它用于清除缓存,比如下面的配置:

[text]location ~ /purge(/.*) {
proxy_cache_purge m_wdjcdn_com ""$scheme$host$1";
}[/text]

如果访问/purge/nosa.png,就把nosa.png的缓存清除了,这个功能可用于刷新缓存。

 

最后再看下关于 proxy_cache_use_stale 的官方解释:

This directive tells Nginx when to serve a stale item from the proxy cache. The parameters for this directive are similar to proxy_next_upstream with the addition of ‘updating’.

To prevent cache stampedes (when multiple threads stampede in to try to update the cache simultaneously) you can specify the ‘updating‘ parameter. This will cause one thread to update the cache and while the update is in progress all other threads will serve the stale version of what is in the cache.

 

 

http vary 头的作用

[c]

Vary  = "Vary" ":" ( "*" | 1#field-name )  

[/c]

 

它的意义就是 告诉 「缓存服务器」按照 Vary 指定的 头的内容,分别缓存不同的版本。

比如,Vary: Accept-Encoding,那么「缓存服务器」就会根据 Accept-Encoding 头值的不同缓存不能的版本(实现是把 Accept-Encoding 的值 也作为 「参数」计算hash),比如同一个文件可能有gzip压缩的,有compress压缩的,还有没压缩的。

还有经常遇到的 Vary: User-Agent 和 Vary: Cookie  等等,他们的本质都是提供了 根据不同的 Accept-Encoding、不同的User-Agent 和 不同的Cookie 等等 来返回不同的资源的功能。

 

事实上,客户端如果直接访问源服务器,Vary 就没意义了。

 

为什么叫应用基础平台

为什么我要建立这个分类?为什么不叫IAAS 或者PAAS,也为什么不叫做Docker 或者 Cloud foundry ?

因为我没想好怎么做,我知道现在运维最大的问题就是APP,如何管理APP是问题所在,这关系着开发和运维的合作方式,开发很痛苦,运维也很痛苦,我想改变这一点。

那么现在存在的工具,比如虚拟化,比如Docker ,比如其他的东西,他们每个都解决了什么问题?符合我的需求么?他们自己有什么问题?这些都是我思考的问题,我会一直思考的。

所以我把它叫做应用基础平台,我会把我的思考、思路、工具 和 方式 都写在这个分类里面,它代表着我对运维的思考,而不仅仅是某项技术。

所以我想对自己说:祝好。

 

Nginx 关于mime type 、gzip 的配置解释

1. 关于mime type

HTTP request里面有一个头叫 Accept,列出浏览器可以接受的mime type,HTTP response 的Content-Type 的值 在Accept 里面。我的理解是Nginx 会根据请求的文件的扩展名来决定返回什么 Content-Type,除非后端Web程序手动设置了Content-Type,如果Web程序没设置,Nginx也没找到对应文件的扩展名的话,就使用默认的Type,这个在Nginx 里用 default_type定义,比如 default_type  application/octet-stream;

mime type 和 文件扩展名的对应关系一般放在 mime.types 里,然后 用 include       mime.types; 加载,mime.types 文件里其实就是用 types 指令来定义的,比如下面是一个完整的定义:

types {

# Audio
audio/midi mid midi kar;
audio/mp4 aac f4a f4b m4a;
audio/mpeg mp3;
audio/ogg oga ogg opus;
audio/x-realaudio ra;
audio/x-wav wav;

# Images
image/bmp bmp;
image/gif gif;
image/jpeg jpeg jpg;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico cur;
image/x-jng jng;

# JavaScript
application/javascript js;
application/json json;

# Manifest files
application/x-web-app-manifest+json webapp;
text/cache-manifest manifest appcache;

# Microsoft Office
application/msword doc;
application/vnd.ms-excel xls;
application/vnd.ms-powerpoint ppt;
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;

# Video
video/3gpp 3gpp 3gp;
video/mp4 mp4 m4v f4v f4p;
video/mpeg mpeg mpg;
video/ogg ogv;
video/quicktime mov;
video/webm webm;
video/x-flv flv;
video/x-mng mng;
video/x-ms-asf asx asf;
video/x-ms-wmv wmv;
video/x-msvideo avi;

# Web feeds
application/xml atom rdf rss xml;

# Web fonts
application/font-woff woff;
application/font-woff2 woff2;
application/vnd.ms-fontobject eot;
application/x-font-ttf ttc ttf;
font/opentype otf;

# Other
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/pdf pdf;
application/postscript ps eps ai;
application/rtf rtf;
application/vnd.wap.wmlc wmlc;
application/xhtml+xml xhtml;
application/vnd.google-earth.kml+xml kml;
application/vnd.google-earth.kmz kmz;
application/x-7z-compressed 7z;
application/x-chrome-extension crx;
application/x-opera-extension oex;
application/x-xpinstall xpi;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-bittorrent torrent;
application/zip zip;

application/octet-stream bin exe dll;
application/octet-stream deb;
application/octet-stream dmg;
application/octet-stream iso img;
application/octet-stream msi msp msm;
application/octet-stream safariextz;

text/css css;
text/html html htm shtml;
text/mathml mml;
text/plain txt;
text/vnd.sun.j2me.app-descriptor jad;
text/vnd.wap.wml wml;
text/vtt vtt;
text/x-component htc;
text/x-vcard vcf;

}

 

那么一般在Nginx 里面这么配置即可:

# Define the MIME types for files.
include mime.types;
default_type application/octet-stream;

# Update charset_types due to updated mime.types
charset_types text/xml text/plain text/vnd.wap.wml application/x-javascript application/rss+xml text/css application/javascript application/json;

 

2. 关于gzip

# Compression

# Enable Gzip compressed.
gzip on;

# Setup gzip http version 1.0 
gzip_http_version 1.0;

# Disable gzip compression for IE6, because IE6 supports gzip not friendly.
gzip_disable “MSIE [1-6].”;

# Compression level (1-9).
# 5 is a perfect compromise between size and cpu usage, offering about
# 75% reduction for most ascii files (almost identical to level 9).
gzip_comp_level 5;

# Don’t compress anything that’s already small and unlikely to shrink much
# if at all (the default is 20 bytes, which is bad as that usually leads to
# larger files after gzipping).
gzip_min_length 256;

# Compress data even for clients that are connecting to us via proxies,
# identified by the “Via” header (required for CloudFront).
gzip_proxied any;

# Tell proxies to cache both the gzipped and regular version of a resource
# whenever the client’s Accept-Encoding capabilities header varies;
# Avoids the issue where a non-gzip capable client (which is extremely rare
# today) would display gibberish if their proxy gave them the gzipped version.
gzip_vary on;

# Compress all output labeled with one of the following MIME-types.
gzip_types
application/atom+xml
application/javascript
application/json
application/rss+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
text/css
text/plain
text/x-component;
# text/html is always compressed by HttpGzipModule

# This should be turned on if you are going to have pre-compressed copies (.gz) of
# static files available. If not it should be left off as it will cause extra I/O
# for the check. It is best if you enable this in a location{} block for
# a specific directory, or on an individual server{} level.
# gzip_static on;

注意几点:

1) gzip_http_version 默认是1.1,对于 1.0 的请求就不会压缩 (我们设置成1.0,表示HTTP1.0以上的版本都启动gzip)。

如果我们使用了proxy_pass 进行反向代理,那么 nginx 和后端的 upstream server 之间默认是用HTTP/1.0协议通信的。

The ngx_http_proxy_module  makes it possible to transfer requests to another server.
It is an HTTP/1.0 proxy without the ability for keep-alive requests yet. (As a result, backend connections are created and destroyed on every request.) Nginx talks HTTP/1.1 to the browser and HTTP/1.0 to the backend server. As such it handles keep-alive to the browser.

此时如果 Nginx 连接后端,后端 也是1.1的话,Nginx 和 后端 之间就不会启用gzip了。

多说一句,在upstream 里,连接backend 如果想使用HTTP1.1,使用 proxy_http_version 指令(ngx_http_proxy_module 模块的指令;设置为1.1),一般配合 keepalive 指令使用来实现长连接(还要把header Connection  清空)。

2) IE6的某些版本对gzip的压缩支持很不好,会造成页面的假死,所以关闭IE6的gzip 。

3) gzip_types 定义哪些mime type 被gzip,mime type需要在types 指令当中被定义才可。

4) gzip_vary 指令的意义:

Enables or disables inserting the “Vary: Accept-Encoding” response header field if the directives gzip, gzip_static, or gunzip are active.

假设CDN/缓存 向Nginx 请求资源,Nginx 在响应头里插入“Vary: Accept-Encoding” , CDN/缓存会把  Accept-Encoding 的值 作为 传入参数 来做hash 计算,这样 Accept-Encoding 不一样,就代表 「资源」是不一样的(即使文件是一样的)。它的好处是可以根据客户端请求的 Accept-Encoding 来返回不一样的资源,包括是不是压缩 和 各种压缩格式。如果没有“Vary: Accept-Encoding”,CDN/缓存 可能给客户端错误的资源,比如客户端不支持压缩,却收到gzip压缩的资源,客户端就解析不了了。

 

 

这里多说两个指令:

sendfile on;
tcp_nopush on;

这两个用于优化文件传输,sendfile on 表示 通过文件描述符直接拷贝,而不是用read()/write();tcp_nopush on 这个选项只有在sendfile on的情况下才有效,tcp_nopush = on 会设置调用tcp_cork方法,意思是数据包不会马上传送出去,等到数据包最大或时,一次性的传输出去(说法可能不准)。

http://wiki.nginx.org/ReadMoreAboutTcpNopush

http://blog.csdn.net/hairetz/article/details/6549306

http://www.pagefault.info/?p=228

 

 

 

参考

nginx.conf 配置参考:

https://github.com/h5bp/server-configs-nginx/blob/master/nginx.conf

mime.types 参考:

https://github.com/h5bp/server-configs-nginx/blob/master/mime.types

 

 

构建机房运维基础架构(十三): 搭建NTP服务

安装:

yum -y install ntp ntpdate

配置文件:

<pre># ntp.conf: Managed by puppet.
#
# Keep ntpd from panicking in the event of a large clock skew
# when a VM guest is suspended and resumed.
tinker panic 0

# Permit time synchronization with our time source, but do not'
# permit the source to query or modify the service on this system.'
restrict default kod nomodify notrap nopeer noquery
restrict -6 default kod nomodify notrap nopeer noquery
restrict 127.0.0.1
restrict -6 ::1
server 0.pool.ntp.org
server 1.pool.ntp.org
server stdtime.gov.hk

# Undisciplined Local Clock. This is a fake driver intended for backup
# and when no outside source of synchronized time is available.
server 127.127.1.0
fudge 127.127.1.0 stratum 10
restrict 127.127.1.0


# Driftfile.
driftfile /var/lib/ntp/drift

 

其他机器同步时间用:


/usr/sbin/ntpdate $ntp_server_ip &>/dev/null ;clock -w

另外:

1.ntp server 配置文件 和其他机器同步命令 都用Puppet管理。

2.最好要两台NTP 服务器(接入一台交换机),起一个VIP指向这两台机器,并且在接入交换机上打开 源IP、源端口、目的IP、目的端口 的哈希功能(在等价路由基础上),这其实是实现了流量的负载均衡和高可用(具体咨询搞网络的同学)。