Switch branches/tags
Nothing to show
Find file History
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
..
Failed to load latest commit information.
img
README.md

README.md

切图仔的 Nginx 小书

本文陆续介绍 Nginx 的功能、配置、及一些实用场景(待完善...)。

一、介绍 Nginx

1. Nginx 是什么?

Nginx,很多工程师喜欢读成'恩基克思'。Nginx 是一款高性能的HTTP和反向代理服务器软件,第一个开源版本诞生于2004年,虽然诞生较晚但经过十多年的发展,已经成为非常流行的 web 服务器软件。其发展速度和流行程度已经远远超过其它同类软件,成为大型网站和高并发网站的首选。

2. Nginx 为什么流行

Nginx 之所以能够脱颖而出,一方面是因为市场往往会选择简单实用的技术,另一方面是因为web服务器的高并发已经成为趋势,而高并发又要求架构具有健壮性和可伸缩性。Nginx 的特性迎合了市场的这个发展趋势,它是为性能而生,从发布以来一直侧重于高性能,高并发,低 CPU 内存消耗;在功能方面:负载均衡,反向代理,访问控制,热部署,高扩展性等特性又十分适合现代的网络架构。更可贵的是配置简单文档丰富,大大降低了学习的门槛。这样稳定,性能强,功能丰富又简单的产品当然会受欢迎了。

3. 为什么选择 Nginx?

Apache 自1990年发布以来,一直是 web 服务器市场的霸主。Nginx 虽然发布较晚,但是却因为在高并发下卓越的表现而迅速崭露头角。最初,Nginx 只是作为 Apache 在高并发场景下的补充,两者结合辅助使用。而现在,Nginx 随着迭代功能,在极多数场合已经可以抛弃老大哥来独当一面了。

80端口之争

Nginx 和 Apache 相同点:

  • 同是 Http 服务器软件,都采用模块化结构设计
  • 支持通用语言接口,如 PHP,Python 等。
  • 支持正向代理和反向代理。
  • 支持虚拟主机以及 SSL 加密传输
  • 支持缓存以及压缩传输
  • 支持 URL 重写
  • 模块多,扩展性强
  • 多平台支持

Nginx 的优势:

  • 轻量级,安装简单、配置文件简洁,运行时 CPU 内存使用率低。
  • 性能强 支持多核,处理静态文件效率高。
  • 支持热部署,启动速度快,可以在不间断服务情况下对软件和配置进行升级
  • 负载均衡 支持容错和健康检查
  • 代理功能强大 支持无缓存的方向代理,同时支持 IMAP/POPS/SMTP 的代理

Nginx 的劣势:

  • 相对于老大哥 Apache 模块要少一些
  • 对动态请求的支持不如 Apache
  • Windows 版本功能有限,受限于 Windows 的特性,支持最好的还是 *unix 系统

4. Nginx 的工作原理

Nginx 由内核和一系列模块组成,内核提供 Web Server 的基本功能,如启动网络协议,创建运行环境,接收和分配客户端请求,处理模块之间的交互。Nginx 的各种功能和操作都由模块来实现。
Nignx 的模块从结构上分为:

  • 核心模块:HTTP 模块、EVENT 模块和 MAIL 模块
  • 基础模块:HTTP Access 模块、HTTP FastCGI 模块、HTTP Proxy 模块和 HTTP Rewrite 模块
  • 第三方模块:HTTP Upstream Request Hash 模块、Notice 模块和HTTP Access Key 模块以及其它自开发模块。

这样的设计使 Nginx 方便开发和扩展,也正因此才使得 Nginx 功能如此强大。Nginx 的模块默认编译进 Nginx 中,如果需要增加或删除模块,需要重新编译 Nginx ,这一点不如 Apache 的动态模块加载方便。(如果需动态加载模块,可以使用兼容 Nginx 的web服务器 Tengine )

5. Nginx 的请求处理

Nginx 使用一个多进程模型来应对外来需求,其中一个 master 进程,多个 worker 进程。master 进程负责管理 Nginx 本身和其他 worker 进程。

所有实际上的业务处理逻辑都在 worker 进程,其内有一个无限循环执行的函数,不断处理来自客户端的请求,并进行处理,直到整个 Nginx 服务停止。

worker 进程中,ngx_worker_process_cycle() 就是这个无线循环的函数。内部对一个请求的简单处理流程如下:

  1. 操作系统提供的机制产生相关的事件
  2. 接受和处理这些事件,如果是接收数据,则产生更高层的request对象
  3. 处理 request 的 header 和 body
  4. 产生响应,并发送回客户端
  5. 完成 request 的处理
  6. 重新初始化定时器及其他事件

如图展示了 Nginx 模块常规的HTTP请求和响应的过程: htpp流程

二、Nginx 配置

#运行用户
user nobody;
#启动进程,通常设置成和cpu的数量相等
worker_processes  1;
 
#全局错误日志及PID文件
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
 
#pid        logs/nginx.pid;
 
