整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

前端常用meta标签的作用以及全面整理

前端常用meta标签的作用以及全面整理

、定义

<meta> 标签提供关于 HTML 文档的元数据。它不会显示在页面上,但是对于机器是可读的。可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。

2、作用

meta里的数据是供机器解读的,告诉机器该如何解析这个页面,还有一个用途是可以添加服务器发送到浏览器的http头部内容,例如我们为页面中添加如下meta标签:


  1. <meta http-equiv="charset" content="iso-8859-1">
  2. <meta http-equiv="expires" content="31 Dec 2008">

浏览器的头部就会包括这些:


  1. charset:iso-8859-1
  2. expires:31 Dec 2008

只有浏览器可以接受这些附加的头部字段,并能以适当的方式使用它们时,这些字段才有意义。

3、meta的必需属性和可选属性

meta的必需属性是content,当然并不是说meta标签里一定要有content,而是当有http-equiv或name属性的时候,一定要有content属性对其进行说明。例如:

必需属性

<meta name="keywords" content="HTML,ASP,PHP,SQL">

这里面content里的属性就是对keywords进行的说明,所以呢也可以理解成一个键值对吧,就是{keywords:"HTML,ASP,PHP,SQL"}。

可选属性

在W3school中,对于meta的可选属性说到了三个,分别是http-equiv、name和scheme。考虑到scheme不是很常用,所以就只说下前两个属性吧。

http-equiv

http-equiv属性是添加http头部内容,对一些自定义的,或者需要额外添加的http头部内容,需要发送到浏览器中,我们就可以是使用这个属性。在上面的meta作用中也有简单的说明,那么现在再举个例子。例如我们不想使用js来重定向,用http头部内容控制,那么就可以这样控制:

<meta http-equiv="Refresh" content="5;url=http://blog.yangchen123h.cn" />

在页面中加入这个后,5秒钟后就会跳转到指定页面啦,效果可看W3school的例子

name

第二个可选属性是name,这个属性是供浏览器进行解析,对于一些浏览器兼容性问题,name属性是最常用的,当然有个前提就是浏览器能够解析你写进去的name属性才可以,不然就是没有意义的。还是举个例子吧:

<meta name="renderer" content="webkit">

这个meta标签的意思就是告诉浏览器,用webkit内核进行解析,当然前提是浏览器有webkit内核才可以,不然就是没有意义的啦。当然看到这个你可能会有疑问,这个renderer是从哪里冒出来的,我要怎么知道呢?这个就是在对应的浏览器的开发文档里就会有表明的,例如这个renderer是在360浏览器里说明的。360浏览器内核控制Meta标签说明文档

常用meta标签大总结

接下来就是常用的meta标签大总结啦,我会尽可能的做到全

charset

charset是声明文档使用的字符编码,解决乱码问题主要用的就是它,值得一提的是,这个charset一定要写第一行,不然就可能会产生乱码了。

charset有两种写法


  1. <meta charset="utf-8">
  2. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

两个都是等效的。

百度禁止转码

百度会自动对网页进行转码,这个标签是禁止百度的自动转码

<meta http-equiv="Cache-Control" content="no-siteapp" />

SEO 优化部分


  1. <!-- 页面标题<title>标签(head 头部必须) -->
  2. <title>your title</title>
  3. <!-- 页面关键词 keywords -->
  4. <meta name="keywords" content="your keywords">
  5. <!-- 页面描述内容 description -->
  6. <meta name="description" content="your description">
  7. <!-- 定义网页作者 author -->
  8. <meta name="author" content="author,email address">
  9. <!-- 定义网页搜索引擎索引方式,robotterms 是一组使用英文逗号「,」分割的值,通常有如下几种取值:none,noindex,nofollow,all,index和follow。 -->
  10. <meta name="robots" content="index,follow">

viewport

viewport主要是影响移动端页面布局的,例如:


  1. <meta name="viewport" content="width=device-width, initial-scale=1.0">

content 参数:

  • width viewport 宽度(数值/device-width)
  • height viewport 高度(数值/device-height)
  • initial-scale 初始缩放比例
  • maximum-scale 最大缩放比例
  • minimum-scale 最小缩放比例
  • user-scalable 是否允许用户缩放(yes/no)

各浏览器平台

Microsoft Internet Explorer


  1. <!-- 优先使用最新的ie版本 -->
  2. <meta http-equiv="x-ua-compatible" content="ie=edge">
  3. <!-- 是否开启cleartype显示效果 -->
  4. <meta http-equiv="cleartype" content="on">
  5. <meta name="skype_toolbar" content="skype_toolbar_parser_compatible">
  6. <!-- Pinned Site -->
  7. <!-- IE 10 / Windows 8 -->
  8. <meta name="msapplication-TileImage" content="pinned-tile-144.png">
  9. <meta name="msapplication-TileColor" content="#009900">
  10. <!-- IE 11 / Windows 9.1 -->
  11. <meta name="msapplication-config" content="ieconfig.xml">

Google Chrome


  1. <!-- 优先使用最新的chrome版本 -->
  2. <meta http-equiv="X-UA-Compatible" content="chrome=1" />
  3. <!-- 禁止自动翻译 -->
  4. <meta name="google" value="notranslate">

