一、Nginx 概述
Nginx 专为 性能优化而开发,其最知名的优点是它的稳定性和低系统资源消耗,以及对并发连接的高处理能力(单台物理服务器可支持 30000-50000 个并发连接,tomcat 通常是几百,不超过 1000 个), 是一个高性能的 HTTP 和反向代理服务器,也是一个IMAP/POP3/SMTP 代理服务器。
集群的架构通常可以解决几万的连接。
注意:c10k问题,是指10000个客户端(client)同时访问服务器,即高并发连接服务器的问题。
关于Nginx服务器,除了其高效性和稳定性的优点之外,我们最常使用的主要是 其反向代理和负载均衡,以及动静分离功能。
二、Nginx功能
2.1 Nginx 正向代理
通常,我们可以通过 ip 地址来直接访问网络中的某台确定的主机(更确切的说应该是通过 socket 套接字来访问确定中的某个确定的进程)。正向代理的代理服务器,是用户主动设置的,在我们的浏览器里面配置代理服务器,通过代理服务器进行互联网的访问。
假设服务器B,能够将客户端的请求转发给服务器A,同时服务器B又能够将服务器A的响应转发给客户端,那么显而易见,我们就可以通过访问服务器B,从而达到访问服务器A的目的。
类似于 等保里面的堡垒机,提供堡垒机访问其他服务器。
如下图,客户端访问服务器 A 的过程,客户端通过服务器 B 同样达到了 访问服务器 A 的目的,但是,请注意此时:服务器 B 似乎是作为客户端访问服务器 A 的一个媒介。
正向代理的用途:
- 访问原来无法访问的资源,如 google
- 可以做缓存,加速访问资源
- 对客户端访问授权,上网进行认证
- 代理可以记录用户访问记录(上网行为管理),对外隐藏用户信息
2.2 Nginx 反向代理
与正向代理服务器不同,反向代理服务器的作用,不仅仅是充当能够访问到目标服务器的 “媒介”。反向代理服务器,是服务器端设置的,不是用户,客户端对是否代理是没有感知的,由反向代理选择目标服务器。
反向代理是在服务器端(如Web 服务器)作为代理使用,而不是客户端。客户端通过正向代理可以访问不同的资源,而反向代理是很多客户端都通过它访问不同后端服务器上的资源,而不需要知道这些后端服务器的存在,而以为所有资源都来自这个反向代理服务器。
也就是说,用户请求目标服务器,由代理服务器决定访问哪个 IP ,这个时候是代理服务器去决定访问那个节点。
Nginx可以承担 “反向代理”的功能,服务器A和B可以是两个Tocmat服务器。
反向代理的作用:
- 1、保证内网的安全,阻止 web 攻击,大型网站,通常将反向代理作为公网访问地址,web 服务器是内网。
- 2、负载均衡,通过反向代理服务器来优化网站的负载。
2.3 负载均衡
在上图中,我们可以看到,服务器 A、B 之间的功能完全相同,可以相互替代,通过将原本由一个服务器负责处理的任务,分担给多台服务器的并发压力,同时扩展了服务器的带宽,从而提高了吞吐量----这就是负载均衡。
Nginx 提供的负载均衡有 2种:内置策略 和扩展策略。
内置策略为轮询,加权轮询,IP Hash 。扩展策略,自定义负载均衡策略。
轮询
权重轮询:
ip Hash
ip hash 对 客户端请求的 IP 进行 hash 操作,然后根据 hash 结果将同一个客户端 ip 的请求分发给同一台服务器进行处理,可以解决 session 不共享的问题。
2.4 动静分离
对于一些基本很少发生变化的静态资源,可以直接放在 Nginx 服务器上,当客户端访问这些静态资源时,Nginx 就可以直接访问给客户端,而不用再访问服务器集群,从而节省了部分请求和响应的时间。
这样一来,当客户端访问Nginx服务器时,当客户端访问静态资源时,Nginx就将静态资源直接返回给客户端,当客户端访问的是动态资源的时候,Nginx才会访问集群,就实现了动态资源和静态资源的分离,从而提高了系统的吞吐量。
CDN
Content Delivery Network,即内容分发网络。
CDN是构建在现有网络基础之上的智能虚拟网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。
三、Nginx 原理
具体的安装可以查看我之前的文章。
3.1 nginx 进程模型
在启动 nginx 之后,可以 发现发现有两个进程,一个 master ,一个 work。
这两个进程分别起着怎样的作用呢?
- master 进程:它是主进程,相当于一个领导者,它不干活,只分发任务。
- worker 进程:工作进程,相当于 一个工作人,它是替 master 进程去服务i的。
master 进程有且只有一个,而 worker 进程,默认下也只有一个,但是可以在配置文件中去配置 worker 的进程数量。当然,这个值 在nginx.conf 中可以配置,一般配置为 cpu-1 。
#user nobody;
worker_processes 1;
events {
worker_connections 1024; // 每个 worker 线程的最大处理线程数。总共打开数 小于 linux的最大打开数量 65535.
}
复制代码
总结:
- master 会把所有的请求信号,分配给 worker 进程去处理。相当于老板在外面接了很多的任务,然后分派给小伙伴去完成。
- master 会监控 worker,是否正常还是发生了一次退出了,这个时候 master 会重启一个新的 worker 去重新执行任务
3.2 Nginx 的 worker 抢占机制
1、通过配置文件,修改 worker 进程的数量,假设是 3 个。
2、其原理是:master 通过主进程 fork 了三个工作worker进程。这个时候如果有客户端有请求进入 nginx 服务器,三个 worker 进程会通过 accept_mutex 锁,来处理某个客户端的请求,谁占有锁,谁就去处理这个客户端请求。
需要注意Nginx 所有worker进程协同工作的关键(共享内存).
3.3 Nginx 的事件处理机制
1、底层的 worker 工作进程,采用的是 Linux 底层操作系统的 io 模式 epoll 来完成处理的。
2、epoll 的io 线程处理模型,采用的是 异步非阻塞的机制来完成线程的处理,所以上面的 client1 如果发生了阻塞,并不会影响 client2 和 client3 的执行。在一般的情况下:nginx 的每个 worker 可以处理 6-8 w的线程处理,所以并发很高。
3.4 nginx.conf 讲解
#user nobody; // worker 进程工作数
worker_processes 1;
events {
// linux 默认使用epoll
worker_connections 1024; //每个 worker 进程允许最大打开的文件数
}
// 针对 http 网络的配置
http {
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 on; // 启用文件的高效传输,有利于文件传输的性能
#tcp_nopush on; // 和 sendfile 一起使用,当请求的数据包累计到了一定大小的时候再发送
#keepalive_timeout 0;
keepalive_timeout 65; // 客户端连接服务器的超时时间,默认65 秒,0 代表不保持连接。
#gzip on; // 一定打开,利于文件和请求数据的传输,同时消耗时间。
// 服务虚拟主机配置
server {
listen 80; // 监听端口
server_name localhost; // 监听服务器 ip、域名、或者localhost
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ .php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ .php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
复制代码
3.5 负载均衡演示
1、轮询(weight=1)
默认选项,当weight不指定时,各服务器weight相同,
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
upstream bakend {
server 192.168.1.10;
server 192.168.1.11;
}
复制代码
2、weight 权重
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
如果后端服务器down掉,能自动剔除。
比如以下配置,则1.11服务器的访问量为1.10服务器的两倍。
upstream bakend {
server 192.168.1.10 weight=1;
server 192.168.1.11 weight=2;
}
复制代码
3、ip_hash 哈希
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session不能跨服务器的问题。
如果后端服务器down掉,要手工down掉。
upstream resinserver{
ip_hash;
server 192.168.1.10:8080;
server 192.168.1.11:8080;
}
复制代码
4、fair(第三方插件)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream resinserver{
server 192.168.1.10:8080;
server 192.168.1.11:8080;
fair;
}
复制代码
5、url_hash(第三方插件)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存服务器时比较有效。
在upstream中加入hash语句,hash_method是使用的hash算法。
upstream resinserver{
server 192.168.1.10:8080 ;
server 192.168.1.11:8080;
hash $request_uri;
hash_method crc32;
}
复制代码