#工作模式及连接数上限
events {
    #单个后台worker process进程的最大并发链接数    
    worker_connections  1024;
}
 
 
http {
    #设定mime类型,类型由mime.type文件定义
    include    mime.types;
    default_type  application/octet-stream;
    #设定日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
 
    access_log  logs/access.log  main;
 
    #sendfile 指令指定 nginx 是否调用 sendfile 函数(zero copy 方式)来输出文件,
    #对于普通应用,必须设为 on,
    #如果用来进行下载等应用磁盘IO重负载应用,可设置为 off,
    #以平衡磁盘与网络I/O处理速度,降低系统的uptime.
    sendfile     on;
    #tcp_nopush     on;
 
    #连接超时时间
    #keepalive_timeout  0;
    keepalive_timeout  65;
    
    #开启gzip压缩
    #gzip  off;
 
    #设定虚拟主机配置
    server {
        #侦听80端口
        listen    80;
        #定义使用 www.nginx.cn访问
        server_name  www.nginx.cn;
 
        #定义服务器的默认网站根目录位置
        root html;
 
        #设定本虚拟主机的访问日志
        access_log  logs/nginx.access.log  main;
 
        #默认请求
        location / {
            
            #定义首页索引文件的名称
            index index.php index.html index.htm;   
 
        }
 
        # 定义错误提示页面
        error_page   500 502 503 504 /50x.html;
        location = /50x.html {
        }
 
        #静态文件,nginx自己处理
        location ~ ^/(images|javascript|js|css|flash|media|static)/ {
            
            #过期30天,静态文件不怎么更新,过期可以设大一点,
            #如果频繁更新,则可以设置得小一点。
            expires 30d;
        }
 
        #PHP 脚本请求全部转发到 FastCGI处理. 使用FastCGI默认配置.
        location ~ .php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
 
        #禁止访问 .htxxx 文件
            location ~ /.ht {
            deny all;
        }
 
    }
}

三、Nginx 命令行

不像其他系统软件,Nginx 仅由几个命令行参数

-c </path/to/config> // 为Nginx指定一个配置文件,来代替缺省的
-t // 不运行,仅仅测试配置。
-v // 显示Nginx的版本
-V // 显示Nginx的版本,编译器版本和配置参数。

Nginx 启动、停止、重启命令

// 启动
sudo nginx
// 或者
sudo /usr/local/Cellar/nginx/1.12.0_1/bin/nginx // 如果不知道实际路径,可以nginx —V查看

// 停止命令
ps -ef | grep nginx // 查看占用进程
kill -QUIT nginx主进程号 // 从容停止
kill -TERM nginx主进程号 // 快速停止
kill -9 nginx主进程号 // 强制停止
// 或者
kill -QUIT `cat /usr/local/var/run/nginx.pid` // 如果不知道实际路径,可以nginx —V查看
// 重启命令
kill -QUIT `cat /usr/local/var/run/nginx.pid`
sudo /usr/local/Cellar/nginx/1.12.0_1/bin/nginx

四、Nginx 实用

场景1:适配PC与移动web

一般门户网站在访问时,会有 PC 和 H5、Pad 几个适配版本,我们常会有这样的需求,在网站被访问时候,服务端来识别用户是 PC 设备还是移动设备,跳转返回相应适配版本的页面。

第一步通常是判断 HTTP 请求头的 User-Agent ,基本原理是通过正则匹配判断,有一套开源的解决方案可以直接使用:http://detectmobilebrowsers.com/,下载 Nginx 配置即可。
第二步就是通过之前对设备的判断,来反向代理到不同的版本。

location / {
	proxy_pass http://leju.com
	if ($mobile_rewrite = perform) {  
        proxy_pass http://m.leju.com/  # 手机版  
    } 	
}

第三步,因为可能错误判断设备,或者用户就想指定访问某种设备版本,在页面底部,通常会有链接跳转其他版本。 foot

<div class="ll_btn">
			<a href="http://www.leju.com#ln=index_fdh">电脑版</a>
			<a href="http://pad.leju.com/?source=chuping#ln=index_fdh">PAD版</a>
			<a href="http://m.leju.com/touch/app/app_download.html?source=chupinghp#ln=index_fdh">客户端</a>
</div>

同时在 Nginx 中加入判断,如果包含指定 source 参数,则指定进入某个版本。

场景2:前端环境切换

前端开发中,我们经常需要在多个环境(开发、内测、外测、预发、正式环境)进行切换。
我们通常通过切换 host 指向搭配机器绑定不同域名的方式去实现:比如测试环境是dev.j.esf.sina.com,正式环境是j.esf.sina.com,搭配不同的 host 指向,可以形成多种组合。

而通过反向代理的Nginx,更容易处理这种代理转发的问题:

  • 我们通过点击页面的环境按钮,让绑定的 javascript 代码往域名下种入带有 IP 信息的 cookie,同时刷新页面。
  • Nginx 接收新的请求,读取请求的 cookie ,如果包含指定的键名和值,则代理到这个 IP 地址。(http header 也可以)
  • 如果没有,则代理到默认的线上环境。
set $env_id “123.59.190.206”;
if( $http_cookie~* "host_id(\S+)(;.*|$)"){
	set $env_id $1;
}

location / {
	proxy_set_header Host $host;
	proxy_pass   http://$env_id:80;
}

...场景待续