Nginx 实战及常用配置介绍

483 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1. 目的

这篇总结是来回顾加实操Nginx的相关操作。包括Nginx三大特性:负载均衡,反向代理和动静分离。最后利用Nginx来模拟一个高可用场景,加深对Nginx的认识。

2. 基本概念

2.1 Nginx说明

Nginx是一个http的反向代理web服务器,在并发能力上表现很好,能承受高达50000个并发数。所以也是深受很多公司青睐。包括百度,京东,新浪,腾讯,淘宝等。

2.2 反向代理 和 正向代理

正向代理是代理客户端,服务端对于不同客户端的请求是无感的。一个比较好的例子就是VPN的使用 ,比如我们翻墙使用google,实际上就是一个正向代理,用户相当于还是访问google网址,但是实际上是发给了VPN服务器,由VPN服务器来和Google进行交互通信,再把内容返还给客户端。正向代理需要配置客户端浏览器。

image-20201113165046603

反向代理刚好相反,是用来代理服务端。客户端对于服务端是无感的,比如用户要访问服务端的多台tomcat服务器,可以通过访问反向代理服务器的方式,然后由反向代理服务器和 tomcat进行通信,把内容返回给客户端。所以反向代理是配置服务端。

image-20201113165348092

2.3 负载均衡

负载均衡是相当于通过负载均衡服务器,来把客户端的请求根据负载均衡配置,来分配到各个服务器。

image-20201113165634425

2.4 动静分离

动静分离相当于是把服务端的动态资源和静态资源分开,用nginx来指向不同的服务器。

image-20201113165938886

3. 环境安装

3.1 Nginx 安装

apt-get install nginx
root@agent:/tmp/8081/apache-tomcat-9.0.39/webapps# nginx -t
nginx: [warn] conflicting server name "192.168.2.5" on 0.0.0.0:80, ignored
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

主要是配置nginx.conf文件。nginx的默认运行端口是80端口。

3.2 tomcat安装

直接下载tomcat压缩文件,然后放到指定路径下,直接解压。需要安装JDK运行。tomcat的运行是在bin路径下,执行sh文件。tomcat的默认运行端口是8080端口。

sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt install openjdk-11-jdk

3.3 keepalived 安装

apt-get install keepalived

4. 反向代理 Practice

通过Nginx来代理tomcat服务器,我的虚拟机ip是192.168.2.5, 在Nginx配置文件中监听9001端口,同时Nginx来代理tomcat的8080和8081两个端口。在8080中创建edu文件和html文件,8081中创建vod文件夹和html文件,通过192.168.2.5:9001:/edu/a.html 和 192.168.2.5:9001:/vod/a.html来分别访问两个tomcat服务器。

主要是nginx.conf的配置,下面就是配置说明。还有tomcat的8081 服务器的配置文件要修改默认监听端口8080为8081。

 server {
                listen 9001;
                server_name 192.168.2.5;

                location ~ /edu/ {
                        proxy_pass http://127.0.0.1:8080;
                }

                location ~ /vod/ {
                        proxy_pass http://127.0.0.1:8081;
                }
        }

Location ~ 是用来判断是否存在,proxy_pass 是用来指向tomcat服务器。这个block是在nginx.conf的http block中配置。通过这个实验就可以看到Nginx的反向代理了。Nginx代理两个tomcat服务器,用户只用访问9001端口即可访问不同的服务器。

5. 负载均衡

负载均衡是有三种配置方式,每一种都来试下。这一次是把8081下的服务器也创建一个edu文件夹和a.html文件,浏览器输入192.168.2.5:80/edu/a.html 来根据负载均衡访问不同的tomcat服务器。

  • 轮询

每个请求逐一分配到不同的tomcat服务器。相当于机会是均等的。配置如下:

 upstream myserver {
                server 192.168.2.5:8080;
                server 192.168.2.5:8081;
        }
        
        server {
                listen 80;
                server_name 192.168.2.5;

                location / {
                        proxy_pass http://myserver;
                }
        }

这样的话,当请求来时,会轮巡去访问两台tomcat服务器。

  • weight方式

    可以给每台tomcat服务器分配权重,请求会更具权重动态的落到不同的服务器。

     upstream myserver {
                    server 192.168.2.5:8080 weight=5;
                    server 192.168.2.5:8081 weight=10;
            }
            
            server {
                    listen 80;
                    server_name 192.168.2.5;
    
                    location / {
                            proxy_pass http://myserver;
                    }
            }
    

    这样配置后,请求会根据权重,概率性的落到两台服务器。

  • Ip_hash 方式

    这个是指请求会只落到第一次访问的服务器,不会改到其他服务器,这种可以解决session问题。

    upstream myserver {
    								ip_hash;
                    server 192.168.2.5:8080 weight=5;
                    server 192.168.2.5:8081 weight=10;
            }
            
            server {
                    listen 80;
                    server_name 192.168.2.5;
    
                    location / {
                            proxy_pass http://myserver;
                    }
            }
    

