分析流程: 用户输入域名 -> 服务器接收 -> 浏览器显示整个网页
一、Nginx基础
是什么?
是高性能的
web服务器, 是
反向代理服务器, 是email服务器
Apache和Nginx哪个好(结论相对)?
相同机器配置, Nginx的并发数多
**Apache适于处理动态页面, Nginx适于处理静态页面
背景?
Nginx[Engine x] 俄罗斯程序员 2004年发布的开源的高性能的web服务器
搭建开发环境(CentOS)
Linux操作系统上(LAMP, LNMP)下载安装Nginx
官方:
nginx.org
实操版本: 稳定版中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指令(理解):
设置nginx
工作进程所属用户和群组, group群组如果省略, 值等于user的值;
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指令(***): 设置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服务器无法处理客户端的请求
-
-
kill 某个进程:
-
$ sudo kill -9 进程ID
-
-
查看nginx的进程情况:
-
$ ps aux | grep nginx
2.5 如果kill命令没有-9参数, 表示不仅仅kill掉该进程4242(Nginx主进程id), 还包含所有子进程
3、
error_log指令: 设置nginx错误日志的路径, 文件名以及日志级别; 记录nginx进程相关的日志信息(启动, 信号, bind端口号等等)
3.1
日志级别: 级别从低到高, 级别越低, 信息量越大
debug: 开发阶段, 查看更多信息
debug, info, notice, warn, error, crit, alert, 或者 emerg
4、
pid指令: 设置nginx主进程的id
4.1 思路: 自动化(shell/perl/python)的读取该文件内容(id), 直接调用kill命令, 直接kill掉所有进程
块指令包含两个:
1、Events块指令
1.1 默认:
1.2
worker_connections指令(***): 设置一个
工作进程可以开启的最大连接数(理论上)是1024个
理论上nginx一共开启的连接数 = 1024 * worker_processes值(3)
思考: HTTP中请求数和上面的连接数是一回事吗?
答: 不是一回事; 连接数connection: TCP连接; 请求数request; 建立一次TCP连接, 发送多次请求
HTTP协议中Connection: keep-alive保持一段时间的连接
Nginx默认设置的超时timeout时间为65s(秒); 具体流程图可以查看附录中的第3部分.
2、http块指令
2.1 access_log指令: 设置访问log路径以及格式对应名字
2.2
lof_format指令: 设置accee.log文件内日志消息格式
access.log日志信息内容如下:
2.3 如何修改access_log格式?
2.3.1 找所有以$开头变量
2.4 include指令: 引入外部指令目录下的某个文件; 引入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指令: 如果客户端请求的资源mime类型无法mime.types内找到映射, 指定一个默认的资源类型
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资源(弹出对话框)
五、全局区
worker_processes 1; // 有1个工作的子进程,可以自行修改,但太大无益,因为要争夺CPU,一般设置为 CPU数*核数
Event {
// 一般是配置nginx连接的特性
// 如1个word能同时允许多少连接
worker_connections 1024; // 这是指 一个子进程最大允许连1024个连接
}
http { //这是配置http服务器的主要段
Server1 { // 这是虚拟主机段
Location { //定位,把特殊的路径或文件再次定位 ,如image目录单独处理
} /// 如.php单独处理
}
Server2 {
}
}
例子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的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 {
root
index
error_page
}
中括号可以不写任何参数,此时称为
一般匹配
也可以写参数
因此,
大类型可以分为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;
}
如果访问
http://xxx.com/
定位流程是:
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;
}
如果我们访问
http://xx.com/image/logo.png
此时, “/” 与 ”/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;
}
我们访问
http://xxx.com/foo
对于uri “/foo”, 两个location的patt,都能匹配他们
即 ‘/’ 能从左前缀匹配 ‘/foo’, ‘/foo’也能左前缀匹配’/foo’,
此时, 真正访问 /var/www/html/index.html
原因:’/foo’
匹配的更长,因此使用之.;
八、rewrite 重写
重写中用到的指令
if (条件) {} 设定条件,再进行重写
set #
设置变量
return #
返回状态码
break #
跳出rewrite
rewrite #
重写
If 语法格式:
If 空格 (条件) {
重写模式
}
条件又怎么写?
答:3种写法
1: “
=” 来判断相等, 用于字符串比较
2: “
~” 用正则来匹配(此处的正则
区分大小写)
~* 不区分大小写的正则
3:
-f -d -e 来判断是否为
文件,为
目录,
是否存在.
例子:
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。
以
xx.com/dsafsd.html 这个不存在页面为
例。
我们观察访问日志,日志中显示的访问路径,依然是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重写时,正则里如果有”{}”,正则要用双引号包起来
九、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
安装MariaDb 在 centos7下
编译完毕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请求: 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"
-
返回结果(红色框内容)表明设置成功
==================================================
我们观察
news.163.com 的头信息
请求:
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压缩内容----
推算一下节省的带宽:
假设
news.163.com PV 2亿
2*10^8 * 9*10^4 字节 ==
2*10^8 * 9 * 10^4 * 10^-9 = 12*K*G = 18T
节省的带宽是非常惊人的
gzip配置的常用参数(可以写在http,server,location,if):
gzip on|off; #是否开启gzip
gzip_buffers 32 4K | 16 8K #缓冲(压缩在内存中缓冲几块? 每块多大?)
gzip_comp_level [1-9] #推荐6 压缩级别(级别越高,压的越小,越浪费CPU计算资源)
gzip_disable #正则匹配UA 什么样的Uri不进行gzip
gzip_min_length 200 # 开始压缩的最小长度(再小就不要压缩了,意义不在)(单位: bytes字节)
gzip_http_version 1.0 | 1.1 # 开始压缩的http协议版本(可以不设置,目前几乎全是1.1协议)
gzip_proxied # 设置请求者代理服务器,该如何缓存内容
gzip_types text/plain application/xml # 对哪些类型的文件用压缩 如txt,xml,html ,css
gzip_vary on|off # 是否传输gzip压缩标志
注意:
图片/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,比较适于用这个方式
十一、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反向代理服务器+负载均衡实例:
用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的集群与负载均衡算法.
十四、Nginx支持PHP(***)
-
两个术语(理解)
CGI: Common Gateway Interface
通用网关接口: 定义一系列标准, 定义web服务器和外部程序之间的标准, 包括传什么格式数据, 返回什么格式数据…..
CGI程序实现:
独立于语言, 使用任意脚本语言或者完全独立的编译语言; C/C++ CGI程序; PHP CGI程序; Python CGI程序;……
优势: 解放web服务器, 交给CGI程序处理客户端请求
FastCGI:快速通用网关接口, 是CGI的进阶版本
-
Nginx支持动态页面内部结构图:
-
Nginx如何支持PHP(动态页面和静态页面)?
3.1 实现静态页面加载和动态页面执行的分离
-
实现Nginx支持动态页面加载
下载并安装php-fpm
$ php-fpm -v
上述命令没有返回值, 使用下面命令安装三个包
$ sudo yum install php php-mysql php-fpm
如果只需要安装php-fpm, 执行下面命令
$ sudo yum install php-fpm
-
修改nginx子配置文件(default.conf), 关于FastCGI部分(PHP部分)
-
root: 设置php文件的根目录
-
fastcgi_pass: 设置FastCGI server的ip地址和端口号
-
fastcgi_index: 默认php文件名
-
fastcgi_param: nginx服务器获取php文件的路径; 其中$document_root即为/usr/share/nginx/html
-
include: 加载fastcgi_params文件路径
-
pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000: nginx主进程将php文件传给FastCGI服务器, 该服务器监听9000端口
-
实操版本: nginx和php-fpm安装在同一个虚拟机
-
启动php-fpm进程
$ sudo service php-fpm start
验证: 下面两个命令均可
$ ps aux | grep php-fpm
$ sudo lsof -P | grep LISTEN
-
重新reload nginx配置文件
$ sudo nginx -s reload
-
验证:
1、在nginx根目录下创建test.php
$ sudo vi /usr/share/nginx/html/test.php
添加内容 phpinfo();
2、浏览器输入URL: localhost/test.php
其中php-fpm需要时active状态
-
面试题一: Apache和Nginx处理静态和动态页面的区别?
PHP默认是Apache的一个module模块, 无论加载静态还是动态页面, httpd进程都会执行/解析
Nginx默认只支持静态页面的加载; 经过下面一系列步骤: 安装/启动php-fpm程序, 修改nginx.conf配置, reload, 才可以支持动态页面加载;
-
面试题二: php-cgi,php-fpm和CGI, FastCGI什么关系?
php-fpm 是使用PHP语言, 实现的
FastCGI标准; 目前启动php-fpm程序
php-cgi 是使用PHP语言, 实现的
CGI标准
cgi(common gateway interface,通用网关接口)指web服务器在接收到客户端发送过来的请求后转发给程序的一组机制。
-
Apache和Nginx处理客户端请求的机制区别? Apache和Nginx有什么不同?
3.1 从module角度
Apache和Nginx全都是模块化设计
Apache默认添加模块, “热添加”其他模块
Nginx默认添加模块, “冷添加”其他模块
3.2 处理客户端请求机制角度:
a、Apache多进程架构:
同步阻塞机制
描述: Apache服务启动, 主进程预先创建多个子进程(配置文件中设置), 每当接收到client客户端请求, 主进程就直接交由子进程处理, 直到该请求处理完毕, 才可以接收其他请求
一个进程对应一个请求
缺点: 操作系统创建进程, 占用大量资源
b、Apache
多进程多线程架构(改进架构):
同步阻塞机制
优势: 系统开销小, 更多的线程执行客户端请求
一个线程对应一个请求
3.3 Nginx如何客户端请求:
异步非阻塞机制
工作进程接收某个请求(动态页面),直接交个php-fpm主进程, 此时该工作进程就可以继续接收其他请求
一个进程对应多个请求
简单流程图如下:
4. Apache如何支持PHP?
windows: 安装Apache -> PHP, 在httpd.conf 添加PHP有关配置
LAMP手动: 安装Apache -> PHP, 自动支持静态和动态页面
结论:
-
Apache只要稍微配置PHP,支持动态页面
-
每个httpd进程都包含phpx_module模块,无论加载静态页面,还是加载动态页面,都会耗费”一些”内存(多余)