1、基本概念
(1)什么是Nginx?详细概念不说了。我们更应该知道Nginx可以做什么,目前主流的用法是用作反向代理、负载均衡和动静分离,都说明Nginx是一个web服务器。
(2)什么是反向代理?其实正常情况下,客户端直接访问服务器端是不存在什么代理的,但是如果我们在客户端设置一个代理,比如vpn,请求是先发给代理,然后代理去访问服务器,那么这叫做正向代理,如果我们在服务器端设置一个代理,请求来了先到代理,然后由代理根据规则分配到不同的地方去(可能是其他服务器上的其他服务),这个代理叫做反向代理。
(3)什么是负载均衡?光是理解概念很简单,有很多负载过来,一个人处理不了,我把它相对公平地分摊给很多个人。具体到Nginx的使用场景就是,客户端一下子来了几百万请求,如果只是一台服务器的话使劲提高配置,那配置也有上限,所以很容易挂掉,这个时候我弄很多台服务器,然后在Nginx上设置一下,这样所有的请求先到Nginx,然后Nginx根据规则把这个请求送到对应的服务器,然后收到结果后再返回,这本质上还是利用了反向代理的用法。
(4)什么是动静分离。因为很多团队的web开发都实行前后端分离,所以在部署的时候可能也会分开部署,这个时候就可以叫做动静分离的部署方式,当然Nginx支持这样的部署方式,这里面也是利用Nginx的反向代理。
2、CentOS下的安装
环境:虚拟机Minimal版本。
先更新yum源,安装yum扩展源不然找不到nginx,然后直接安装:
yum -y update
yum install epel-release
yum install nginx
这种方式安装的Nginx,命令在/sbin/nginx
,配置在/etc/nginx/
中。
以下命令可以操作Nginx。
# 查看版本
nginx -v
# 启动Nginx
nginx
# 关闭Nginx
nginx -s stop
# 重新加载,尤其是配置文件修改的情况下
nginx -s reload
# 检查nginx是否运行
ps -ef | grep nginx
查看CentOS的ip地址,可以安装一下网络工具。
yum install -y net-tools
# 查看
ifconfig
这个时候访问应该还是不行的。因为防火墙的端口没有开。
# 查看防火墙开放的端口
firewall-cmd --list-all
# 增加端口
firewall-cmd --add-port=80/tcp --permanent
# 要重启防火墙才生效
firewall-cmd --reload
这个时候就可以利用获取的局域网的ip地址进行访问了。不过这个默认页面和我们平常看到的那个不一样,平常看到的是欢迎使用nginx的页面,现在这个页面是环境使用centos,nginx的影子都没看到,让人直接怀疑是不是有问题。这个时候看看配置文件/etc/nginx.conf
就能找到默认的首页在/usr/share/nginx/html/index/html
,这个文件里面的内容确实就是欢迎使用centos这一套,可能是针对这个平台改过的。不管怎样,成功安装并启动使用了。
3、配置文件概览
这个配置文件主要就是nginx.conf文件。这个文件主要由3部分。我们经常要打交道的就是server部分的配置,server部分的配置逻辑主要是,监听什么端口,当请求来了之后,我按照定义的规则跳转到哪里去。
# 这是第一部分,是全局的配置,比如worker_processes决定处理并发的能力,数值越大,并发处理越好,当然受到硬件制约
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
# 这是第二部分,events部分,这部分也是做一些配置,比如下面的配置就是决定在第一部分的1个worker_process可以最多连接多少个客户端,这里定义的是1024个。
events {
worker_connections 1024;
}
# 这是第三部分,这就是我们经常会修改和打交道的地方,叫做http部分。里面其实也分成了两部分,一部分是http的全局配置,另一部分就是server的部分相当于一个个虚拟主机,这是核心。
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;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
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;
#}
}
# 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;
# }
#}
}
4、设置反向代理
设置反向代理比较简单:比如下面的配置,我们的程序是war包部署在Tomcat中,甭管有几个,比如有一个的话端口是8080,有两个的话,还有一个是8181,那么这个时候,我们不想让客户用8080或者8181端口去访问,因为客户习惯是80端口。这个时候因为有两个Tomcat不可能都用80端口,所以就能用nginx做代理,转发过去。其次,这里最重要的是根据不同的路径转发到了不同的Tomcat中。
其实,这里如果只有一个Tomcat的话,我们也可以设置。只是如果只有一个,而且没有其他服务或者静态页面的时候,是没有必要这么设置增加复杂性的。
server {
listen 80;
server_name localhost;
location /aaa {
proxy_pass http://127.0.0.1:8080;
root html;
index index.html index.htm;
}
location /bbb {
proxy_pass http://127.0.0.1:8181;
root html;
index index.html index.htm;
}
}
5、设置负载均衡
设置负载均衡的主要配置在与upstream,里面设置不同的服务器地址以及均衡策略。
下面配置的意思是,我们监听80端口,有请求来了,我们因为设置了代理,所有的都转到http://hahaha
去,这个hahaha是个名字,就是我们设置了负载均衡的名字,这个负载均衡里面有2个服务器,我们用的策略是对请求来的ip做hash,然后根据hash值分配到对应的server上去处理,ip_hash的好处是只要客户ip不变,那么请求一定一直会被分配到同一个server上,与session等有关。如果不写,那么默认是轮询,就是第一个分配给server1,第二个分配给server2,第三个分配给server1,这样轮询。
upstream hahaha{
ip_hash;
server 127.0.0.1:8080;
server 127.0.0.1:8181;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://hahaha;
root html;
index index.html index.htm;
}
}
如果采用默认轮询的话,我们还可以设置不同的权重,这样可以根据每个服务器的配置来决定。配置高的就多接收和处理请求,低的就少处理一些。weight值越大,权重越大,处理越多。
upstream hahaha{
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8181 weight=2;
}
根据相应时间来分配,相应时间短的优先分配。
upstream hahaha{
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8181 weight=2;
fair;
}
6、设置动静分离
如果只有一个静态页面文件,那么直接通过示例中的设置,就可以实现,这里的root是我们静态文件存在的路径。如果存放在地方,比如/opt/local/www/index.html
中,那么root就可以设置为/opt/local/www
。
location / {
root html;
index index.html index.htm;
}
那么动呢。动就是如果我们的静态文件中有请求接口的话,那么这个接口如果统一以/api/xxx
之类的结尾的话,那么我们可以通过设置代理转发实现。
location /api {
proxy_pass http://localhost:8080;
root html;
index index.html index.htm;
}
7、设置高可用和keepalived
(1)先配置两台web服务器,用tomcat部署两台,里面内容稍微修改一下到时候好区别是哪台服务器在实际接收请求和处理。
# 升级
yum -y update
# 可以先搜索一下jdk,发现是有的,11的也有,但我们安装8
yum search java | grep jdk
# 安装jdk,安装之后环境变量已经自动配置好了
yum install java-1.8.0-openjdk
下载tomcat,去官网找网址。
yum install wget
# 下载有点慢
wget http://mirror.evowise.com/apache/tomcat/tomcat-8/v8.5.51/bin/apache-tomcat-8.5.51.tar.gz
# 解压
tar -zvxf apache-tomcat-8.5.51.tar.gz
# 修改一点html,比如web1和web2,用来标记是哪个服务器,端口就不改了,默认8080吧
vi webapps/ROOT/index.jsp
# 启动
./startup.sh
开通防火墙的80端口,用ifconfig查看局域网ip,然后在本机测试看看是否能访问tomcat。
firewall-cmd --add-port=8080/tcp --permanent
firewall-cmd --reload
yum install -y net-tools
ifconfig
依次部署两台web服务器,都需要在本机直接访问,以确保这一步能正常访问。
http://172.16.25.147:8080/
http://172.16.25.148:8080/
(2)部署2台nginx服务器。
这个之前已经部署过。我们先在第一台nginx上配置如下,测试一下轮询是不是生效:
upstream testServer{
server 172.16.25.147:8080;
server 172.16.25.148:8080;
}
server {
...
location / {
proxy_pass http://testServer;
}
}
注意以上的配置:每行配置结束不要忘记分号;upstream的命名不要有下划线,因为在proxy_pass中需要使用它,如果有下划线,它会提示在domain中下划线是无效字符。
我们这第一台Nginx的ip是:172.16.25.147,所以在本机上直接访问这个网址就能看到。刷新后有轮询,如果后面没有轮询的话,那需要强制刷新才行。
第2台Nginx同样的配置。然后测试访问一下看看http://172.16.25.146
。
(3)配置keepalived
在这2台nginx上安装keepalived并且做主从配置。
# 先安装
yum install -y keepalived
安装完之后,keepalived的配置文件在/etc/keepalived/keepalived.conf
,这个文件里面有写好的默认配置,我们只需要修改一点点就行。
global_defs {
# 这部分的邮件通知如果有的话就修改,测试的时候没必要改
notification_email {
381347268@qq.com
}
smtp_server 192.168.200.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
# 这边一台是MASTER,一台改成BACKUP,表示一主一从
state MASTER
# 这边自己ifconfig查看网卡名称
interface ens33
# 不用改,两台保持一致
virtual_router_id 51
# 主一般比从大一点,可以把从的那台改小一点,比如一个101,一个99
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
# 这个根据自己内网IP定义一个新的,这个新的就是将来本机要访问的,两台保持一致即可
172.16.25.155
}
}
两台都修改好之后,启动keepalive,两台都启动
systemctl start keepalived.service
然后本机访问172.16.25.155
发现可用。
这个时候怎么判断现在用的是主还是从的nginx呢?在主从两台nginx上分别执行查看,可以发现主上的ens33绑定了一个172.16.25.155/32 scope global ens33
,从上没有?
ip a
你会发现主从上都有,也就是说两个都成为主节点了。这里的原因是因为防火墙没有放行vrrp协议,而keepalive之间通信协议就是wrrp,也就是说他们之间没法正常通信,所以谁也找不到对象,所以都把自己当做主节点了。那么放行即可。224.0.0.18是keepalive的组播默认地址。
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --destination 224.0.0.18 --protocol vrrp -j ACCEPT
firewall-cmd --reload
在两台nginx服务器上设置防火墙放行vrrp协议后,甚至不用重启keepalive,就发现正常了,ip a
查看的时候只有一台上有绑定了inet。
然后关闭主服务器的keepalive,再用ip a
在两台上看看是否会自动切换在第二台nginx上绑定inet。
systemctl stop keepalived.service
当然实际当中,我们两台web服务器上的内容多数情况是一致的。我们的这个172.16.25.155
也会变成我们对用户开放的那个公网IP地址,甚至会和域名解析的IP地址绑定在一起,这样用户可以直接通过域名来访问,这样就搭建了一个nginx主从集群+微服务集群的简单架构。
(4)监测方面的补充配置
keepalive的配置文件中也可以增加一段监测脚本,比如在keepalived.conf中增加一段:
vrrp_script_chk_http_port{
# 脚本位置
script '/usr/local/src/nginx_ckeck.sh'
# 间隔2秒监测一次
interval 2
weight 1
}
然后就可以在/usr/local/src/nginx_ckeck.sh
中写入一段执行脚本:
#!/bin/bash
A=`ps -C nginx -no-header | wc -l`
if [ $A -eq 0 ];then
/usr/local/nginx/sbin/nginx
sleep 2
if [ `ps -C nginx -no-header | wc -l` -eq 0 ];then
killall keepalived
fi
fi
8、简单原理
(1)启动nginx之后我们可以通过ps -ef | grep nginx
发现,有两个进程,一个是master process
,一个是worker process
,这里的worker
数量就和我们最早提到的配置文件中的设置有关,一般建议配置成cpu数
,设置多了会造成cpu切换的浪费。
因为nginx底层用到了IO多路复用技术以最大化的提高处理形成,所以这就是我们为什么只把它部署在Linux服务器
的原因。
(2)当有客户端请求来的时候,master是最先接收到的,然后把这个请求扔出来,让worker进程来争抢,谁抢到谁去处理。这样的分进程的方式有很多好处:
- 因为master和worker是分开的,所以我们配置文件修改后用
nginx -s reload
可以热部署,做到更新不断服务,因为master发现需要更新配置了,它先负责一些准备工作,然后等待原先的那些worker处理结束,一结束就被master给kill掉,然后master把新生成的worker给启动起来。 - 因为worker之间也是独立的进程,所以之间相互影响比较小。
(3)每个请求与worker的connection数量一般是2个或者4个。因为有来有回。比如客户端和worker之间的来回2个连接,如果worker不仅仅是返回静态文件,还要去请求动态自愿的话,那么一来一回可能又是2个,一共变成4个连接了。
所以,这里有个计算最大并发数的问题。比如一个4核cpu的服务器,设置了worker数量是4,每个worker最大连接1024,那么如果作为静态服务器的话,最大并发就是4*1024/2
,如果作为反向代理的话,最大并发数就是4*1024/4
。