6. 动静分离

这种是指把动态资源和静态资源区分开,放在不同的位置,比如数据库查找,属于动态资源,可以放在tomcat中,而静态页面这种可以放在nginx中,根据不同的指向去访问这些资源。就不操作了。

7. 高可用模拟

Nginx的高可用是指,用两台nginx服务器来做主从服务,当主服务器宕机后,可以自动切换到从服务器。Nginx的切换和监控是由keepalived 来实现,在keepalived中会定义一个脚本,一直去监控 nginx线程的状态,一旦状态变化时,会切换到另一个从服务器。

image-20201113182414578

上面就是整个流程图 ,虚拟ip 192.168.2.50 是keepalived设置的一个虚拟ip,有一个nginx_check.sh 的脚本,会每隔2s去运行下这个脚本, 这个脚本是用来检测nginx线程的,如果没有nginx线程,会kill掉keepalive,服务会导向到从服务器上 。从服务器也是需要一样的配置,只是把 state改成MASTER。

vrrp_script chk_http_port {
        script "/etc/keepalived/nginx_check.sh"
        interval 2
        weight 2
}

vrrp_instance inside_VI_1 {
    state BACKUP #指定那个为master,那个为backup,如果设置了nopreempt这个值不起作用,主备考priority决定
    interface eth1 #设置实例绑定的网卡
    virtual_router_id 50 #VPID标记
    priority 90 #优先级,高优先级竞选为master
    advert_int 1 #检查间隔,默认1秒
    authentication { #设置认证
        auth_type PASS #认证方式
        auth_pass 111111 #认证密码
    }
    virtual_ipaddress { #设置vip
        192.168.2.50
    }
}
# !/bin/bash
A= 'ps -C nginx -no-header | wc -l'
if [ $A -eq 0 ];then
        /usr/sbin/nginx
        sleep 2
        if [ 'ps -C nginx --no-header | wc -l' -eq 0 ];then
                killall keepalived
        fi
fi
upstream myserverkeepalived {
                server 192.168.2.50:8080;
                server 192.168.2.50:8081;
        }

        server {
                listen 80;
                server_name 192.168.2.50;

                location / {
                        proxy_pass http://myserverkeepalived;
                }
        }

通过192.168.2.50:/edu/a.html 去 访问,默认情况下是用的master的nginx。我们可以把master的nginx down掉,服务还是可以继续访问,这个时候用的从的nginx。

8. Nginx 的基本原理

Nginx的架构是一个master的主进程作为守护进程 启动,多个 work进程附属于master进程,结构如下图。每个 work而进程相当于反向代理服务器。各个work进程通过竞争来抢夺请求。

image-20201113190537081 image-20201113190640325

这种方式的好处:

  • 支持热部署。当nginx.conf有改动时,即使有work进程在处理事务,也不影响。config file会同步到未进行事务的work进程,待任务完成后,再同步。
  • 各个work进程不用加锁而实现独立运行,节省了加锁的开销。

每个work支持的最大连接数是4个,worker的最适宜个数和cpu核数保持一致最好。

9. 附件

1)nginx.conf

user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
        worker_connections 768;
        # multi_accept on;
}

http {

        ##
        # Basic Settings
        ##

        sendfile on;
        tcp_nopush on;
        tcp_nodelay on;
        keepalive_timeout 65;
        types_hash_max_size 2048;
        # server_tokens off;

        # server_names_hash_bucket_size 64;
        # server_name_in_redirect off;

        include /etc/nginx/mime.types; 
        default_type application/octet-stream;
    
        ##
        # Logging Settings
        ##
    
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
root@monitor:/etc/nginx# 
root@monitor:/etc/nginx# 
root@monitor:/etc/nginx# cat nginx.conf 
user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
	worker_connections 768;
	# multi_accept on;
}

http {

	##
	# Basic Settings
	##

	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	##
	# Logging Settings
	##

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;

	##
	# Gzip Settings
	##

	gzip on;
	gzip_disable "msie6";
       
	
	 upstream myserverkeepalived {
                server 192.168.2.50:8080;
                server 192.168.2.50:8081;
        }

        server {
                listen 80;
                server_name 192.168.2.50;

                location / {
                        proxy_pass http://myserverkeepalived;
                }
        }

	upstream myserver {
		server 192.168.2.6:8080;
                server 192.168.2.6:8081;
	} 

        server {
		listen 80;
		server_name 192.168.2.6;
                
		location / {
			proxy_pass http://myserver;
		}
	} 	

 
        server {
		listen 80;
		server_name 192.168.2.6;
		
		location / {
			root html;
			proxy_pass http://127.0.0.1:8080;
 			index index.html index.html;
		}
	}

        server {

		listen 9001;
		server_name 192.168.2.6;
 		
		location ~ /edu/ {
			proxy_pass http://127.0.0.1:8080;
		}
		
		location ~ /vod/ {
			proxy_pass http://127.0.0.1:8081;
		}
	}


		

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

	##
	# nginx-naxsi config
	##
	# Uncomment it if you installed nginx-naxsi
	##

	#include /etc/nginx/naxsi_core.rules;

	##
	# nginx-passenger config
	##
	# Uncomment it if you installed nginx-passenger
	##
	
	#passenger_root /usr;
	#passenger_ruby /usr/bin/ruby;

	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}


