03-Nginx
Nginx介绍
- 开源、轻量、快速、可扩展的web服务器
- 早期是配合apache服务使用,现在很多网站都在使用Nginx, 像Github、Netflix、Wordpress都基于nginx
- 可配置能力弱于Apache, 性能强于apache
- 适用于大流量、高并发环境,稳定快速、占用资源少
Nginx与Apache比较
Apache:
- Apache是基于线程的
- 基于进程消耗的资源多,所有apache改造为基于线程的模式
- 而同进程下的多线程共享内存,其中一个线程出现问题,进程下所有线程都可能出现问题
Nginx:
- nginx使用事件驱动的架构
- 新客户端请求时不创建新的进程、线程
- 事件处理器 处理请求任务
- 更少的处理时间、更少的内存消耗
nginx使用了一个基于事件的软件架构。当有新的客户端请求发往服务器的时候,服务器不会为这个用户创建新的进程或新的线程,事件的软件架构会有一个核心软件的一个响应组件,称之为事件处理器,用来接受客户端的请求。把客户端对服务器的请求都变为一个TASK,来一个新的访问请求,就处理一个TASK,一个任务,处理完响应的资源就释放了。所以可以利用更少的资源、更少的系统时间,消耗更少的系统内存,提供更大的访问量的处理请求的并发能力。
因为这种基于事件的处理方式,也导致nginx更适合处理静态资源,但是处理动态内容不如Apache。
Apache与Nginx共用
- Apache处理动态内容
- Nginx处理静态内容
Nginx架构分析之事件驱动模型
事件驱动模型介绍
事件驱动模型是实现异步非阻塞的一个手段。事件驱动模型中,一个进程(线程)就可以了。
对于web服务器来说,客户端A的请求连接到服务端时,服务端的某个进程(Nginx worker process)会处理该请求,
此进程在没有返回给客户端A结果时,它又去处理了客户端B的请求。
服务端把客户端A以及客户端B发来的请求作为事件交给了“事件收集器”,
而“事件收集器”再把收集到的事件交由“事件发送器”发送给“事件处理器”进行处理。
最后“事件处理器”处理完该事件后,通知服务端进程,服务端进程再把结果返回给客户端A、客户端B。
在这个过程中,服务端进程做的事情属于用户级别的,而事件处理这部分工作属于内核级别的。
也就是说这个事件驱动模型是需要操作系统内核来作为支撑的。
Nginx事件驱动模型
Nginx的事件驱动模型,支持select、poll、epoll、rtsig、kqueue、/dev/poll、eventport
等。
最常用的是前三种,其中kqueue模型用于支持BSD系列平台的事件驱动模型。kqueue是poll模型的一个变种,本质上和epoll一样。/dev/poll
是Unix平台的事件驱动模型,其主要在Solaris7及以上版本、HP/UX11.22及以上版本、IRIX6.5.15及以上版本、Tru64 Unix 5.1A及以上版本的平台使用。
eventport是用于支持Solaris10及以上版本的事件驱动模型。
文件描述符
文件描述符是计算机科学中的一个术语,是一个用于表述只想文件的引用的抽象化概念。
在linux当中,每个进程会在进程控制块(PCB)当中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表都有一个指向已经打开文件的指针。
每个linux进程都应该有三个标准的文件描述符,对应三个标准流。
整数值 | 名称 | (unistd.h)符号常量 | (stdio.h)文件流 |
---|---|---|---|
0 | Standard input | STDIN_FILENO | stdin |
1 | Standard output | STDOUT_FILENO | stdout |
2 | Standard error | STDERR_FILENO | stderr |
文件描述符在形式上是一个非负整数,实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。
正因为对于linux来说,一切皆是文件的思想,所以,文件描述符为该系列平台上进行设备相关的变成实际上提供了统一的方法。
注意:文件描述符只有在linux下记为0,1,2,在其他系统是不一样的,例如在windows系统下,文件描述符和信号量、互斥锁等内核对象一样都记作HANDLE。所以文件描述符的概念只在Linux和UNIX系统上可以用来使用。
select模型
Linux和Windows都支持,使用select模型的步骤是:
- 创建所关注事件的描述符集合,对于一个描述符,可以关注其上面的读(Read)事件、写(Write)事件以及异常发生(Exception)事件。在select模型中,要创建这3类事件描述符集合。
- 调用底层提供的select()函数,等待事件发生。
- 轮询所有事件描述符集合中的每一个事件描述符,检查是否有相应的事件发生,如果有就进行处理。
poll模型
- poll模型是Linux平台上的事件驱动模型,在Linux2.1.23中引入的,Windows平台不支持该模型。
- poll模型和select模型工作方式基本相同,区别在于,select模型创建了3个文件描述符集合,而poll模型只创建一个文件描述符集合。
epoll模型
- epoll模型属于poll模型的变种,在Linux2.5.44中引入。epoll比poll更加高效,原因在于它不需要轮询整个描述符集合,而是Linux内核会关注事件集合,当有变动时,内核会发来通知。
- 也就是说,epoll不产生事件,但它监听并报告事件。
安装与配置
安装:
1 | sudo apt install nginx |
配置文件介绍
基于虚拟主机的配置
1 | /etc/nginx/nginx.conf # 主配置文件(包含其他配置文件) |
介绍主配置文件/etc/nginx/nginx.conf
/etc/nginx/nginx.conf
1 | user www-data # nginx进程账号 |
虚拟主机配置文件
1 | /etc/nginx/sites-enabled/ # 已启用的站点 |
新建虚拟主机(Server Blocks)
在一台物理服务器上,通过不同的主机名区分不同的服务器。在不同的站点创建一个虚拟主机,每个虚拟主机对应一个配置文件。
在Apache称之为虚拟主机,Nginx称之为 Server Blocks
1 |
|
然后就可以请求www.lab.com
Nginx支持PHP
安装fastCGI process manager
1 | sudo apt install php-fpm # 处理nginx转发的php请求 |
配置nginx
1 | sudo vim /etc/nginx/sites-available/lab.com |
更该配置如下:
1 | # 检测nginx修改是否正确 |
1 | sudo vim /var/www/lab.com/index.php # 当访问www.qq.com 主机名的时候,会显示index.php 页面内容 |
写测试的php代码:
1 | phpinfo(); |
1 | # 重启nginx服务 |
此时访问 www.lab.com,显示如下:
配置php
1 | sudo vim /etc/php/7.2/fpm/php.ini # php的主配置文件 |
重启php服务:
1 | sudo systemctl restart php7.2-fpm.service |
Nginx支持SSL
自签名证书:
1 | sudo openssl req -x509 -days 365 -sha256 -newkey rsa:2048 -nodes -keyout /etc/ssl/private/lab.key -out /etc/ssl/certs/lab.pem |
服务器配置
1 | sudo vim /etc/nginx/sites-available/lab.com |
使用Let's encrypt
免费证书
1 | # 安装 |
这是免费证书,有效期90天
1 | # 证书更新: |
测试ssl:https://www.ssllabs.com/ssltest/ 这个网站可以扫描你的证书配置
正向代理和反向代理
正向代理
也就是代理客户端访问外网服务器。
公司企业对员工上网进行过滤,过滤的主流方法就是用代理服务器。公司内部员工上网的时候所有的请求都不是发给外网的目标服务器的,所有的请求都是发送给公司内部搭建的代理服务器的。
因为客户端所有的请求都发给代理服务器,那么代理服务器必须看见、了解要请求的外网服务器的具体的内容资源、请求的参数等,所有详细的信息都必须向代理服务器申明,否则代理服务器就无法代替你去到外网服务器拿请求的资源。
所以代理服务器是能够看到应用层的东西的,客户端发给服务端应用层的东西要让代理服务器知道,这样代理服务器就可以原封不动的将请求的资源拿过来给你。
代理是把对应用层的请求告诉给代理服务器,代理服务器知道后,会按照你的要求重新生成一个请求,向外网真正的服务器发送。然后代理服务器把外网服务器返回的结果拿到之后,重新打包封装,再返回给客户端。
这种工作方式就决定着代理服务器必须要了解应用层内容,这样代理服务器就可以对应用层的内容进行控制,当你发送一个视频请求,代理服务器可以拒绝请求。
这种代理方式是 代理服务器代替企业内部客户端发送请求,再将响应内容返回给客户端。
nginx做反向代理
什么是反向代理:
把nginx部署在企业web服务器的前面,让它先接受客户端的请求。客户端的请求发送给nginx的反向代理服务器,nginx的反向代理服务器根据客户端发来的请求,再代理转发给真正的web服务器。真正的服务器接收到nginx转发的请求之后,进行响应,把内容交给nginx服务器,nginx服务器再把响应交给客户端。
这个过程中,代理服务器是代替服务端接收客户端的请求,而不是代替客户端,它是代替真正的web服务端向客户端交付web服务的。称之为反向代理。
这种反向代理服务器可以部署在企业内部,在防火墙里面;更常见的是把nginx部署在互联网上,在企业防火墙外面,甚至nginx的反向代理服务器可以是云平台。
nginx反向代理过程:
通过nginx做反向代理,nginx可以承受高并发、大流量、高负载的访问请求,即使有大流量访问,也可以保证web服务器瘫痪,不会让应用程序宕机。通过nginx的过滤,把剩余的干净的请求转发给web服务器,由真正的web服务器进行处理,而真正的web服务器可以由Apache进行搭建。
结合Apache / Nginx的优势:
Apache适合处理动态内容,可以把需要程序逻辑处理的动态的内容部署在apache服务器集群上,然后通过前端的nginx做反向代理。大流量、高并发打向nginx,nginx可以抗住,把有害的、恶意的请求过滤之后,干净的请求转发给后面的apache服务器集群做处理,处理一些动态内容,响应的内容给nginx,nginx再交付给客户端。
- Apache不适用于高并发、高负载的环境
- Nginx没有内建支持动态内容处理能力
- 结合Apache / Nginx的优势
- Nginx接受入站的请求和静态内容缓存,动态请求发给Apache
- Apache完成动态内容处理
- Nginx作为反向代理,动态请求转发给Apache
Nginx做反向代理部署
本机安装Apache
由于apache和nginx都会默认侦听80端口,会有冲突,所以先停掉nginx
1 | # 先停掉nginx |
修改Apache 侦听端口
让nginx侦听80端口,修改apache侦听端口
1 | sudo /etc/apache2/ports.conf |
修改如下:
修改apache虚拟主机的站点配置
1 | sudo vim /etc/apache2/sites-available/000-default.conf |
修改:
1 | # 重启apache服务 |
修改ngixn的配置
需要将nginx 80端口转发给apache默认的页面
1 | sudo vim /etc/nginx/sites-available/default |
重启nginx服务
Apache支持php
这样在访问 192.168.32.128:80
时,动态的内容如php 会转发给 本机的8080端口
这就需要apache支持php服务,处理php的内容
安装:
1 | sudo apt install php7.2 libapache2-mod-php7.2 |
验证:
1 | php -v |
启用模块:
1 | a2enmod php7.2 |
修改索引文件:
1 | sudo vim /etc/apache2/mods-available/dir.conf |
测试php
1 | cd /var/www/html/ |
Nginx与Apache不在一个服务器部署
准备的实验环境:
一台Ubuntu虚拟机安装Apache服务,另外两台安装Nginx服务,由宿主机向第一台nginx服务器发送访问请求,第一台ngixn服务器把访问请求转发给第二台nginx服务器,第二台nginx服务器再把请求转发给apache服务器。
就是通过宿主机,中间跨两道nginx代理,最终访问到apache上的web页面
- apache 192.168.8.101
- nginx1 192.168.8.102
- nginx2 192.168.8.103
在nginx1中修改:
1 | sudo vim /etc/nginx/sites-available/default |
nginx2:
1 | sudo vim /etc/nginx/sites-available/default |
都重启服务之后
宿主机访问 nginx1 http://192.168.8.102 结果访问到了apache的web页面
Nginx负载均衡
负载均衡介绍
apache不适合做大流量、高并发的工作,如果 客户端访问请求量比较大,都是正常的请求,nginx能抗住,但一台apache可能扛不住,这样可以做apache服务器集群。由前面的一个nginx接收到客户端所有的访问请求之后,由nginx反向代理把请求转发给后面诸多的apache服务器。
而且nginx可以做负载均衡,比如说1秒有一万个请求发给nginx,nginx可以承受住,但如果把这一万个请求发给apache,apache就受不了了。多台apache服务器集群,nginx可以负载均衡,按照一定权重把请求分摊给多个apache服务器。
先在nginx服务器里创建一个组,把后面的apache的ip写到这个组里面,然后在nginx配置里面指定,凡是访问nginx的请求,都要按一定权重比例分给后面的apache里。
1 | sudo vim /etc/nginx/sites-available/default |
负载均衡方法
round-robin
轮询,默认使用方法,按照权重
least_conn
最少连接数优先
客户端的所有请求都是发给nginx,由nginx把请求分摊给后面的web服务器。后端的服务器如果有增有减,有的服务器可能刚上线,刚加入这个组,它维持的连接数还比较少。比如说这个组由5台服务器,前面4台都各自维持了100个连接了,第5台服务器刚练上来,还没有连接数,这意味着它的负载最小,最空闲,就把新的请求发给它处理。
least_time
响应速度最快
你可能连接数很少,只有50个,人家有100个连接。但是但从连接数上不能反映出工作能力的强弱。人家的配置比你好,新一代cpu、固态硬盘,而你老旧的cpu、机械硬盘。人家100个连接响应都很快,而你50个就不行了。
hash
基于请求的hash值
对每一个请求做一个hash值,如果hash值相同,就永远发给这个目标的服务器。
更适合来自同样的计算机的相同请求,每次都由同一个后端服务器来响应。
ip_hash
基于IP地址的hash值
以这个客户端IP地址发给nginx请求,nginx算完hash值之后,凡是来自与你这个IP的所有请求都会被转发给同一个服务器,除非这个服务器宕机,那么会重新计算hash值分配。
这种场景适合需要长时间的 session会话连接请求。