四、静态资源优化
Nginx作为静态资源Web服务器,用于静态资源处理,传输非常的高效
静态资源指的是非Web服务器端运行处理而生成的文件
静态资源类型 | 种类 |
浏览器渲染 | HTML、CSS、JS |
图片文件 | JPEG、GIF、PNG |
视频文件 | FLV、MP4、AVI |
其他文件 | TXT、DOC、PDF |
1、 静态资源缓存expires
浏览器缓存设置用于提高网站性能,像新闻网站,图片一旦发布,改动的可能是非常小的,所以我们希望用户访问一次后,图片缓存在用户的浏览器上。 浏览器是有自己的缓存机制,他是基于HTTP协议缓存机制来实现的,在HTTP协议中有很多头信息,那么实现浏览器的缓存就需要依赖特殊的头信息来与服务器进行特殊的验证,如Expires(http/1.0);Cache-control(http/1.1)。
浏览器缓存过期校验机制
浏览器发送请求,检测浏览器中有缓存,检测是否过期,没有过期就从缓存中直接读取,返回给浏览器;
过期了检查有无Etag,没有的话检查有无last-Modified,没有的话向web服务器发送请求,Web服务器请求后端,缓存协商再返回给浏览器,有last-Modified则向Web服务器请求if-Modified-Since,由服务器决策,返回200或304,200则请求后端,进行缓存协商,304则直接返回给浏览器;
如果有Etag,则向Web服务器请求If-None-Match,由服务器决策,返回200或304,200则请求后端,进行缓存协商,304则直接返回给浏览器。
名词解释:
1. Last-Modified:服务器上文件的最后修改时间 2. Etag:文件标识 3. Expires:本地缓存目录中,文件过期的时间(由服务器指定具体的时间) 4. Cache-control:本地缓存目录中,文件过期的时间(由服务器指定过期的间隔时间,由于浏览器根据间隔生成具体的时间)
配置静态资源缓存expires
1. #作用:添加Cache-Control Expires头 2. Syntax: expires [modified] time; 3. epoch | max | off; 4. Default: expires off; 5. Context: http, server, location, if in location 6. 7. server { 8. listen 80; 9. server_name tets.koten.com; 10. 11. location ~ .*\.(jpg|gif|png)$ { 12. expires 7d; 13. } 14. location ~ .*\.(js|css)$ { 15. expires 30d; 16. } 17. } 18. 19. 20. #取消js、css、html等静态文件缓存(如果代码没有上线,希望静态文件不被缓存) 21. location ~ .*\.(js|css|html)$ { 22. add_header Cache-Control no-store; 23. add_header Pragma no-cache; 24. }
2、sendfile静态资源高效读取
1. Syntax: sendfile on | off; 2. Default: sendfile off; 3. Context: http, server, location, if in location 4. 5. #将多个包一次发送,大文件推荐打开,需要开启sendfile 6. Syntax: tcp_nopush on | off; 7. Default: tcp_nopush off; 8. Context: http, server, location 9. 10. #来个包发个包不等待,适合小文件,需要开启keepalive 11. Syntax: tcp_nodelay on | off; 12. Default: tcpnodelay off; 13. Context: http, server, location
五、静态资源压缩
Nginx将响应报文发送至客户端之前启用压缩功能,然后进行传输,这能够有效地节约带宽,并提高响应至客户端的速度。
1、gzip传输压缩
1. #开启gzip传输压缩,传输前压缩,传输后解压 2. Syntax: gzip on | off; 3. Default: gzip off; 4. Context: http, server, location, if in location 5. 6. #gzip指定压缩文件 7. Syntax: gzip_types mime-type ...; 8. Default: gzip_types text/html; 9. Context: http, server, location 10. 11. #gzip压缩比率,加快传输,但压缩本身比较耗费服务器性能 12. Syntax: gzip_comp_level level; 13. Default:gzip_comp_level level 1; 14. Context: http, server, location 15. 16. #gzip压缩协议版本,压缩使用在http哪个协议,主流选择1.1版本 17. Syntax: gzip_http_version 1.0 | 1.1; 18. Default:gzip_http_version 1.1; 19. Context: http, server, location 20. 21. #静态文件压缩案例 22. [root@LB01 conf.d]# cat try.conf 23. server { 24. listen 80; 25. server_name test.koten.com; 26. 27. location ~ .*\.(jpg|png|gif) { 28. root /code/images; 29. #gzip on; 30. #gzip_types image/jpeg image/gif image/png; 31. #gzip_comp_level 2; 32. #gzip_http_version 1.1; 33. } 34. location ~ .*\.(txt|xml|html|json|js|css)$ { 35. gzip on; 36. gzip_http_version 1.1; 37. gzip_comp_level 1; 38. gzip_types text/plain application/json application/x-javascript application/css application/xml text/javascript; 39. } 40. } 41. #压缩前后观察对比,可以明显看到传输的Size大小变化
六、其他
1、防止资源盗链
防盗链,指的是防止资源被其他网站恶意盗用。
基础防盗链思路:主要是针对客户端请求过程中所携带的一些Header信息来验证请求的合法性,比如客户端在请求的过程中都会携带referer信息。优点是规则简单,配置和使用都很方便,缺点是防盗链所依赖的Referer验证信息是可以伪造的,所以通过referer信息防盗链并非100%可靠。
1. Syntax: valid_referers none | blocked | server_name | string ...; 2. Default: -; 3. Context: server, location 4. 5. #none: referer来源头部为空的情况 6. #blocked: referer来源头部不为空,这些都不以http://或者https://开头 7. #server_name: 来源头部信息包含当前域名,可以正则匹配
1、在Web1上准备html文件,准备偷取Web02的图片
1. <html> 2. <head> 3. <meta charset="utf-8"> 4. <title>fangdao_test</title> 5. </head> 6. <body style="background-color:pink;"> 7. <center><img src="https://web.koten.com/daolian.jpg"/></center> 8. </body> 9. </html>
2、访问页面可以看到
3、在服务器上配置允许盗的站点
1. location ~ .*\.(jpg|png|gif) { 2. root /var/www/wordpress/wp-content/extra/; 3. valid_referers none blocked *.koten.com server_name ~\.google\. ~\.baidu\.; 4. if ( $invalid_referer ) { 5. return 403; 6. } 7. } 8. #所有来自*.koten.com都可以访问到当前站点的图片,如果来源域名不在这个列表中,那么$invalid_referer等于1,在if语句中返回一个403个客户,这样用户便会看到一个403的页面
4、配置返回图片
1. location ~ .*\.(jpg|png|gif) { 2. root /var/www/wordpress/wp-content/extra/; 3. valid_referers none blocked *.koten.com; 4. if ( $invalid_referer ) { 5. rewrite ^(.*)$ /Picture/daolian1.gif break; 6. } 7. }
5、这种防护并不能百分百保证资源不被盗,因为我们可以通过命令来修改来源的refer信息
1. #伪造协议头访问 2. [root@web01 code]# curl -e "https://www.baidu.com" -I http://test.koten.com/Picture/daolian.jpg 3. HTTP/1.1 403 Forbidden 4. Server: nginx 5. Date: Thu, 10 Oct 2019 09:01:05 GMT 6. Content-Type: text/html; charset=utf-8,gbk 7. Content-Length: 162 8. Connection: keep-alive 9. 10. #伪造协议头访问 11. [root@web01 code]# curl -e "https://www.koten.com" -I http://test.koten.com/Picture/daolian.jpg 12. HTTP/1.1 200 OK 13. Server: nginx 14. Date: Thu, 10 Oct 2019 09:01:35 GMT 15. Content-Type: image/jpeg 16. Content-Length: 556417 17. Last-Modified: Thu, 10 Oct 2019 07:14:19 GMT 18. Connection: keep-alive 19. ETag: "5d9eda4b-87d81" 20. Accept-Ranges: bytes
2、允许跨域访问
跨域访问是当我们通过浏览器访问a网站时,同时会利用到ajax或其他方式,同时也请求b网站,这样的话就出现了请求一个页面,使用了两个域名,这种方式对浏览器来说默认是禁止的。因为浏览器会读取Access-Control-Allow-Origin的头信息,如果服务端允许,则浏览器不会进行拦截。
1. #编辑Nginx配置文件 2. [root@web02 code]# vim /etc/nginx/conf.d/s.conf 3. server { 4. listen 80; 5. server_name test.koten.com; 6. location / { 7. root /code; 8. index index.html; 9. } 10. } 11. 12. #编辑html文件 13. [root@Nginx ~]# cat /code/test.html 14. <html lang="en"> 15. <head> 16. <meta charset="UTF-8" /> 17. <title>测试ajax和跨域访问</title> 18. <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> 19. </head> 20. <script type="text/javascript"> 21. $(document).ready(function(){ 22. $.ajax({ 23. type: "GET", 24. url: "http://web.koten.com", 25. success: function(data) { 26. alert("成功跨域!"); 27. }, 28. error: function() { 29. alert("跨域失败!"); 30. } 31. }); 32. }); 33. </script> 34. <body> 35. <h1>跨域访问测试</h1> 36. </body> 37. </html> 38. 39. #被关联网站配置 40. server { 41. listen 80; 42. server_name web.koten.com; 43. root /code; 44. index index.html; 45. charset utf-8; 46. 47. location ~ .*\.(html|htm)$ { 48. add_header Access-Control-Allow-Origin *; 49. add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS; 50. } 51. }
3、CPU亲和配置
CPU亲和(affinity)减少进程之间不断频繁切换,减少性能损耗,其实现原理是建CPU核心和Nginx工作进程绑定方式,把每个worker进程固定到对应的cpu上执行,减少切换CPU的cache miss,获得更好的性能。
1. #查看当前CPU物理状态 2. [root@Web01 ~]$ lscpu | grep "CPU(s)" 3. CPU(s): 8 4. On-line CPU(s) list: 0-7 5. NUMA node0 CPU(s): 0-7 6. 7. #以上服务器有一颗物理CPU,上面有8个核心 8. 9. #将Nginx worker进程绑定至不同的核心上,建议与CPU核心保持一致 10. 11. # 第一种绑定组合方式(不推荐) 12. worker_processes 12; 13. worker_cpu_affinity 000000000001 000000000010 000000000100 000000001000 000000010000 000000100000 000001000000 000010000000 000100000000 001000000000 010000000000 10000000000; 14. 15. # 第二种方式(使用较少) 16. worker_processes 2; 17. worker_cpu_affinity 101010101010 010101010101; 18. 19. # 第三种最佳绑定方式,修改nginx启动的work进程为自动。 20. worker_processes auto; 21. worker_cpu_affinity auto; 22. 23. #查看Nginx worker进程绑定至对应CPU 24. [root@web01 ~]# ps -eo pid,args,psr|grep [n]ginx 25. 1242 nginx: master process /usr/ 2 26. 1243 nginx: worker process 0 27. 1244 nginx: worker process 1 28. 1245 nginx: worker process 2 29. 1246 nginx: worker process 3
4、通用优化配置
1. [root@nginx ~]# cat nginx.conf 2. user www; # nginx进程启动用户 3. worker_processes auto; #与cpu核心一致即可 4. worker_cpu_affinity auto; # cpu亲和 5. 6. error_log /var/log/nginx/error.log warn; # 错误日志 7. pid /run/nginx.pid; 8. worker_rlimit_nofile 35535; #每个work能打开的文件描述符,调整至1w以上,负荷较高建议2-3w 9. 10. events { 11. use epoll; # 使用epoll高效网络模型 12. worker_connections 10240; # 限制每个进程能处理多少个连接,10240x[cpu核心] 13. } 14. 15. http { 16. include mime.types; 17. default_type application/octet-stream; 18. charset utf-8; # 统一使用utf-8字符集 19. 20. # 定义日志格式 21. log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 22. '$status $body_bytes_sent "$http_referer" ' 23. '"$http_user_agent" "$http_x_forwarded_for"'; 24. 25. #定义json日志格式 26. log_format json_access '{"@timestamp":"$time_iso8601",' 27. '"host":"$server_addr",' 28. '"clientip":"$remote_addr",' 29. '"size":$body_bytes_sent,' 30. '"responsetime":$request_time,' 31. '"upstreamtime":"$upstream_response_time",' 32. '"upstreamhost":"$upstream_addr",' 33. '"http_host":"$host",' 34. '"url":"$uri",' 35. '"domain":"$host",' 36. '"xff":"$http_x_forwarded_for",' 37. '"referer":"$http_referer",' 38. '"status":"$status"}'; 39. 40. access_log /var/log/nginx/access.log main; # 访问日志 41. 42. server_tokens off; # 禁止浏览器显示nginx版本号 43. client_max_body_size 200m; # 文件上传大小限制调整 44. 45. # 文件高效传输,静态资源服务器建议打开 46. sendfile on; 47. tcp_nopush on; 48. # 文件实时传输,动态资源服务建议打开,需要打开keepalive 49. tcp_nodelay on; 50. keepalive_timeout 65; 51. 52. # Gzip 压缩 53. gzip on; 54. gzip_disable "MSIE [1-6]\."; #针对IE浏览器不进行压缩 55. gzip_http_version 1.1; 56. gzip_comp_level 2; #压缩级别 57. gzip_buffers 16 8k; #压缩的缓冲区 58. gzip_min_length 1024; #文件大于1024字节才进行压缩,默认值20 59. gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript image/jpeg; 60. 61. # 虚拟主机 62. include /etc/nginx/conf.d/*.conf; 63. }
Nginx性能优化总结
1、CPU亲和、worker进程数、调整每个worker进程打开的文件数
2、使用EPOOL网络模型、调整每个worker进程的最大连接数
3、文件的高效读取sendfile、no铺设
4、文件传输实时性、nodealy
5、开启tcp长连接,以及长连接超时时间keepalived
6、开启文件传输压缩gzip
7、开启静态文件expires缓存
8、隐藏Nginx版本号
9、禁止通过ip地址访问,禁止恶意域名解析,只允许域名访问
10、配置防盗链、以及跨域访问
11、防DDOS、CC攻击,限制单IP并发连接,以及http请求
12、建立Nginx错误页面
13、Nginx加密传输https优化
14、Nginx proxy_cache、fastcgi_cache、uwsgi_cache缓存,第三方工具(squid、varnish)
我是koten,10年运维经验,持续分享运维干货,感谢大家的阅读和关注!