#mail {
#	# See sample authentication script at:
#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
# 
#	# auth_http localhost/auth.php;
#	# pop3_capabilities "TOP" "USER";
#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
# 
#	server {
#		listen     localhost:110;
#		protocol   pop3;
#		proxy      on;
#	}
# 
#	server {
#		listen     localhost:143;
#		protocol   imap;
#		proxy      on;
#	}
#}
  1. keepalived.conf
global_defs {
   notification_email {  #指定keepalived在发生切换时需要发送email到的对象,一行一个
		monitor@3evip.cn
   }
   notification_email_from monitor@3evip.cn #指定发件人
   smtp_server stmp.3evip.cn #指定smtp服务器地址
   smtp_connect_timeout 30 #指定smtp连接超时时间
   router_id LVS_DEVEL #运行keepalived机器的一个标识
}

vrrp_sync_group VG_1{ #监控多个网段的实例
	group {
		inside_network #实例名
		outside_network
	}
	notify_master /path/xx.sh #指定当切换到master时,执行的脚本
	netify_backup /path/xx.sh #指定当切换到backup时,执行的脚本
	notify_fault "path/xx.sh VG_1" #故障时执行的脚本
	notify /path/xx.sh 
	smtp_alert #使用global_defs中提供的邮件地址和smtp服务器发送邮件通知
}

vrrp_script chk_http_port {
	script "/etc/keepalived/nginx_check.sh"
	interval 2
	weight 2
}

vrrp_instance inside_VI_1 {
    state BACKUP #指定那个为master,那个为backup,如果设置了nopreempt这个值不起作用,主备考priority决定
    interface eth1 #设置实例绑定的网卡
    virtual_router_id 50 #VPID标记
    priority 90 #优先级,高优先级竞选为master
    advert_int 1 #检查间隔,默认1秒
    authentication { #设置认证
        auth_type PASS #认证方式
        auth_pass 111111 #认证密码
    }
    virtual_ipaddress { #设置vip
        192.168.2.50
    }
}
virtual_server 192.168.36.99 80 {
    delay_loop 6 #健康检查时间间隔
    lb_algo rr  #lvs调度算法rr|wrr|lc|wlc|lblc|sh|dh
    lb_kind DR  #负载均衡转发规则NAT|DR|RUN
    persistence_timeout 5 #会话保持时间
    protocol TCP #使用的协议
    persistence_granularity <NETMASK> #lvs会话保持粒度
    virtualhost <string> #检查的web服务器的虚拟主机(host:头)    
    sorry_server<IPADDR> <port> #备用机,所有realserver失效后启用
	real_server 192.168.200.5 23 {
            weight 1 #默认为1,0为失效
            inhibit_on_failure #在服务器健康检查失效时,将其设为0,而不是直接从ipvs中删除 
            notify_up <string> | <quoted-string> #在检测到server up后执行脚本
            notify_down <string> | <quoted-string> #在检测到server down后执行脚本
			TCP_CHECK {
				connect_timeout 3 #连接超时时间
				nb_get_retry 3 #重连次数
				delay_before_retry 3 #重连间隔时间
				connect_port 23  健康检查的端口的端口
				bindto <ip>   
			}
			HTTP_GET | SSL_GET{
				url{ #检查url,可以指定多个
						path /
						digest <string> #检查后的摘要信息
						status_code 200 #检查的返回状态码
				}
				connect_port <port> 
				bindto <IPADD>
				connect_timeout 5
				nb_get_retry 3
				delay_before_retry 2
			}

			SMTP_CHECK{
					host{
						connect_ip <IP ADDRESS>
						connect_port <port> #默认检查25端口
						bindto <IP ADDRESS>
					}
					connect_timeout 5
					retry 3
					delay_before_retry 2
					helo_name <string> | <quoted-string> #smtp helo请求命令参数,可选
			}
			MISC_CHECK{
					misc_path <string> | <quoted-string> #外部脚本路径
					misc_timeout #脚本执行超时时间
					misc_dynamic #如设置该项,则退出状态码会用来动态调整服务器的权重,返回0 正常,不修改;返回1,检查失败,权重改为0;返回2-255,正常,权重设置为:返回状态码-2
			}
    }
}

3 ) nginx_check.sh

# !/bin/bash
A= 'ps -C nginx -no-header | wc -l'
if [ $A -eq 0 ];then
	/usr/sbin/nginx
	sleep 2
	if [ 'ps -C nginx --no-header | wc -l' -eq 0 ];then
		killall keepalived
	fi
fi