零、绪
分析流程: 用户输入域名 -> 服务器接收 -> 浏览器显示整个网页
一、Nginx基础
是什么?
是高性能的web服务器, 是反向代理服务器, 是email服务器
Apache和Nginx哪个好(结论相对)?
相同机器配置, Nginx的并发数多
**Apache适于处理动态页面, Nginx适于处理静态页面
背景?
Nginx[Engine x] 俄罗斯程序员 2004年发布的开源的高性能的web服务器
搭建开发环境(CentOS)
Linux操作系统上(LAMP, LNMP)下载安装Nginx
实操版本: 稳定版中pre-built包(因为Nginx是c语言实现的, 使用源代码需要编译等等复杂的步骤)
Linux系统安装软件包的方式:
-
源代码方式
-
rpm包安装
-
yum原生安装
-
yum本地源安装(Nginx官方推荐安装)
使用yum下载/安装/启动Nginx步骤:
-
创建文件
$ sudo vi /etc/yum.repos.d/nginx.repo
-
输入字母i进入插入模式, 添加下面内容
[nginx]
name=nginx repo
gpgcheck=0
enabled=1
说明:
OS需要替换成centos
OSRELEASE需要替换成6或者7 (取决于CentOS的主版本号)
-
输入Esc键, 然后输入:wq, 保存退出
-
输入下面命令进行下载安装
$ sudo yum install nginx
-
启动nginx服务
$ sudo nginx
-
验证:
浏览器输入 localhost, 返回”Welcome to nginx”页面即可
或者使用下面命令查看nginx进程
$ ps aux | grep nginx
返回下面结果, 也表示成功启动nginx服务
Nginx其他常用命令:
linux命令添加-h, 或者--h或者-help参数查找其他命令
$ nginx -h
查看nginx安装版本(version)
$ nginx -v
判断/测试(test)nginx配置文件的语法是否正确
$ nginx -t
给主进程发送各种信息:
强制停止nginx服务(断电)
$ sudo nginx -s stop
退出停止nginx服务(优雅地gracefully)
$ sudo nginx -s quit
如果配置文件内容发生修改, 使之生效
$ sudo nginx -s reload
二、nginx 的编译安装
安装准备: nginx依赖于pcre库,要先安装pcre (缺少 xx.h头文件则安装 xx-devel)
*.devel软件一般都是C语言编写的一些头文件或cpp文件,往往是其他模块或这我们自己写的模块在编译时,需要依赖这些*-devel软件包
yum install pcre pcre-devel
cd /usr/local/src/
tar zxvf nginx-1.14.2.tar.gz
cd nginx-1.14.2
./configure --prefix=/usr/local/nginx
make && make install
启动:
cd /ulsr/local/nginx, 看到如下4个目录
./
....conf 配置文件
... html 网页文件
...logs 日志文件
...sbin 主要二进制程序
[root@localhost nginx]# ./sbin/nginx
若出现以下报错:
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
....
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
原因:不能绑定80端口,80端口已经被占用
(有时是自己装了apache,nginx等,还有更多情况是操作系统自带了apache并作为服务启动)
解决:把占用80端口的软件或服务关闭即可.
三、Nginx的信号控制
TERM, INT
|
Quick shutdown
|
QUIT
|
Graceful shutdown 优雅的关闭进程,即等请求结束后再关闭
|
HUP
|
Configuration reload ,Start the new worker processes with
a new configuration Gracefully shutdown the old worker processes
改变配置文件,平滑的重读配置文件
|
USR1
|
Reopen the log files 重读日志,在日志按月/日分割时有用
|
USR2
|
Upgrade Executable on the fly 平滑的升级
|
WINCH
|
Gracefully shutdown the worker processes 优雅关闭旧的进程(配合USR2来进行升级)
|
具体语法:
Kill -信号 选项 nginx的主进程号
Kill -HUP 4873
Kill -信号控制 `cat /xxx/path/log/nginx.pid`
Kil; -USR1 `cat /xxx/path/log/nginx.pid`
四、Nginx配置段
主配置文件语法构成:
1. 简单指令: 指令名 指令值1 指令值2;
2. 块指令
块指令名 {
简单指令;
简单指令;
}
指令作用域:
绝大多数指令不是特定属于某一个块的。同一指令放在不同层级的块中,其作用域也不相同。
一般,高一级块中的指令可以作用于自身所在的块和此块包含的所有低层级块。如果某个指令在两个不同层级的块中同时出现,则采用“就近原则”
简单指令包含四个:
1、user指令(理解):
语法:user user [group] ;
作用:设置nginx工作进程所属用户和群组,group群组如果省略, 值等于user的值。
补充说明:只有被设置的用户或者用户组成员才有权限启动 nginx 进程。该指令只能在全局块中配置。
1.1 默认配置: nginx工作进程所属用户和群组均为nginx(用户群组名)
1.2 软件启动 -> 进程 -> 进程之间关系
1.3 $ ps aux | grep nginx命令, 第一列root, 表示该进程的所属用户是root(只有root用户以及拥有超级用户权限的用户才可以操作该进程); 第二列为进程ID号
-
-
-
master process nginx: nginx的主进程; 分配客户端请求给工作进程处理
-
worker process: 工作进程(子进程), 所属用户就是第一列nginx; 处理客户端请求的进程
-
kill某个子进程, 对web服务几乎没有影响
-
kill主进程, worker子进程几乎做不了什么
2、worker_process指令(***):
语法:worker_process number | auto ;
作用:设置nginx工作进程的个数; 影响nginx的性能(处理请求的并发数)
补充说明:该指令只能在全局设置。
2.1 默认:
2.2 设置工作进程的个数依据原则:推荐设置为可用CPU核的个数
2.3 修改这个指令: 从1改成3(主配置文件指令发生变化), 使之生效, 需要执行下面的命令
$ sudo vi /etc/nginx/nginx.conf
保存退出(esc键; :wq)
$ sudo nginx -s reload
2.4 如果kill nginx的工作进程(子进程), 系统自动按照worker_processes指令设置的值, 重新创建新的工作进程; 如果kill掉主进程, web服务器无法处理客户端的请求
$ sudo kill -9 进程ID
$ ps aux | grep nginx
2.5 如果kill命令没有-9参数, 表示不仅仅kill掉该进程4242(Nginx主进程id), 还包含所有子进程
3、error_log指令:
语法:error_log file | stderr [ debug | info | notice | warn | error | crit | alert | emerg ] ;
作用:设置nginx错误日志的路径,文件名以及日志级别;记录nginx进程相关的日志信息(启动, 信号, bind端口号等等)。
补充说明:全局、http块、server块中都可以配置。且指定的文件对于运行nginx进程的用户要有写权限。
3.1 日志级别: 级别从低到高, 级别越低, 信息量越大
debug: 开发阶段, 查看更多信息,在编译时使用 --with-debug 开启。
debug, info, notice, warn, error, crit, alert, 或者 emerg。
设置某一级别后,比这一级高的日志也会被记录。
4、pid指令:
语法:pid filepath ;
作用:设置nginx主进程的 id。
补充说明:文件可以为绝对路径,也可以是 nginx 安装目录为根目录的行对路径。且一定要包含文件名,该指令只能在全局设置。
4.1 思路: 自动化(shell/perl/python)的读取该文件内容(id), 直接调用kill命令, 直接kill掉所有进程
块指令包含两个:
1、events块指令
1.1 worker_connections指令(***):
语法:worker_connections number ;
作用:设置一个工作进程可以开启的最大连接数(理论上)是1024个。
补充说明:该指令只能在 events 块中配置。
理论上nginx一共开启的连接数 = 1024 * worker_processes值(3)
思考: HTTP中请求数和上面的连接数是一回事吗?
答: 不是一回事; 连接数connection: TCP连接; 请求数request; 建立一次TCP连接, 发送多次请求
HTTP协议中Connection: keep-alive保持一段时间的连接
Nginx默认设置的超时timeout时间为65s(秒); 具体流程图可以查看附录中的第3部分.
keepalive_timeout 指令,可在http、server、location中配置。
keepalive_requests指令:
语法:keepalive_requests number ;
作用:限制某一连接发送请求次数。
补充说明:发送请求次数,可在http、server、location中配置。
1.2 accept_mutex指令:
语法:accept_mutex on | off ;
作用:某一时刻只有一个网络连接到来时,多个睡眠进程会被同时叫醒,但只有一个进程可获得连接,称为“惊群”现象。当期设置为开启时,将会对 多个nginx 进程接收连接进行序列化,防止多个进程对连接争抢。
补充说明:默认为开启状态,其只能在 events 块中配置。
1.3 use指令:
语法:use method ;
作用:事件驱动模型选择。
说明:method可选:select、poll、kqueue、epoll、rtsig、/dev/poll 以及 eventport。只能在events块中配置。
2、http块指令
2.1 access_log指令: 设置前端访问log路径以及格式对应名字。
2.2 log_format指令: 设置accee.log文件内日志消息格式。
格式:access_log path [ format_name [buffer=size] ] ;
格式:log_format name string... ;
作用:记录nginx服务器提供服务过程应答前端请求的日志。
补充说明:access_log可以在 http 块、server块、location块中配置,log_format只能在http块中配置。
log_format 格式,变量的名称用双引号括起来,string整体用单引号括起来:
access.log 日志信息内容如下:
2.3 如何修改access_log格式?
2.3.1 找所有以$开头变量
2.4 include指令:
语法:include file ;
作用:引入外部指令目录下的某个文件(配置); 如,引入mime.types文件(面试点)
补充说明:支持相对路径引入。该指令可以放在配置文件的任何地方。mime.types 文件是主配置文件应用的第三方文件。
mime.types 映射关系: mime类型和该类型对应的文件扩展名;Apache相关配置查看下面附录部分
Accept: text/*, text/html; 指定客户端请求资源的mime类型;
Content-Type: text/html; 服务器返回的mime类型text/html, 文件名xxxx.html / xxxx.htm
2.5 default_type指令:
语法:default_type mime-type ;
作用:如果客户端请求的资源mime类型无法mime.types内找到映射, 指定一个默认的资源类型。
补充说明:浏览器为区分资源类型,需要使用 MIME Type。MIME Type是网络资源的媒体类型。nginx 需要能够识别前端请求的资源类型。
2.5.1 application/octet-stream: 二进制字节流类型; 无法找到的类型, 认为是程序(可执行文件),浏览器无法显示/解析, 直接下载。
mime对应流程图:
mime类型流程描述:
描述: web服务器会为所有的HTTP对象数据附加一个MIME类型, 当web浏览器从web服务器获取一个资源/对象时, 会查看服务器mime.types中存储的相关类型, 浏览器依据服务器返回的Content-Type字段的值(mime类型), 决定如何处理
a、 客户端请求一个不存在的类型: test.aaa
a. Nginx web服务器包含test.aaa
b. localhost/test.aaa 放在Nginx配置的根目录下
1) 子配置文件: /etc/nginx/conf.d/default.conf
2) 根目录: /usr/share /nginx /html/
b 、正确性: 客户端看到下载test.aaa资源(弹出对话框)
2.6 sendfile 指令:
语法:sendfile on | off ;
语法:sendfile_max_chunk size ;
补充说明:可在http 、server 、location 中配置。
五、全局区
worker_processes 1; // 有1个工作的子进程,可以自行修改,但太大无益,因为要争夺CPU,一般设置为 CPU数*核数
events {
// 一般是配置nginx连接的特性
// 如1个word能同时允许多少连接
worker_connections 1024; // 这是指 一个子进程最大允许连1024个连接
}
http { //这是配置http服务器的主要段
server 1 { // 这是虚拟主机段
listen 80; // 网络监听,可监听IP地址、端口。如 192.168.1.10、192.168.1.10:8080、*:8080
server_name xxx ...; // 可以有多个,以第一个为主,可以使用 *(只能用在三级域名的首段或者尾段)、正则(~标记打头)
error_page code ... [=[response]] uri; // 设置网站错误页面。可在http、server、location块中配置。uri可以是路径(安装目录下的html为更目录的相对路径)或 网站地址。response表示把code转为response。如果不想用相对路径,可在定义一个location指令定向错误页面到新的路径root下,如下面的 /www/404.html。
location /404.html{ //定位,对除虚拟主机名称(或IP)之外的字符串进行匹配,对特殊的路径或文件再次定位 ,如 image目录单独处理、如.php单独处理
root /www; // 接收请求后查找资源的根目录路径,可包含nginx 服务器预设的大多是变量。可在http、server、location中配置。
alias xxx: // 改变location接收到的 URI 的请求路径。
index index.html ... ; // 设置网站的默认首页。可设置多个,空格隔开
allow all; // 访问权限
}
}
server 2 {
error_page 404 /404.html;
}
server 3 {
error_page 410 =301 /empty.gif; // 服务器产生401的http消息时,使用 nginx安装路径/html/empty.gif 返回给客户端 301 消息
}
...
server n {
error_page 403 http://xxxx/403.html;
}
}
例子1: 基于域名的虚拟主机
server {
listen 80; # 监听端口
server_name a.com; # 监听域名
location / {
root /var/www/a.com; # 根目录定位,也可以是相对目录(相对于nginx程序目录)
index index.html; # 设置默认请求主页面文件名
}
}
例子2: 基于端口的虚拟主机配置
server {
listen 8080;
server_name 192.168.1.204;
location / {
root /var/www/html8080;
index index.html;
}
}
虚拟机:又称虚拟服务器、主机空间或网页空间,是一种技术,主要为了节省互联网服务器硬件资源。
将一台服务器的某项或者全部服务内容逻辑划分为多个服务单位,对外表现为多个服务器,从而充分利用服务器硬件资源。从用户角度来看,一台虚拟主机和一台独立的硬件主机完全一样。
可以避免为每一个要运行的网站提供单独的Nginx服务器,也无须为每个网站对应运行一组nginx进程。即一台服务器上只运行一组nginx进程,就可以运行多个网站。
server_name 匹配优先级:
a、对于匹配方式不同,从上往下:
1、准确匹配 server_name
2、通配符在开始时匹配 server_name 成功
3、通配符在结尾时匹配 server_name 成功
4、正则表达式匹配 server_name 成功
b、在以上四种匹配方式中,若被同一优先级匹配多次,则以第一次为准
六、日志管理
我们观察nginx的server段,可以看到如下类似信息
#access_log logs/host.access.log main;
这说明 该server, 它的访问日志的文件是 logs/host.access.log ,使用的格式”main”格式。
除了main格式,你可以自定义其他格式:
main格式是什么?
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
main格式是我们定义好一种日志的格式,并起个名字,便于引用.
以上面的例子, main类型的日志,记录的 remote_addr.... http_x_forwarded_for等选项.
1: 日志格式 是指记录哪些选项
默认的日志格式: main
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
如默认的main日志格式,记录这么几项
远程IP- 远程用户/用户时间 请求方法(如GET/POST) 请求体body长度 referer来源信息
http-user-agent 用户代理/蜘蛛 ,被转发的请求的原始IP
http_x_forwarded_for:在经过代理时,代理把你的本来IP加在此头信息中,传输你的原始IP
2: 声明一个独特的log_format并命名
log_format mylog '$remote_addr- "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
在下面的server/location,我们就可以引用 mylog
在server段中,这样来声明:
Nginx允许针对不同的server做不同的Log ,(有的web服务器不支持,如lighttp)
access_log logs/access_8080.log mylog;
声明log log位置 log格式;
实际应用: shell+定时任务+nginx信号管理,完成日志按日期存储
分析思路:
凌晨00:00:01,把昨天的日志重命名,放在相应的目录下
再USR1信息号控制nginx重新生成新的日志文件
具体脚本:
#!/bin/bash
base_path='/usr/local/nginx/logs'
log_path=$(date -d yesterday +"%Y%m")
day=$(date -d yesterday +"%d")
mkdir -p $base_path/$log_path
mv $base_path/access.log $base_path/$log_path/access_$day.log
#echo $base_path/$log_path/access_$day.log
kill -USR1 `cat /usr/local/nginx/logs/nginx.pid`
定时任务
Crontab 编辑定时任务
01 00 * * * /xxx/path/b.sh 每天0时1分(建议在02-04点之间,系统负载小)
七、location 语法
location 有”定位”的意思, 根据Uri来进行不同的定位.
在虚拟主机的配置中,是必不可少的,location可以把网站的不同部分,定位到不同的处理方式上.
比如, 碰到.php, 如何调用PHP解释器? --这时就需要location
location 的语法:
location [ = | ~ | ~* | ^~ ] patt {
}
patt 是待匹配的字符串,可是包含或不包含正则的字符串。如,/index.php 或 .php$ 。
匹配流程:在不添加选项时,在server中的多个location中搜索是否有 patt 和请求字符串匹配,如果有多个,记录匹配度最高的一个。然后在用 location块中的正则 patt 和请求字符串匹配,当第一个正则匹配到后,结束搜索,并使用这个location块处理请求,若正则匹配失败,就用刚才记录的最高匹配的location处理请求。
"=" :要求请求字符串与 patt 严格匹配。如果成功匹配,就停止继续向下搜索并处理此请求。
“~”:表示 patt 包含正则表达式,并区分大小写。
“~*”:表示 patt 包含正则表达式,并不区分大小写。
“^~”:表示 找到 patt 和请求字符串匹配度最高的location后,立即使用此 location 处理请求,而不再使用location块中的正则 patt 和请求字符串做匹配。注意其还会对 编码 过 URL 字符串进行解码。
中括号可以不写任何参数,此时称为一般匹配
也可以写参数
因此,大类型可以分为3种
location = patt {} [精准匹配]
location patt {} [一般匹配]
location ~ patt {} [正则匹配]
如何发挥作用?:
首先看有没有精准匹配,如果有,则停止匹配过程.
比如,
location = patt {
config A
}
如果 $uri == patt,匹配成功,使用configA。
location = / {
root /var/www/html/;
index index.htm index.html;
}
location / {
root /usr/local/nginx/html;
index index.html index.htm;
}
定位流程是:
1: 精准匹配中 ”/” ,得到index页为 index.htm
2: 再次访问 /index.htm , 此次内部转跳uri已经是”/index.htm” ,
根目录为/usr/local/nginx/html
3: 最终结果,访问了 /usr/local/nginx/html/index.htm
再来看,正则也来参与:
location / {
root /usr/local/nginx/html;
index index.html index.htm;
}
location ~ image {
root /var/www/image;
index index.html;
}
此时, “/” 与 ”/image/logo.png” 匹配,
同时,”image”正则 与”image/logo.png”也能匹配,
谁发挥作用?
正则表达式的成果将会使用。覆盖 “/” 的匹配
图片真正会访问 /var/www/image/logo.png
location / {
root /usr/local/nginx/html;
index index.html index.htm;
}
location /foo {
root /var/www/html;
index index.html;
}
对于uri “/foo”, 两个location的patt,都能匹配他们
即 ‘/’ 能从左前缀匹配 ‘/foo’, ‘/foo’也能左前缀匹配’/foo’,
此时, 真正访问 /var/www/html/index.html
原因:’/foo’匹配的更长,因此使用之.;
八、rewrite 重写
rewrite 用于实现URL的重写,比如在改变网站结构后,无需用户客户端用户修改原来的书签,也无需其他网站修改对我们网站的友情链接。
nginx的rewrite功能依赖PCRE的支持,在编译之前,需要安装PCRE库,并且支持nginx预设变量。
nginx使用 ngx_http_rewrite_module 模块解析(标准http模块)和处理rewrite功能的相关配置。
地址重写:google.cn在服务器中被改变为www.google.com的过程。
地址转发:将一个域名指到另一个已有站点的过程。
区别:
- 地址转发后客户端浏览器中的地址显示是不变的;而地址重写后客户端浏览器地址栏中的地址改变为服务器选择确定的地址。
- 在一次转发整个过程中,只产生一次网路请求;二一次地址重写一般会产生两次请求。
- 地址转发一般发送在同一个项目内;而地址重写没有限制。
- 地址转发的页面可以不用全路径表示,而地址重写必须使用完整的路径
- 地址转发可以将客户端的reques范围内属性传递给新的页面,但地址重写不可以
- 地址转发的速度较重定向快
重写中用到的指令:
rewrite_log 指令:
作用:是否开启URL重写日志输出,以notice级别输出到error_log中,默认off
语法:rewrite_log on | off ;
If 指令:
作用:设定条件,再进行重写,用来支持条件判断,并根据条件判断结果选择不同的nginx配置,可在 server 或 location 块中配置。
语法:
If (条件) {
重写模式
}
说明:变量的值为空字符串或者以“0”开头的任意字符串(这里字符串不需要加引号),都认为false。
正则表达式一般不需要加引号,但如果含有 } 或者 ; 字符时,必须要给整个正则表达式添加引号。
条件又怎么写?
答:3种写法
1: “=” 来判断相等, 用于字符串比较
2: “~” 用正则来匹配(此处的正则区分大小写)
~* 不区分大小写的正则
3: -f -d -e -x来判断是否为文件,为目录,是否存在,是否可执行
例子:
if ($remote_addr = 192.168.1.100) {
return 403;
}
if ($http_user_agent ~ MSIE) {
rewrite ^.*$ /ie.htm;
break; #(不break会循环重定向)
}
if (!-e $document_root$fastcgi_script_name) {
rewrite ^.*$ /404.html break;
}
注, 此处还要加break。
set 指令:
作用:设置变量
语法:set variable value ;
说明:variable 变量名,要使用 $ 作为第一个字符,且不能与 nginx预设的全局变量名同名
value 变量值,可以是字符串、其他变量或变量组合等。
return 指令:
作用:完成对请求的处理,返回状态码,处于该指令后面的所有配置都无效。可在 server、location、if 块中。
语法:return [text]; 或 return code URL ; 或 return URL ;
说明:code 为返回给客户端的HTTP状态码,0~999的任意状态码。非标准的 444 可强制关闭服务器与客户端的连接而不返回客户端任何消息。
text 返回给客户端的响应体内容,支持变量的使用
URL 返回给客户端的URL地址。
break 指令;
作用:跳出rewrite,与该指令处于同一作用域的配置,位于它之前的生效,之后的无效,即回到上一层作用域继续向下读取配置。可在server、location、if 块中。
语法:break ;
rewrite 指令:
作用:通过正则表达式来重写URI,可以同时存在一个或者多个指令,安装顺序依次匹配和处理。可在 server、location块中配置。
语法:rewrite regex replacement [flag] ;
说明:replacement 匹配成功后用于替换URI中被截取内容的字符串。
flag:用于设置 rewrite 对 URI 的处理行为。
- last 该标志重写后的URI重新在 server 块中执行,为重写后的URi提供转入其他 location 块的机会。
- break 重写后的URI在当前的 location 块中执行,不会将新的URI转向到其他 location块。
- redirect 重写后返回给客户端,302
- permanent 重写后返回给客户端,301
rewrite 就收到的URI不包含 host 地址。请求的get参数也是获取不到的(可用nginx全局变量 $request_uri ?)。
我们观察访问日志,日志中显示的访问路径,依然是GET /dsafsd.html HTTP/1.1
提示: 服务器内部的rewrite和302跳转不一样.
跳转的话URL都变了,变成重新http请求404.html,而内部rewrite,上下文没变,就是说 fastcgi_script_name 仍然是 dsafsd.html,因此 会循环重定向,需要用break
set 是设置变量用的, 可以用来达到多条件判断时作标志用。
达到apache下的 rewrite_condition的效果
如下:判断IE并重写,且不用break; 我们用set变量来达到目的
if ($http_user_agent ~* msie) {
set $isie 1;
}
if ($fastcgi_script_name = ie.html) {
set $isie 0;
}
if ($isie 1) {
rewrite ^.*$ ie.html;
}
Rewrite语法:
Rewrite 正则表达式 定向后的位置 模式
Goods-3.html ----> Goods.php?goods_id=3
goods-([d]+).html ---> goods.php?goods_id =$1
location /ecshop {
index index.php;
rewrite goods-([d]+).html$ /ecshop/goods.php?id=$1;
rewrite article-([d]+).html$ /ecshop/article.php?id=$1;
rewrite category-(d+)-b(d+).html /ecshop/category.php?id=$1&brand=$2;
rewrite category-(d+)-b(d+)-min(d+)-max(d+)-attr([d.]+).html /ecshop/category.php?id=$1&brand=$2&price_min=$3&price_max=$4&filter_attr=$5;
rewrite category-(d+)-b(d+)-min(d+)-max(d+)-attr([d+.])-(d+)-([^-]+)-([^-]+).html /ecshop/category.php?id=$1&brand=$2&price_min=$3&price_max=$4&filter_attr=$5&page=$6&sort=$7&order=$8;
}
注意:用url重写时,正则里如果有”{}”,正则要用双引号包起来
防盗链:
location ~* ^.+.(gif | jpg | png | swf | flv | rar | zip) $
{
valid_referers none blocked server_names *.myweb.name;
if ($invalid_referer) {
rewrite ^/ http://www.myweb.com/images/forbidden.png;
}
}
valid_referers none | blocked | server_names | string ...;
作用:用来获取 referer 头域中的值,并且根据该值得请求给 nginx 全局变量 $invalid_refer 赋值。若没有符合 valid_referers 指令配置的值,则赋值为 1。
说明:none 检查referer头域不存在。
blocked 头域的值被防火墙或者代理服务器删除或伪装的情况,该情况下referer头域的值不以 http 或 https 开头
server_names 设置一个或多个URL,检测是否是其中的一个
九、nginx+php的编译
apache一般是把php当做自己的一个模块来启动的。
而nginx则是把http请求变量(如get,user_agent等)转发给 php进程(两者平级),即php独立进程与nginx进行通信,称为 fastcgi 运行方式。
因此,为apache所编译的php,是不能用于nginx的.
注意:我们编译的PHP 要有如下功能:
连接mysql,,gd, ttf,以 fpm(fascgi) 方式运行
./configure --prefix=/usr/local/fastphp
--with-mysql=mysqlnd
--enable-mysqlnd
--with-gd
--enable-gd-native-ttf
--enable-gd-jis-conv
--enable-fpm
编译完毕php后:
nginx+php 的配置比较简单,核心就一句话----把请求的信息转发给9000端口的PHP进程,
让PHP进程处理 指定目录下的PHP文件.
如下例子:
location ~ .php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; # conf目录下的文件,定义了一些fastcgi参数
}
1:碰到php文件,
2: 把根目录定位到 html,
3: 把请求上下文转交给9000端口PHP进程,
4: 并告诉PHP进程,当前的脚本是 $document_root$fastcgi_scriptname
(注:PHP会去找这个脚本并处理,所以脚本的位置要指对)网页内容的压缩编码与传输速度优化
十、Nginx支持gzip压缩(**)
相关指令可配置在 http、server、location块中,Nginx服务器通过ngx_http_gzip_module模块、ngx_http_gzip_static_module模块和ngx_http_gunzip_module模块对这些指令进行解析和处理。
一、简单实例:
-
HTTP请求: Accept-Encoding域
-
HTTP响应: Content-Encoding域
-
Nginx如何支持压缩gzip(是nginx模块) : nginx的主配置文件: 什么类型资源需要压缩; 多大才需要压缩, 缓存大小等等, 步骤如下:
3.1 配置文件修改如下:
-
gzip on: 打开gzip压缩模块
-
gzip_buffers: 设置gzip压缩使用系统缓存个数和每页缓存大小
-
gzip_comp_level: 设置压缩级别, 取值范围为1 ~ 9, 值越小, 压缩速度越快, 压缩程度越低
-
gzip_min_length: 设置压缩最小大小(单位: bytes字节)
-
gzip_types: 设置压缩的mime类型
3.2 reload nginx配置文件
$ sudo nginx -s reload
3.3 验证:
-
创建test.css文件, 任意添加内容
$ sudo vi /usr/share/nginx/html/test.css
-
命令行输入下面命令:
$ curl -I -H "Accept-Encoding:gzip" "http://127.0.0.1/test.css"
-
返回结果(红色框内容)表明设置成功
==================================================
请求:
Accept-Encoding:gzip,deflate,sdch
响应:
Content-Encoding:gzip
Content-Length:36093
再把页面另存下来,观察,约10W字节,实际传输的36093字节
原因-------就在于gzip压缩上.
原理:
浏览器---请求----> 声明可以接受 gzip压缩 或 deflate压缩 或compress 或 sdch压缩
从http协议的角度看--请求头 声明 acceopt-encoding: gzip deflate sdch (是指压缩算法,其中sdch是google倡导的一种压缩方式,目前支持的服务器尚不多)
服务器-->回应---把内容用gzip方式压缩---->发给浏览器
浏览<-----解码gzip-----接收gzip压缩内容----
推算一下节省的带宽:
2*10^8 * 9*10^4 字节 ==
2*10^8 * 9 * 10^4 * 10^-9 = 12*K*G = 18T
节省的带宽是非常惊人的
二、由ngx_http_gzip_module模块处理的9个指令:
主要负责Gzip功能的开启和设置,对响应数据进行在线实时压缩。
gzip on | off ; #是否开启gzip,只有on时,以下指令设置才能生效
gzip_buffers number size ; #设置压缩文件使用缓冲空间的大小(number压缩在内存中缓冲几块? 每块多大? 需向系统申请 number*size 大小的空间用于存储压缩数据,默认128 ),如,32 4K | 16 8K
gzip_comp_level [1-9] #推荐6 压缩级别(级别越高,压的越小,越浪费CPU计算资源,越低效率越高,默认为1)
gzip_disable regex ... #针对不同种类客户端发起的请求,选择性关闭开启gzip功能。regex正则匹配UA(user-agent,客户端浏览器标志),什么样的Uri不进行gzip
gzip_min_length length # 开始压缩的最小长度(再小就不要压缩了,意义不在,单位: bytes字节,默认20,推荐1024),长度大小通过http响应头的content-length指令获取,若使用chunk动态压缩或其不存在,则该指令无效。
gzip_http_version 1.0 | 1.1 # 开始压缩的http协议版本(可以不设置,目前几乎全是1.1协议,默认1.1)
gzip_proxied off | expired | no-cache | no-store | private | no_last_modified | no_etag | auth | any ... # 设置请求者代理服务器该如何缓存内容,nginx做反向代理时有效,前提是在后端服务器返回的响应页面头部中,Requess部分包含用于通知代理服务器的Via头域。
- off:关闭nginx服务器对后端服务器返回结果的gzip压缩功能,是默认设置
- expired:当后端服务器响应页面头部包含用于指示响应数据过期时间的 expired头域时,启用对响应数据的gzip压缩
- no-cache:后端服务器 Cache-Control :no-cache时,启用gizp
- no-store:后端服务器 Cache-Control:no-store时,启用gzip
- private:后端服务器 Cache-Control:private时,启用gzip
- no_last_modified:后端服务器响应页头部不包含 最后修改时间的 Last_Modified 头域时,启用
- no_etag:后端服务器响应页头部不包含 标识被请求变量的实体值的 ETAG 头域时,启用
- auth:后端服务器包含 http 授权证书 authorization 头域时,启用
- any:无条件启用
gzip_types mime-type ...; # 对哪些mime类型的文件用压缩,默认 text/html,如 text/plain application/xml text/css text/plain
gzip_vary on|off # 是否传输gzip压缩标志,Vary:Accept-Encoding 告诉接收方发送的数据进行了压缩处理,默认是off,其实开可以通过 add_header 指令达到同样效果,如 add_header Vary Accept-Encoding gzip;
三、由ngx_http_gzip_static_moduel模块处理的指令:
主要负责搜索和发送经过gzip功能压缩的数据,这些数据以 .gz 格式存储在服务器上。如果客户请求的数据之前被压缩过,并且客户端支持 gzip则直接返回。
该模块是nginx的可选http模块,编译时加上 --with-http_gzip_static_module
四、由ngx_http_gunzip_module模块处理的指令:
针对不支持gzip压缩数据处理的客户端浏览器,对压缩数据进行解压处理。
该模块是nginx的可选http模块,编译时加上 --with-http_gunzip_module
gunzip_static on | off ; # 开启或关闭,默认是关闭
gunzip_buffers number size ; # 设置nginx服务器解压缩gzip文件使用缓存空间的大小,默认128字节
注意:
图片/mp3这样的二进制文件,不必压缩
因为压缩率比较小,比如100->80字节,而且压缩也是耗费CPU资源的。
比较小的文件不必压缩, nginx的缓存设置 提高网站性能
对于网站的图片,尤其是新闻站, 图片一旦发布, 改动的可能是非常小的.我们希望 能否在用户访问一次后, 图片缓存在用户的浏览器端,且时间比较长的缓存。可以, 用到 nginx的expires指令设置 .
nginx中设置过期时间,非常简单,
在location或if段里,来写.
格式 expires 30s;
expires 30m;
expires 2h;
expires 30d;
(注意:服务器的日期要准确,如果服务器的日期落后于实际日期,可能导致缓存失效)
另: 304 也是一种很好的缓存手段
原理是: 服务器响应文件内容时,同时响应 etag 标签(内容的签名,内容一变,他也变)和 last_modified_since 2个标签值。
浏览器下次去请求时,头信息发送这两个标签, 服务器检测文件有没有发生变化,如无,直接头信息返回 etag,last_modified_since
浏览器知道内容无改变,于是直接调用本地缓存。
这个过程,也请求了服务器,但是传着的内容极少.
对于变化周期较短的,如静态html,js,css,比较适于用这个方式
对应关系:
etag —— if-none-match
last-modified —— if-modified-since
实际上浏览器输入 url 之后敲下回车就是先看本地 cache-control、expires 的情况,刷新(F5)就是忽略先看本地 cache-control、expires 的情况,带上条件 If-None-Match、If-Modified-Since,强制刷新(Ctrl + F5)就是不带条件的访问。
十一、Nginx负载均衡Load Balance
-
术语:
代理Proxy: 也称为网络代理, 是一种特殊的网络服务, 允许一个网络终端通过该服务与另一个网络终端进行连接
正向代理服务器:
-
描述: 通常就是正向代理,隐藏真实请求客户端,服务器不清楚真正的客户端是谁.
-
截图:
反向代理服务器(负载均衡):
-
描述: 反向代理服务器隐藏了真实的服务器端, 客户端直接发送请求给反向代理服务器, 由proxy反向代理服务器通过设置的负载均衡算法, 交由其他web服务器处理
-
截图:
Nginx负载均衡截图:
-
Nginx中负载均衡一般配置, 涉及默认四个负载均衡算法
nginx子配置文件中, http块指令
http {
upstream cluster {
server server_name或者IP地址;
server server_name或者IP地址;
server server_name或者IP地址;
}
location / {
proxy_pass: http://域名;
}
}
默认包含四个负载均衡算法:
-
Round Robin(默认): 轮训调度算法; 依次给服务器发送请求
upstream cluster {
server server_name或者IP地址;
server server_name或者IP地址;
server server_name或者IP地址;
}
-
最少连接数算法: 找哪台机器的连接数最少给谁
upstream cluster {
least_conn;
server server_name或者IP地址;
server server_name或者IP地址;
server server_name或者IP地址;
}
-
权重算法: 每台服务器指定一个权重数; 给性能好的服务器指定较大的权重(处理请求多)
upstream cluster {
server server_name或者IP地址 weight=100;
server server_name或者IP地址 weight=50;
server server_name或者IP地址 weight=10;
}
-
IP-Hash散列算法: 某些客户端直接发送请求给某台/某组服务器
upstream cluster {
ip_hash;
server server_name或者IP地址;
server server_name或者IP地址;
server server_name或者IP地址;
}
-
实际: 上述多个算法结合使用, 依据测试结果
-
实际方案: 结合算法+内部实现算法(自定义需求)
- Nginx反向代理服务器(负载均衡) à N个Apache提供web服务; LAMP, LNMP, LNAMP
nginx反向代理服务器+负载均衡实例:
支持两个用法 1个proxy, 1个upstream,分别用来做反向代理,负载均衡
以反向代理为例, nginx不自己处理php的相关请求,而是把php的相关请求转发给apache来处理。
----这不就是传说的”动静分离”,动静分离不是一个严谨的说法,叫反向代理比较规范.
反向代理后端如果有多台服务器,自然可形成负载均衡,
但proxy_pass如何指向多台服务器?
把多台服务器用 upstream指定绑定在一起并起个组名,
然后proxy_pass指向该组
默认的均衡的算法很简单,就是针对后端服务器的顺序,逐个请求.
也有其他负载均衡算法,如一致性哈希,需要安装第3方模块.
反向代理导致了后端服务器的IP,为前端服务器的IP。而不是客户真正的IP,怎么办?
十二、Nginx具体的压缩配置
常用以下配置
gzip on|off
gzip_buffers 4K|8K 缓冲(和硬盘块相当)
gzip_comp_level [1-9] 推荐6
gzip_disable 正则匹配如User-Agent,针对古老浏览器不压缩
gzip_min_length 200
gzip_http_version 1.0|1.1
gzip_types text/plain , application/xml (各mime之间,一定要加空格,不是逗号)
gzip_vary on|off
Vary的作用:
Vary是用来标志缓存的依据.
如上图: 看出,这个新闻页面由
思考:
1: 如果2个人,一个浏览器支持gzip,一个浏览器不支持gzip
2个同时请求同个页面, chinaCache缓存压缩后,还是未压缩的?
2: 如果1人,再次请求页面,chinaCache返回压缩后的缓存内容,还是压缩前的缓存内容?
这个时候 Vary的作用体现出来.
即------缓存的内容受 Accept-Encoding头信息的影响.
所以如果--
请求时,不支持gzip, 缓存服务器将会生成一份未gzip的内容.
请求时,支持gzip, 缓存服务器将会生成一份gzip的内容.
下次再请求时, 缓存服务器会考虑客户端的Accept-Encoding因素,并合理的返回信息
Nginx对于图片,js等静态文件的缓存设置
注:这个缓存是指针对浏览器所做的缓存,不是指服务器端的数据缓存.
主要知识点: location expires指令
location ~ .(jpg|jpeg|png|gif)$ {
expires 1d;
}
location ~ .js$ {
expires 1h;
}
设置并载入新配置文件,用firebug观察,
会发现 图片内容,没有再次产生新的请求,原因--利用了本地缓存的效果.
注: 在大型的新闻站,或文章站中,图片变动的可能性很小,建议做1周左右的缓存
Js,css等小时级的缓存.
如果信息流动比较快,也可以不用expires指令,
用last_modified, etag功能(主流的web服务器都支持这2个头信息)
原理是:
响应: 计算响应内容的签名, etag 和 上次修改时间
请求: 发送 etatg, If-Modified-Since 头信息.
服务器收到后,判断etag是否一致, 最后修改时间是否大于if-Modifiled-Since
如果监测到服务器的内容有变化,则返回304,
浏览器就知道,内容没变,直接用缓存.
304 比起上面的expires 指令
多了1次请求,
但是比200状态,少了传输内容.
Nginx反向代理与负载均衡
正向代理
反向代理
具体的负载均衡的方式
注意:负载均衡是一种方案,实现办法有DNS轮询,
如下图,DNS服务器允许一个域名有多个A记录,
那么在用户访问时,一般按地域返回一个较近的解析记录.
这样,全国不同的地区的用户,看到的163的主页,来自不同的服务器.
第二步: 当 解析出结果,比如浏览器连接60.217时,
这台主机后面还有N台,也要做负载均衡.
1: 硬件上做负载均衡, F5 BIG-IP ,硬件负载均衡(很贵).
直接从TCP/IP的底层协议上,直接做数据包的中转.
2: 软件负载均衡, LVS
3: 反向代理+负载均衡
反向代理与keep-alive连接
Nginx反向代理设置
例: 把图片重写到 8080端口(既然能写到8080端口,就意味着可以写到其他独立服务器上)
location ~ .(jpg|jpeg|png|gif)$ {
proxy_pass http://192.168.1.204:8080;
expires 1d;
}
集群与均衡-----如果后端的服务器非常多,该如何写? 又如何均匀的分发任务
nginx 与memcached的组合
用法: nginx响应请求时,直接请求memcached,
如果没有相应的内容,再回调PHP页面,去查询database,并写入memcached.
分析: memcached是k/v存储, key-->value,
nginx请求memecached时,用什么做key?
一般用 uri arg 做key, 如 /abc.php?id=3
十三、Nginx 第三方模块的安装
以ngx_http_php_memcache_standard_balancer-master为例
1:解压 到 path/ngx_module
配置:
./configure --prefix=/xxx/xxx --add_module=/path/ngx_module
编译 安装
Make && make install
配置memcache集群
upstream memserver { 把用到的memcached节点,声明在一个组里
hash_key $request_uri; // hash计算时的依据,以uri做依据来hash
server localhost:11211;
server localhost:11212;
}
Location里
location / {
# root html;
set $memcached_key $uri;
memcached_pass memserver; // memserver为上面的memcache节点的名称
error_page 404 /writemem.php;
index index.php index.html index.htm;
}
在nginx中做集群与负载均衡,步骤都是一样的
Upstream {}模块 把多台服务器加入到一个组
然后 memcached_pass, fastcgi_pass, proxy_pass ==> upstream组
默认的负载均衡的算法:
是设置计数器,轮流请求N台服务器.
可以安装第3方模式,来利用uri做hash等等.
这个模块就是用一致性hash来请求后端结节,并且其算法,与PHP中的memcache模块的一致性hash算法,兼容.
安装该模块后:
Nginx.conf中
upstream memserver {
consistent_hash $request_uri;
server localhost:11211;
server localhost:11212;
}
在PHP.ini中,如下配置
memcache.hash_strategy = consistent
这样: nginx与PHP即可完成对memcached的集群与负载均衡算法.
CIDR,允许访问的客户端的CIDR地址,如,202.80.18.23/25,前面32位IP地址,后面/25表示该IP地址中前25位是网路位,其余位代表主机部分。
Nginx默认只支持静态页面的加载; 经过下面一系列步骤: 安装/启动php-fpm程序, 修改nginx.conf配置, reload, 才可以支持动态页面加载;
描述: Apache服务启动, 主进程预先创建多个子进程(配置文件中设置), 每当接收到client客户端请求, 主进程就直接交由子进程处理, 直到该请求处理完毕, 才可以接收其他请求