360浏览器


  1. <!-- 选择使用的浏览器解析内核 -->
  2. <meta name="renderer" content="webkit|ie-comp|ie-stand">

UC手机浏览器

UCBrowser_U3_API

QQ手机浏览器


  1. <!-- 锁定屏幕在特定方向 -->
  2. <meta name="x5-orientation" content="landscape/portrait">
  3. <!-- 全屏显示 -->
  4. <meta name="x5-fullscreen" content="true">
  5. <!-- 页面将以应用模式显示 -->
  6. <meta name="x5-page-mode" content="app">

Apple iOS


  1. <!-- Smart App Banner -->
  2. <meta name="apple-itunes-app" content="app-id=APP_ID,affiliate-data=AFFILIATE_ID,app-argument=SOME_TEXT">
  3. <!-- 禁止自动探测并格式化手机号码 -->
  4. <meta name="format-detection" content="telephone=no">
  5. <!-- Add to Home Screen添加到主屏 -->
  6. <!-- 是否启用 WebApp 全屏模式 -->
  7. <meta name="apple-mobile-web-app-capable" content="yes">
  8. <!-- 设置状态栏的背景颜色,只有在 “apple-mobile-web-app-capable” content=”yes” 时生效 -->
  9. <meta name="apple-mobile-web-app-status-bar-style" content="black">
  10. <!-- 添加到主屏后的标题 -->
  11. <meta name="apple-mobile-web-app-title" content="App Title">

Google Android


  1. <meta name="theme-color" content="#E64545">
  2. <!-- 添加到主屏 -->
  3. <meta name="mobile-web-app-capable" content="yes">
  4. <!-- More info: https://developer.chrome.com/multidevice/android/installtohomescreen -->

App Links


  1. <!-- iOS -->
  2. <meta property="al:ios:url" content="applinks://docs">
  3. <meta property="al:ios:app_store_id" content="12345">
  4. <meta property="al:ios:app_name" content="App Links">
  5. <!-- Android -->
  6. <meta property="al:android:url" content="applinks://docs">
  7. <meta property="al:android:app_name" content="App Links">
  8. <meta property="al:android:package" content="org.applinks">
  9. <!-- Web Fallback -->
  10. <meta property="al:web:url" content="http://applinks.org/documentation">
  11. <!-- More info: http://applinks.org/documentation/ -->

最后——移动端常用的meta


  1. <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
  2. <meta name="apple-mobile-web-app-capable" content="yes" />
  3. <meta name="apple-mobile-web-app-status-bar-style" content="black" />
  4. <meta name="format-detection"content="telephone=no, email=no" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
  6. <meta name="apple-mobile-web-app-capable" content="yes" /><!-- 删除苹果默认的工具栏和菜单栏 -->
  7. <meta name="apple-mobile-web-app-status-bar-style" content="black" /><!-- 设置苹果工具栏颜色 -->
  8. <meta name="format-detection" content="telphone=no, email=no" /><!-- 忽略页面中的数字识别为电话,忽略email识别 -->
  9. <!-- 启用360浏览器的极速模式(webkit) -->
  10. <meta name="renderer" content="webkit">
  11. <!-- 避免IE使用兼容模式 -->
  12. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  13. <!-- 针对手持设备优化,主要是针对一些老的不识别viewport的浏览器,比如黑莓 -->
  14. <meta name="HandheldFriendly" content="true">
  15. <!-- 微软的老式浏览器 -->
  16. <meta name="MobileOptimized" content="320">
  17. <!-- uc强制竖屏 -->
  18. <meta name="screen-orientation" content="portrait">
  19. <!-- QQ强制竖屏 -->
  20. <meta name="x5-orientation" content="portrait">
  21. <!-- UC强制全屏 -->
  22. <meta name="full-screen" content="yes">
  23. <!-- QQ强制全屏 -->
  24. <meta name="x5-fullscreen" content="true">
  25. <!-- UC应用模式 -->
  26. <meta name="browsermode" content="application">
  27. <!-- QQ应用模式 -->
  28. <meta name="x5-page-mode" content="app">
  29. <!-- windows phone 点击无高光 -->
  30. <meta name="msapplication-tap-highlight" content="no">
  31. <!-- 适应移动端end -->

ginx优化与防盗链

一、隐藏版本号

可以使用Fiddler工具抓取数据包,查看Nginx版本,也可以在CentOS中使用命令curl -I http://20.0.0.55 显示响应报文首部信息。

curl -I http://20.0.0.55

方法一:修改配置文件方式

vim /usr/local/nginx/conf/nginx.conf
http {
    include       mime.types;
    default_type  application/octet-stream;
    server_tokens off;     #添加关闭版本号
}
systemctl restart nginx
curl -I http://20.0.0.55

方法二:

[root@localhost objs]# vim /opt/nginx-1.12.2/src/core/nginx.h
#define NGINX_VERSION      "1.30.23"                     #修改版本号
#define NGINX_VER          "apache/" NGINX_VERSION       #修改服务器类型
---》wq
[root@localhost opt]# cd nginx-1.12.2/
[root@localhost nginx-1.12.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module
[root@localhost nginx-1.12.2]# make           编译
[root@localhost objs]# cp /opt/nginx-1.12.2/objs/nginx /usr/local/nginx/sbin/nginx
[root@localhost objs]# systemctl start nginx
[root@localhost objs]# curl -I http://20.0.0.55

二、修改用户和组

vim /usr/local/nginx/conf/nginx.conf
user root root;                 #取消注释,修改用户为root,组为root

systemctl restart nginx

ps aux | grep nginx
主进程由root创建,子进程由nginx创建

三、缓存时间

vim /usr/local/nginx/conf/nginx.conf
http {
......
  server {
  ...... 
    location / {
      root html;
      index index.html index.htm;
    }
    
    location ~ \.(gif|jpg|jpeg|png|bmp|ico)$ {    #加入新的 location,以图片作为缓存对象
      root html;
      expires 1d;                 #指定缓存时间,1天
    }
......
  }
}

systemctl restart nginx

四、日志切割

vim /opt/fenge.sh
#!/bin/bash
#  filename: fenge.sh
day=$(date -d "-1 day" "+%Y%m%d")                 #显示前一天的时间
logs_path="/var/log/nginx"                        #定义一个新的日志存放目录
pid_path="/usr/local/nginx/logs/nginx.pid"        #定义变量pid_path将nginx进程id

[ -d $logs_path ] || mkdir -p $logs_path        #创建日志文件目录

#移动并重命名日志文件
mv /usr/local/nginx/logs/access.log ${logs_path}/huigenb.com-access.log-{$day}

#重建日志文件
kill -USR1 $(cat $pid_path)
#删除30天前的日志文件                   
find $logs_path -mtime +30 -exec rm -rf {} \;
#find $logs_path -mtime +30 |xargs rm -rf
---->wq
chmod +x /opt/fenge.sh
/opt/fenge.sh
ls /var/log/nginx
ls /usr/local/nginx/logs/access.log

crontab -e
0 1 * * * /opt/fenge.sh   #设置周期性计划

五、连接超时

HTTP有个KeepAlive,告诉web服务器在处理完一个请求后保持这个TCP连接的打开状态。若接收到来自客户端的其他请求,服务端会利用这个未被关闭的连接,而不需要再建立一个连接。

KeepAlive在一段时间内保持打开状态,它们会在这段时间占用资源,占用过多就会影响性能。

vim /usr/local/nginx/conf/nginx.conf
http {
...... 
    keepalive_timeout 65 180;               #三次握手的超过时间
    client_header_timeout 80;               #等待客户端发送请求头的超时时间会发送408 错误
    client_body_timeout 80;                 #设置客户端发送请求体的超时时间
...... 
}

systemctl restart nginx

keepalive_timeout

指定KeepAlive的超时时间(timeout)。指定每个TCP连接最多可以保持多长时间,服务器将会在这个时间后关闭连接。 Nginx的默认值是65秒,有些浏览器最多只保持 60 秒,所以可以设定为 60 秒。若将它设置为0,就禁止了keepalive 连接。

第二个参数(可选的)指定了在响应头Keep-Alive:timeout=time中的time值。这个头能够让一些浏览器主动关闭连接,这样服务器就不必去关闭连接了。没有这个参数,Nginx 不会发送 Keep-Alive 响应头。

client_header_timeout

客户端向服务端发送一个完整的 request header 的超时时间。如果客户端在指定时间内没有发送一个完整的 request header,Nginx 返回 HTTP 408(Request Timed Out)。

client_body_timeout

指定客户端与服务端建立连接后发送 request body 的超时时间。如果客户端在指定时间内没有发送任何内容,Nginx 返回 HTTP 408(Request Timed Out)。

六、更改进程数

在高并发场景,需要启动更多的Nginx进程以保证快速响应,以处理用户的请求,避免造成阻塞

cat /proc/cpuinfo | grep -c "physical id"      #查看cpu核数
ps aux | grep nginx                            #查看nginx主进程中包含几个子进程
vim /usr/local/nginx/conf/nginx.conf
worker_processes  2;                           #修改为核数相同或者2倍
worker_cpu_affinity 01 10;                     #设置每个进程由不同cpu处理,进程数配2 4 6 8分别为0001 0010 0100 1000 

systemctl restart nginx

2核cpu,开启两个进程

worker_processes     2;
worker_cpu_affinity 01 10;

解释:01表示启用第一个CPU内核,10表示启用第二个CPU内核

worker_cpu_affinity 01 10;表示开启两个进程,第一个进程对应着第一个CPU内核,第二个进程对应着第二个CPU内核。

2核cpu,开启4个进程

worker_processes     4;
worker_cpu_affinity 01 10 01 10;

解释:开启了四个进程,它们分别对应着开启2个CPU内核

4核cpu,开启4个进程

worker_processes     4;
worker_cpu_affinity 0001 0010 0100 1000;

解释:0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推

4核cpu,开启2个进程

worker_processes     2;
worker_cpu_affinity 0101 1010;

解释:0101表示开启第一个和第三个内核,1010表示开启第二个和第四个内核;2个进程对应着四个内核;worker_cpu_affinity配置是写在/etc/nginx/nginx.conf里面的;2核是 01,四核是0001,8核是00000001,有多少个核,就有几位数,1表示该内核开启,0表示该内核关闭

8核cpu,开启8个进程

worker_processes     8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

解释:0001表示启用第一个CPU内核,0010表示启用第二个CPU内核,依此类推;worker_processes最多开启8个,8个以上性能提升不会再提升了,而且稳定性变得更低,所以8个进程够用了。

七、配置网页压缩

Nginx的ngx_http_gzip_module压缩模块提供对文件内容压缩的功能。

允许Nginx服务器将输出内容在发送客户端之前进行压缩,以节约网站带宽,提升用户的访问体验,默认已经安装可在配置文件中加入相应的压缩功能参数对压缩性能进行优化。

vim /usr/local/nginx/conf/nginx.conf
http {
...... 
gzip on;       #取消注释,开启gzip压缩功能
   gzip_min_length 1k;        #最小压缩文件大小
   gzip_buffers 4 64k;        #压缩缓冲区,大小为4个64k缓冲区
   gzip_http_version 1.1;     #压缩版本(默认1.1,前端如果是squid2.5请使用1.0)
   gzip_comp_level 6;         #压缩比率
   gzip_vary on;     #支持前端缓存服务器存储压缩页面
   gzip_types text/plain text/javascript application/x-javascript text/css text/xml application/xml application/xml+rss image/jpg image/jpeg image/png image/gif application/x-httpd-php application/javascript application/json;  #压缩类型,表示哪些网页文档启用压缩功能
...... 
}

cd /usr/local/nginx/html
先将图片(R-C.jpg)文件传到/usr/local/nginx/html目录下
vim index.html
...... 
<img src="R-C.jpg"/>       #网页中插入图片
</body>
</html>

systemctl restart nginx

在Linux系统中,打开火狐浏览器,按F12,然后F5

选择 网络------>选择HTML、WS、其他

访问http://20.0.0.55 ,双击200响应消息查看响应头中包含Content-Enconding:gzip

八、配置防盗链

vim /usr/local/nginx/conf/nginx.conf
http {
......
  server {
  ......
   location ~* \.(gif|jpg|swf)$ {
           valid_referers none blocks *.dajb.com dajb.com;
           if ( $invalid_referer) {
              rewrite ^/ http://www.dajb.com/error.png;
        }
        }

  ......
  }
}

~* .(jpg|gif|jepg|bmp|ico)$ :这段正则表达式表示匹配不区分大小写,以.jpg 或.gif 或.swf

结尾的文件;

? valid_referers :设置信任的网站,可以正常使用图片;

? 后面的网址或者域名 :referer 中包含相关字符串的网址;

? if语句:如果链接的来源域名不在valid_referers所列出的列表中,$invalid_referer为1,则执行后面的操作,即进行重写或返回403 页面。

Web源主机(20.0.0.55)

cd /usr/local/nginx/html
将R-C.jpg、error.png文件传到/usr/local/nginx/html目录下
vim index.html
...... 
<img src="R-C.jpg"/>
</body>
</html>

echo "20.0.0.55 www.dajb.com" >> /etc/hosts 
echo "20.0.0.58 www.daolian.com" >> /etc/hosts

盗链网站主机(20.0.0.58)

yum install -y httpd
vim /var/www/html/index.html
<html>
<body>
<img src="http://www.dajb.com/R-C.jpg"/>
</body>
</html>
---->wq
echo "20.0.0.55 www.dajb.com" >> /etc/hosts 
echo "20.0.0.58 www.daolian.com" >> /etc/hosts

盗图网站主机(20.0.0.58)上进行浏览器验证

九、fpm参数优化

cd /usr/local/php/etc/
cp php-fpm.conf.default php-fpm.conf
vim php-fpm.conf
pid=run/php-fpm.pid
 
vim /usr/local/php/etc/php-fpm.d/www.conf
#96行
pm=dynamic    #fpm进程启动方式,动态的
#107行
pm.max_children=20  #fpm进程启动的最大进程数
#112行
pm.start_servers=5  #动态方式下启动时默认开启的进程数,在最小和最大之间
#117行
pm.min_spare_servers=2  #动态方式下最小空闲进程数
#122行
pm.max_spare_servers=8  #动态方式下最大空闲进程数
 
#启动php-fpm,不可用于重启
/usr/local/php/sbin/php-fpm  -c /usr/local/php/lib/php.ini
#执行第一个命令后,就可以使用下面这条命令查看pid号重启php-fpm
kill -USR2 `cat /usr/local/php/var/run/php-fpm.pid`
netstat -anpt | grep 9000

十、文件句柄

linux/Unix上,一切皆文件,每一次用户发起请求就会生成一个文件句柄,文件句柄可以理解为就是一个索引,所以文件句柄就会随着请求量的增多,而进程调用的频率增加,文件句柄的产生就越多,系统对文件句柄默认的限制是1024个,对Nginx来说非常小了,需要改大一点

(1)设置方式

系统全局性修改

用户局部性修改

进程局部性修改

(2)系统全局性修改和用户局部性修改

vim /etc/security/limits.conf

在End of file前面添加4个参数

soft:软控制,到达设定值后,操作系统不会采取措施,只是发提醒

hard:硬控制,到达设定值后,操作系统会采取机制对当前进程进行限制,这个时候请求就会受到影响

root:这里代表root用户(系统全局性修改)

*:代表全局,即所有用户都受此限制(用户局部性修改)

nofile:指限制的是文件数的配置项。后面的数字即设定的值,一般设置10000左右

尤其在企业新装的系统,这个地方应该根据实际情况进行设置,可以设置全局的,也可以设置用户级别的

(3)进程局部性修改

vim /usr/local/nginx/conf/nginx.conf

每个进程的最大文件打开数,所以最好与 ulimit -n 的值保持一致。

worker_rlimit_nofile 35535; #进程限制

十一、事件处理模型优化

nginx的连接处理机制在于不同的操作系统会采用不同的I/O模型,Linux下,nginx使用epoll的I/O多路复用模型,在freebsd使用kqueue的IO多路复用模型,在solaris使用/dev/pool方式的IO多路复用模型,在windows使用的icop等等。要根据系统类型不同选择不同的事务处理模型,我们使用的是Centos,因此将nginx的事件处理模型调整为epoll模型。

events {
    worker_connections  10240;    //设置连接数
    use epoll;
}

十二、高效传输模式

vim /usr/local/nginx/conf/nginx.conf
sendfile on; # 开启高效文件传输模式。
tcp_nopush on; #需要在sendfile开启模式才有效,防止网路阻塞,积极的减少网络报文段的数量。将响应头和正文的开始部分一起发送,而不一个接一个的发送。

十三、proxy超时设置

proxy_connect_timeout 90;
proxy_send_timeout  90;
proxy_read_timeout  4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k

nginx通用配置优化

#将nginx进程设置为普通用户,为了安全考虑
user nginx; 

#当前启动的worker进程,官方建议是与系统核心数一致
worker_processes 2;
#方式一,就是自动分配绑定
worker_cpu_affinity auto;

#日志配置成warn
error_log /var/log/nginx/error.log warn; 
pid /var/run/nginx.pid;

#针对 nginx 句柄的文件限制
worker_rlimit_nofile 35535;
#事件模型
events {
    #使用epoll内核模型
    use epoll;
    #每一个进程可以处理多少个连接,如果是多核可以将连接数调高 worker_processes * 1024
    worker_connections 10240;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    charset utf-8;  #设置字符集

    #设置日志输出格式,根据自己的情况设置
    log_format  main  '$http_user_agent' '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" '
                      '"$args" "$request_uri"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;   #对静态资源的处理比较有效
    #tcp_nopush     on;   #如果做静态资源服务器可以打开

    keepalive_timeout  65; 

    ########
    #Gzip module
    gzip  on;    #文件压缩默认可以打开

    include /etc/nginx/conf.d/*.conf;
}

mote_addr - r e m o t e u s e r [ remote_user [ re m o t e u ? ser [ time_local] “ KaTeX parse error: Double superscript at position 34: … '? status b o d y b y t e s s e n t " body_bytes_sent " b o d y b ? y t e s s ? e n t " http_referer” ’

'“ h t t p u s e r a g e n t " " http_user_agent" " h tt p u ? se r a ? g e n t "" http_x_forwarded_for” ’

‘“

a r g s " " args" " a r g s ""

request_uri”’;

access_log  /var/log/nginx/access.log  main;

sendfile        on;   #对静态资源的处理比较有效
#tcp_nopush     on;   #如果做静态资源服务器可以打开

keepalive_timeout  65; 

########
#Gzip module
gzip  on;    #文件压缩默认可以打开

include /etc/nginx/conf.d/*.conf;

}

信做过web的同学对于 Nginx 一定不陌生,它是一款轻量级的开源 Web 服务及代理程序。在 Nginx 出现之前市场上主流两款 Web 服务,一款是 IIS,另外一款是 Apache。而在 Nginx 诞生后,因其轻量化、支持高并发等特性,逐渐蚕食了这两款 Web 服务的市场份额。目前国内大量企业已经广泛使用 Nginx。那么我们在工作中如何对其进行优化和配置便成了重中之重。

在学习如何优化和配置 Nginx 之前,首先需要提前掌握一些基础知识,包括:

  • 熟悉Linux 的基础操作;
  • 了解 Nginx 安装和基础配置;
  • 对 HTTP 请求过程有一定了解。

Nginx 的优化主要分为基础优化和缓存优化,我们先来看一下基础优化。

基础配置优化主要包括:

  • CPU 亲和性优化;
  • Nginx 模型优化;
  • Nginx 传输方式优化;
  • Nginx 文件压缩优化。

在 Nginx 用于普通的绝大部分 Web 服务时这些优化场景都是需要了解的。

CPU 亲和性

所谓的 CPU 亲和性是做什么呢?现在的CPU通常都是多核的,而且可以通过超线程来虚拟更多核数 ,那亲和力就是让 Nginx 充分发挥多核 CPU 的性能,从而提高 Nginx 的服务性能。 Nginx 运行时会启用 1 个 master 进程及多个 worker 进程,worker 进程负责处理请求,如果 worker 进程在多核 CPU 中发生频繁的调度切换就会损耗性能。在这种情况下,我们希望减少这种频繁调度,让每一个 Nginx 的 worker 线程都能够固定到具体的 CPU 核心上,所以就需要配置 Nginx 的 CPU 亲和性来解决这个问题。

由于 Nginx CPU 亲和性配置本身有多套配置方案,这里推荐我们推荐直接将配置项设置成 auto(worker_cpu_affinity ),即采用了 Nginx 推荐的 CPU绑核策略方式。另外的一个方式是手动绑定,将 worker 线程数量与 CPU 核数一一绑定方式设置。我们设置成 auto Nginx 会自动识别并按照推荐策略来分配 worker 线程和 CPU。

如图所示,我们看到 CPU 的核心有 8 个,如果我们设置成 auto 后,那么 Nginx 会将 8 个 worker 线程一对一地按照推荐策略绑定到 CPU 核心上,这样避免 CPU 频繁对 worker 线程进行调度,从而降低 CPU 损耗。

IO 流事件模型

Nginx 第二个基础配置优化项是 IO 流事件模型,我们经常可以在 Nginx 下面看到的 events 配置模块中默认设置了 use epoll,表示 Nginx 使用 epoll 这个 IO 流事件模型,那为什么 Nginx 会选择使用 epoll 呢?这是因为 epoll 有以下这些得天独厚的优势。我们来详细讲解一下:

首先,Linux 系统下一切皆文件,比如我们打开一个设备,它便会产生一个文件描述符。在产生一个进程时,这个进程便需要一个进程描述符,这个进程描述符也是一个文件。所以在 Nginx 处理请求的时候,每一个请求都会产生处理请求的描述符。

其次,在 Nginx 处理大规模请求的时候,为了提高并发效率需要采用异步非阻塞模型,这又和 epoll 有什么关系呢?epoll 本身是以异步非阻塞模型来处理请求流中的事件流。

这里还需要注意一点,并不是所有的 Linux 操作系统都可以使用 epoll,它是在 kernel 2.6 版本以后提出的,早期内核使用的 select\poll 模型,select 模型比 epoll 模型性能要低很多,有经验的运维同学一定深有体会。

那么 epoll 相比于 select 模型到底具备哪些优势呢?

  • epoll 处理事件流模型是线程安全的;
  • epoll 跟 select 模型相比调用 fd 文件描述符时使用了 mmap 共享用户和内核的部分空间,提高了效率;
  • epoll 是基于事件驱动的,相比 select 需要扫描整个文件描述符的相关状态,epoll 基于事件驱动避免频繁扫描文件描述符,可以直接调用 callback 回调函数,效率更高;
  • 取消了 select 模型里面单个进程能够监视的文件描述符的数量存在的最大限制(1024),如果你有使用过早期的 Apache 版本的,它使用的select 模型,当请求超过 1000 以后就会出现延迟或者请求错误,而改用 Nginx 的话性能会得到明显的改善。

另外补充下,在 events{} 配置中还涉及一个优化的地方就是 worker_connections,这个也是在 events 里面来进行设置的,通过上面的学习我们知道了 worker 线程作用,那每一个 worker 线程所支持的连接是有限的,这里会默认设置成 1024,而我们在处理高并发的场景时,单个 worker 线程设置成 1024 的话往往偏低,这里建议你将 worker_connections 调大一些,你可以参考实际业务所需 Nginx 处理最大峰值来调大这个设置值。

零拷贝

第三个基础配置优化是零拷贝,所谓零拷贝的配置是在 Nginx 中的 HTTP 配置模块中添加一个 sendfile on 配置项,它便是一个零拷贝,所谓零拷贝并不代表不拷贝了,而是说它做到了文件的内核态到用户态的零拷贝。

如图所示,如果我们没有使用零拷贝时文件传输是什么样子的?首先 Nginx 在处理文件时,会将文件传入操作系统内核态的 Buffer Cache,然后传递到操作系统上层的用户态,经用户态的 Buffer Cache 再传回内核态中,最后通过 Socket 将文件转发出去。

这个时候你会发现一个问题,对于静态文件并不需要流转到用户态中,直接通过内核态效率更高,所以这时我们就需要在 Nginx 中开启 sendfile on,这样静态文件就可以通过红色的路径在内核态中完成转发,而不用再去绕道用户态,提高了效率。

文件压缩

Nginx 基础配置优化的最后一项是文件压缩,我们知道服务端往客户端发送的数据越小,占用的延迟越低,用户体验就会越好。所以往往在代理或 Nginx 中会设置文件压缩,我们主要通过 gzip 方式进行设置,主要的设置项如下:

  • gzip on 负责打开后端的压缩功能;
  • gzip_buffer 16 8k 表示设置 Nginx 在处理文件压缩时的内存空间;
  • gzip_comp_level 6 表示 Nginx 在处理压缩时的压缩等级,通常等级越高它的压缩比就越大,但并不是说压缩比越大越好,还是需要根据实际情况来选择合适的压缩比,压缩比太大影响性能,压缩比太小起不到应有的效果,一般来说推荐你设置成 6 就比较合适;
  • gzip_http_version 1.1 表示只对 HTTP 1.1 版本的协议进行压缩;
  • gzip_min_length 256 表示只有大于最小的 256 字节长度时才进行压缩,如果小于该长度就不进行压缩;
  • gzip_proxied any 代表 Nginx 作为反向代理时依据后端服务器时返回信息设置一些 gzip 压缩策略;
  • gzip_vary on 表示是否发送 Vary:Accept_Encoding 响应头字段,实现通知接收方服务端作了 gzip 压缩;
  • application/vnd.ms-fontobject image/x-icon; gip 压缩类型;
  • gzip_disable “msie6”; 关闭 IE6 的压缩。

最后这两项表示设置 zip 的压缩类型及是否关闭 客户端使用 IE6 浏览器请求过来的压缩,以上就是对文件压缩的典型配置,你可以根据具体情况做一些细节上的调整。

上面就是我们讲了基础优化,但是我们在使用 Nginx 作为代理入口的时候,对于网站优化有效的方式除了需要考虑基础配置优化外,更有用的方式就是优化缓存。用到缓存优化主要期望提高网站服务访问效率,减少服务端的性能使用。

缓存配置优化大致可以分为几个部分,分别是浏览器缓存优化代理缓存优化HTTPS SSL 缓存优化KV 服务缓存优化等。

首先我们需要了解一个问题,客户端如何直观的看到大部分缓存(浏览器缓存、代理缓存、ssl缓存)优化效果呢?推荐你用 Chrome 浏览器中的开发者工具,打开浏览器并点击视图-开发者工具。例如我们在 URL 地址栏中输入 www.baidu.com。这个时候我们会看到在 Network 标签栏中会出现对应的访问名称、路径。然后点击某一个路径,这时会在 Headers 中看到相应的头信息内容。

我们刚用浏览器打开 www..com 这个网站,表示浏览器发送一次 HTTP 请求,我们能看到服务端会返回给客户端代码经过渲染后的一个效果展示。如果点击右键查看源代码,这样就可以看到网站返回的 body 内容。除了 body 之外,一个完整的 HTTP 响应,服务端返回给客户端还有一部分就是 Response Headers,表示服务端返回给客户端的头信息内容。

上面就是一次 HTTP 请求和响应的过程,如果我们想判断服务端有没有做缓存,缓存的时间是多长。这些内容都会在头信息中通过服务端展示给客户端,我们可以在 Response Headers 查看头信息。

比如expires 头信息是控制在什么时间点生成的缓存元素,Cache Control 负责保存这个元素需要缓存多长时间。

通过使用Chrome 开发者工具我们就能够非常清晰的看到一次页面的打开效果,了解它的请求了是什么(请求头),服务端返回了什么( body及返回 头信息),通过这个工具详细的查看数据并对一个页面缓存情况进行分析,对于开发和运维人员而言是必须要掌握的。

缓存优化

如果缓存的元素在客户端,那么主要有浏览器缓存和 HTTPS 缓存,你可别认为缓存文件是在客户端,这两部分缓存都可以通过 Nginx 进行设置并作主要优化。

另外一个种类代理端的缓存(也就是缓存文件存放在代理服务的节点中),那 Nginx 作为反向代理服务的时候,可以支持代理缓存设置。

最后一个种类是将缓存文件放入后台服务(通过后台服务中程序逻辑来实现),例如我们可以将一部分数据通过此方式缓存,比如将用户最长查看的数据(网站中登录状态、连接数等)缓存到 Memcache、Redis 中,避免直接请求关系型数据库或其他服务,因为效率更高所以可以降低后端的延迟,也减少请求对数据库的依赖度,从而整个网站的性能也会有很大的提升。

如果只考虑缓存最优的话,那么参考以下三点即可:

  • 缓存越靠前越好,通常情况下整个网站的元素内容越靠前越好,也就是说能放在客户端的就放在客户端,而不要放到后端去频繁请求。
  • 缓存的数据越多越好,也就是能在本层级缓存的数据越多,就越可以减少对后端的请求。
  • 缓存的命中率越高越好,如果设置了很多缓存,但命中率不高,同样还是会造成穿透到后端访问,此时还需要考虑将缓存的命中率设置的越高,这时观察指标,会发现缓存效果越优。

通常而言,一个网站如果做了缓存优化可以比没做缓存优化的性能提升几倍以上。下面我们就来具体介绍一下 Nginx 如何来设置缓存。

浏览器缓存

浏览器缓存通常是缓存到客户端(如:浏览器、客户端app),这就是浏览器缓存。

对于浏览器这部分缓存数据,我们通常可以把静态元素,比如用户请求的图片、CSS 、JS 等元素缓存到客户端。这种缓存可以通过 Nginx配置中的 expires 配置项进行设置,expires 后面可以加具体的时间,也可以加对应的特定意义的数值,比如 -1 表示永久缓存,max 设置最大周期缓存(默认缓存周期为 10 年),需要做具体的时间的设置可以写入具体的时间周期,比如一个小时或是一天。

HTTPS 配置优化

现在几乎大部分网站都已经开启了 HTTPS,当开启https后客户端访问服务端打开一次浏览器,通过 HTTPS 方式会比 HTTP 请求握手会要增加很多次从而延迟也增加了。这时就需要考虑 HTTPS 是否有更好的优化方案来减少客户端和服务端请求。

上面是一个 HTTPS 请求过程,实际在进行 HTTPS 请求之前需要进行 TCP 的三次握手过程,而这里我们只是描述 HTTPS 的建连过程,客户端发送 hello 报文,服务端发送证书,客户端进行加密,服务端验证加密。这时开始进行服务端与客户端的传输。我们看到整个 HTTPS 建立增加了部分的证书加密的协商。

多次的连接对于用户和服务端而言,性能和延迟都会增加很多。并且如果每一次浏览器跟服务端断开连接以后,又要进行一次整体的建立连接的过程。为了减少客户端和服务端的断开重连过程,这时就需要在 Nginx 中配置 ssl_session_cache 发挥作用。

当浏览器跟服务端建立第一次加密证书验证的会话后,服务端会给客户端浏览器缓存一个 SessionKey,如果客户端跟服务端再次断开连接,这时浏览器就可以拿 SessionKey 直接跟服务端进行交互。只需要进行一次校验,就可以开始数据传输。我们看到有了 SessionKey 这种方式后,就可以避免浏览器跟服务端频繁的进行 HTTPS 会话的建联。

通过在 Nginx 中添加 ssl_session_cache 配置,配置中分配 Nginx 在处理 SSL 会话所需要开辟的共享内存的空间,我这里设置值为 10 MB,第二个参数就是设置 SSL SessionKey 的超时时间,这里设置的为 10 分钟,也就是每隔 10 分钟需要重新再进行一次建联,这是一个在服务端的超时时间。

好了,上面就是对 HTTPS 在会话层进行的缓存优化示例。

打开文件缓存

打开文件缓存设置在 Nginx 端,通常而言我们会把一些静态元素(如:JPG、CSS、GS)在代理端通过这种方式进行设置,这里 Nginx 缓存的是静态元素的元数据。那么把元数据缓存到 Nginx 端有什么好处?元数据的作用就是缓存打开用户所请求的静态元素的文件路径等信息,那么如果在本地频繁地查找之前请求过的静态元素文件而没有缓存元数据时效率比较低,而如果我们把一部分索引数据缓存到 Nginx 的 Cache 下,这种频繁访问就可以很大地提高访问效率。

我们来看 open_file_cache 具体的设置策略,max 表示最大能够缓存的文件个数,inactive 表示最少的用户使用次数。我们结合看一下,这个表示在 20 秒内最小需要使用两次。如果没有使用的话,就会把元数据删掉,也这就是一个淘汰元数据的策略。

open_file_cache_valid 是设置主动更新和检查的时间,表示每隔 30 秒检查缓存文件的元信息有没有对应的更新,如果有更新就需要去做对应的更新,它是一个更新的策略。

location / {
  index index.htm index.html;
  expires max;  
  open_file_cache max=1000 inactive=20s; 
  open_file_cache_valid 30s; 
  open_file_cache_min_uses 2; 
  open_file_cache_errors on;
}

代理缓存优化

最后就是代理缓存的优化了,代理缓存比较常见,比如说代理访问 PHP 后台服务并作缓存,也可以代理 JAVA 服务,缓存 JAVA 后台服务的返回数据,注意这里不局限于通过 http_proxy来作代理缓存,只要 Nginx 支持的代理模式(UWSGI、SGI)都可以设置代理缓存。你可以来看一下通过http_proxy设置的如下示例:

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60mlocation / {

        proxy_cache my_cache;

        …

}

proxy_cache_path 表示在本地分配哪个路径来存储并缓存后台返回数据;cache levels 表示存放文件的分层方式;my_cache:10m max_size=10g 分别表示是开辟一个名为my_cache共享块(用于统计访问次数)及缓存的单个文件的最大大小等。这些都是做对应的缓存在本地的文件目录相关属性的一些设置。另外一块的设置表示在proxy_cache 的时候,通过 location 引用到 cache 的名称。

代理缓存的特性是什么呢?首先通过 Nginx 作代理,可以支持实现动静态的分离,静态元素直接交给 Nginx 来处理,再把后端动态数据适当作缓存。通常做这种代理+缓存的架构,是能有效的提高整体网站的访问并发性能。

缓存使用注意问题

对于缓存的整体使用,之前说的缓存越多越好,越靠前越好,命中率越高越好,但是同时我们也需要综合考虑,并且注意缓存在使用时遇到的一些实际问题。

  • 文件更新策略问题。文件后端做缓存的配置策略的时候,要考虑到缓存的删除策略、更新策略,怎么保证它的后端数据更新对于前端用户能够及时的感知。
  • 缓存命中率失败给后端造成的瞬间压力。我们知道,当前端缓存的元素越多,命中率越高,对于后台的压力就越少。当一旦前端的缓存失效,或者某个节点迁移,或者某一部分的前端头信息失效,造成后端缓存瞬间压力,就可能会造成比较灾难性的后果。所以你在网站设计的时候也需要考虑,怎么去避免这种缓存失效?一旦前端缓存失效,你怎么保证后端服务的高可用而不受影响?
  • 多节点缓存一致性。你在做缓存设置的时候也需要考虑到,假设前端有很多个节点,保存同样的一部分内容的时候,怎么保证这些数据是能够达到一致性,这个时候也涉及缓存架构的设计,前端的缓存节点的更新策略,这些也是你在实际使用缓存时应该注意的问题。

总结

以上就是我们介绍的 Nginx 基础配置优化和缓存配置优化,下一次我们说一下 Nginx 的负载均衡优化配置。



(此处已添加圈子卡片,请到客户端查看)