假如你配一个LNMP环境,每次只须要服务10个并发请求,那么单台服务器必定会比多个服务器集群要快。只有当并发或总请求数量超过单台服务器的承受能力时,服务器集群才会体现出优点。php
计算机集群架构按功能和结构能够分红如下几类:css
提示:
负载均衡集群和高可用性集群是互联网行业经常使用的集群架构模式,也是咱们要学习的重点。html
负载均衡集群的做用为:前端
负载均衡集群典型的开源软件包括LVS,Nginx,Haproxy等。以下图所示:java
提示:
不一样的业务会有若干秒的切换时间,DB业务明显长于Web业务切换时间。android
通常是指在集群中任意一个节点失效的状况下,该节点上的全部任务会自动转移到其余正常的节点上。此过程并不影响整个集群的运行。nginx
高可用性集群的做用为:git
高可用性集群经常使用的开源软件包括Keepalived,Heartbeat等,其架构图以下图所示:github
高性能计算集群也称并行计算。一般,高性能计算集群涉及为集群开发的并行应用程序,以解决复杂的科学问题(天气预报,石油勘探,核反应模拟等)。高性能计算集群对外就好像一个超级计算机,这种超级计算机内部由数十至上万个独立服务器组成,而且在公共消息传递层上进行通讯以运行并行应用程序。在生产环境中实际就是把任务切成蛋糕,而后下发到集群节点计算,计算后返回结果,而后继续领新任务计算,如此往复。web
因为不多用到,在此略
特别提示:
在互联网网站运维中,比较经常使用的就是负载均衡集群和高可用性集群
互联网企业经常使用的开源集群软件有:Nginx,LVS,Haproxy,Keepalived,heartbeat。
互联网企业经常使用的商业集群硬件有:F5,Netscaler,Radware,A10等,工做模式至关于Haproxy的工做模式。
淘宝,赶集网,新浪等公司曾使用过Netscaler负载均衡产品。集群硬件Netscaler的产品图以下图所示:
下面是我对同窗们的基本选择建议,更多的建议等你们学完负载均衡内容后再细分讲解。
相比较而言,商业的负载均衡产品成本高,性能好,更稳定,缺点是不能二次开发,开源的负载均衡软件对运维人员的能力要求较高,若是运维及开发能力强,那么开源的负载均衡软件是不错的选择,目前的互联网行业更倾向于使用开源的负载均衡软件。
负载均衡集群提供了一种廉价,有效,透明的方法,来扩展网络设备和服务器的负载,带宽和吞吐量,同时增强了网络数据处理能力,提升了网络的灵活性和可用性。
搭建负载均衡服务的需求以下:
(1)把单台计算机没法承受的大规模并发访问或数据流量分担到多台节点设备上,分别进行处理,减小用户等待响应的时间,提高用户体验。
(2)单个重负载的运算分担到多台节点设备上作并行处理,每一个节点设备处理结束后,将结果汇总,返回给用户,系统处理能力获得大幅度提升。
(3)7*24小时的服务保证,任意一个或多个有限后面节点设备宕机,不能影响业务。
在负载均衡集群中,同组集群的全部计算机节点都应该提供相同的服务。集群负载均衡器会截获全部对该服务的入站请求。而后将这些请求尽量地平均地分配在全部集群节点上。
本节先带同窗们一块儿操做实战,让同窗们对Nginx负载均衡有一个初步的概念,而后再继续深刻讲解Nginx负载均衡的核心知识应用。
上图是快速实践Nginx负载均衡的逻辑架构图
在上图中,全部用户的请求统一发送到Nginx负载均衡器,而后由负载均衡器根据调度算法来请求Web01和Web02
HOSTNAME | IP | 说明 |
---|---|---|
lb01 | 192.168.103.121 | Nginx主负载均衡器 |
lb02 | 192.168.103.122 | Nginx副负载均衡器 |
web01 | 192.168.103.123 | Web01服务器 |
web02 | 192.168.103.124 | Web02服务器 |
hostname lb01
hostname lb02
hostname web01
hostname web02
在 web01 与 web02 上安装 apache
# 安装apache [root@web01 ~]# yum install httpd -y [root@web01 init.d]# service httpd start [root@web02 ~]# yum install httpd -y [root@web02 init.d]# service httpd start # 查看是否启动 [root@web02 ~]# lsof -i :80 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME httpd 11393 root 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11394 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11395 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11396 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11397 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11409 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11410 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11411 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11412 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11413 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) httpd 11414 apache 4u IPv6 168729 0t0 TCP *:http (LISTEN) # 修改index.html页内容 [root@web01 /]# echo 192.168.103.123 >/var/www/html/index.html [root@web02 /]# echo 192.168.103.124 >/var/www/html/index.html
下面将在以上4台服务器上安装Nginx,这里只给出安装的命令部分。
# 安装上传下载组件 [root@lb01 /]# yum install lrzsz -y [root@lb02 /]# yum install lrzsz -y [root@web01 /]# yum install lrzsz -y [root@web02 /]# yum install lrzsz -y
# 安装pcre与gcc环境依赖 # lb01 [root@lb01 tools]# yum -y install openssl openssl-devel pcre pcre-devel [root@lb01 tools]# rpm -qa openssl openssl-devel pcre pcre-devel [root@lb01 tools]# yum install gcc -y # lb02 [root@lb02 tools]# yum -y install openssl openssl-devel pcre pcre-devel [root@lb02 tools]# rpm -qa openssl openssl-devel pcre pcre-devel [root@lb02 tools]# yum install gcc -y # web01 [root@web01 /]# yum -y install openssl openssl-devel pcre pcre-devel [root@web01 /]# rpm -qa openssl openssl-devel pcre pcre-devel [root@web01 /]# yum install gcc -y # web02 [root@web02 /]# yum -y install openssl openssl-devel pcre pcre-devel [root@web02 /]# rpm -qa openssl openssl-devel pcre pcre-devel [root@web02 /]# yum install gcc -y
# 上传nginx文件 [root@lb01 ~]# mkdir -p /home/oldboy/tools [root@lb01 ~]# cd /home/oldboy/tools [root@lb01 tools]# rz -y [root@lb01 tools]# tar xf nginx-1.6.2.tar.gz [root@lb01 tools]# cd nginx-1.6.2/ # 建立nginx用户 [root@lb01 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx # 安装编译 [root@lb01 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install # 创建ln连接 [root@lb01 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/ # 启动nginx [root@lb01 nginx-1.6.2]# nginx # 中止nginx # [root@lb01 nginx-1.6.2]# nginx -s stop # 查看 # [root@lb01 nginx-1.6.2]# lsof -i :80 # 上传nginx文件 [root@lb02 ~]# mkdir -p /home/oldboy/tools [root@lb02 ~]# cd /home/oldboy/tools [root@lb02 tools]# rz -y [root@lb02 tools]# tar xf nginx-1.6.2.tar.gz [root@lb02 tools]# cd nginx-1.6.2/ # 建立nginx用户 [root@lb02 nginx-1.6.2]# useradd -M -s /sbin/nologin nginx # 安装编译 [root@lb02 nginx-1.6.2]# ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module && make && make install # 创建ln连接 [root@lb02 nginx-1.6.2]# ln -s /usr/local/nginx/sbin/* /usr/local/sbin/ # 启动nginx [root@lb02 nginx-1.6.2]# nginx # 中止nginx # [root@lb02 nginx-1.6.2]# nginx -s stop # 查看 # [root@lb02 nginx-1.6.2]# lsof -i :80
本小节将在两台NginxWeb服务器的节点上操做(web01与web02):配置并查看Web服务器的配置结果。
// web01 # 添加本地主机名 [root@web01 /]# cd usr/local/nginx/conf/ [root@web01 conf]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.103.123 www.yunjisuan.com 192.168.103.123 bbs.yunjisuan.com // web02 # 添加本地主机名 [root@web02 /]# cd usr/local/nginx/conf/ [root@web02 conf]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.103.124 www.yunjisuan.com 192.168.103.124 bbs.yunjisuan.com
安装 telnet 可选
// web01 # 添加本地主机名 # 安装telnet [root@web01 /]# yum install telnet nmap dos2unix -y // web02 # 安装telnet [root@web02 /]# yum install telnet nmap dos2unix -y
配置nginx
// web01 # 配置nginx [root@web01 nginx-1.6.2]# cd /usr/local/nginx/conf/ # 删除nginx.conf.default中的#|^$,并写入nginx.conf [root@web01 conf]# egrep -v "#|^$" nginx.conf.default [root@web01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf // web02 # 安装telnet [root@web02 nginx-1.6.2]# cd /usr/local/nginx/conf/ # 删除nginx.conf.default中的#|^$,并写入nginx.conf [root@web02 conf]# egrep -v "#|^$" nginx.conf.default [root@web02 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
修改 nginx.conf
// web01 [root@web01 conf]# vim nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } } } // web02 [root@web02 conf]# vim nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } } }
这里故意将www虚拟主机放在下面,便于用后面的参数配置测试效果
// web01 [root@web01 conf]# nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful // web02 [root@web02 conf]# nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
// web01 [root@web01 conf]# nginx -s reload [root@web01 conf]# netstat -antup | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 17429/nginx: master // web02 [root@web02 conf]# nginx -s reload [root@web02 conf]# netstat -antup | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 17429/nginx: master
// web01 [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs} [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html [root@web01 /]# cat /usr/local/nginx/html/www/index.html 192.168.103.123 192.168.122.1 www [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html 192.168.103.123 192.168.122.1 bbs // web02 [root@web01 /]# mkdir /usr/local/nginx/html/{www,bbs} [root@web01 /]# echo "`hostname -I `www" >> /usr/local/nginx/html/www/index.html [root@web01 /]# cat /usr/local/nginx/html/www/index.html 192.168.103.124 192.168.122.1 www [root@web01 /]# echo "`hostname -I `bbs" >> /usr/local/nginx/html/bbs/index.html [root@web01 /]# cat /usr/local/nginx/html/bbs/index.html 192.168.103.124 192.168.122.1 bbs
// web01 [root@web01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 www [root@web01 /]# curl bbs.yunjisuan.com 192.168.103.123 192.168.122.1 bbs // web02 [root@web02 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 www [root@web02 /]# curl bbs.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
配置文档:http://nginx.org/en/docs/http/ngx_http_upstream_module.html
语法:
upstream backend { server backend1.example.com weight=5; server backend2.example.com:8080; server unix:/tmp/backend3; server backup1.example.com:8080 backup; server backup2.example.com:8080 backup; } server { location / { proxy_pass http://backend; } }
测试:(本操做基于lb01和lb02)
添加本地域名 [root@lb01 conf]# vim /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.103.121 www.yunjisuan.com
安装 telnet (可选)
# 安装telnet
[root@lb01 conf]# yum install telnet nmap dos2unix -y
# 配置nginx [root@lb01 nginx-1.6.2]# cd /usr/local/nginx/conf/ # 删除nginx.conf.default中的#|^$,并写入nginx.conf [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default [root@lb01 conf]# egrep -v "#|^$" nginx.conf.default >nginx.conf
upstream webpools { server 192.168.103.123 weight=5; server 192.168.103.124 weight=5; server 192.168.103.125 weight=5 backup; } server { location / { proxy_pass http://webpools; } }
[root@lb01 conf]# vim nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream webpools { server 192.168.103.123:80 weight=5; server 192.168.103.124:80 weight=5; server 192.168.103.125:80 weight=5 backup; } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; } } }
注意:upstream名称不能包含下划线,不然会报以下错误
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>400 Bad Request</title> </head><body> <h1>Bad Request</h1> <p>Your browser sent a request that this server could not understand.<br /> </p> <p>Additionally, a 400 Bad Request error was encountered while trying to use an ErrorDocument to handle the request.</p> </body></html>
[root@lb01 conf]# nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lb01 conf]# nginx -s reload
[root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
Nginx主配置文件nginx.conf是一个纯文本类型的文件(其余配置文件大多也是如此),它位于Nginx安装目录下的conf目录,整个配置文件是以区块的形式组织的。通常,每一个区块以一个大括号“{}”来表示,区块能够分为几个层次,整个配置文件中Main区位于最上层,在Main区下面能够有Events区,HTTP区等层级,在HTTP区中又包含有一个或多个Server区,每一个Server区中又可有一个或多个location区,整个Nginx配置文件nginx.conf的主体框架为:
[root@chensiqi conf]# egrep -v "#|^$" nginx.conf #去掉包含#号和空行的内容 worker_processes 1; #worker进程的数量 error_log logs/error.log; #错误日志(默认没开) pid logs/nginx.pid; #进程号(默认没开) events { #事件区块开始 worker_connections 1024; #每一个worker进程支持的最大链接数 } #事件区块结束 http { #http区块开始 include mime.types; #Nginx支持的媒体类型库文件包含 default_type application/octet-stream; #默认的媒体类型 sendfile on; #开启高效传输模式 keepalive_timeout 65; #链接超时。 server { #网站配置区域(第一个server第一个虚拟主机站点) listen 80; #提供服务的端口,默认80 server_name www.chensiqi.org; #提供服务的域名主机名 location / { #第一个Location区块开始 root html; #站点的根目录(相对于nginx安装路径) index index.html index.htm; #默认的首页文件,多个用空格分开 } error_page 500 502 503 504 /50x.html; #出现对应的http状态码时,使用50x.html回应客户 location = /50x.html { #Location区块开始,访问50x.html root html; #指定对应的站点目录为html } } server { #网站配置区域(第二个server第二个虚拟主机站点) listen 80; #提供服务的端口,默认80 server_name bbs.chensiqi.org; #提供服务的域名主机名 location / { #服务区块 root html; #相对路径(nginx安装路径) index index.html index.htm; } location = /50x.html { #发生错误访问的页面 root html; } } }
整个nginx配置文件的核心框架以下:
worker_processes 1; events { worker_connections 1024; } http { include mime.types; server { listen 80; server_name localhost; location / { root html; index index.html index.htm; } } }
若是是配合动态服务(例如PHP服务),Nginx软件还会用到扩展的fastcgi相关配置文件,这个配置是经过在Nginx.conf主配置文件中嵌入include命令来实现的,不过默认状况是注释状态,不会生效。
fastcgi.conf配置文件的初始内容以下:
[root@localhost conf]# cat fastcgi.conf fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
[root@localhost conf]# cat fastcgi_params fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; # PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200;
上述未作注释的目录或文件是比较少用的,有关动态扩展配置后文讲到PHP服务时再来说解。
error_log file level;
常见的日志级别【debug|info|notice|warn|error|crit|alert|emerg】
生产场景通常是warn|error|crit这三个级别之一,注意不要配置info等较低级别,会带来巨大磁盘I/O消耗。
error_log的默认值为:
# default:error_log logs/error.log error;
worker_processes 1; error_log logs/error.log; #很是简单,通常增长此行便可 events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; include extra/www.conf; include extra/mail.conf; include extra/status.conf; }
默认状况下Nginx会把全部的访问日志生成到一个指定的访问日志文件access.log里,但这样一来,时间长了就会致使日志个头很大,不利于日志的分析和处理,所以,有必要对Nginx日志,按天或按小时进行切割,使其分红不一样的文件保存。
[root@localhost nginx]# cat /server/scripts/cut_nginx_log.sh #!/bin/bash #日志切割脚本可挂定时任务,天天00点整执行 Dateformat=`date +%Y%m%d` Basedir="/usr/local/nginx" Nginxlogdir="$Basedir/logs" Logname="access" [ -d $Nginxlogdir ] && cd $Nginxlogdir || exit 1 [ -f ${Logname}.log ] || exit 1 /bin/mv ${Logname}.log ${Dateformat}_${Logname}.log $Basedir/sbin/nginx -s reload [root@localhost nginx]# cat >>/var/spool/cron/root << KOF #cut nginx access log by Mr.chen 00 00 * * * /bin/bash /server/scripts/cut_nginx_log.sh >/dev/null 2>&1
语法为:
location [ = | ~ | ~* | ^~ ] uri {
...
}
上图是对location语法的说明。上述语法中的URI部分是关键,这个URI能够是普通的字符串地址路径,或者是正则表达式,匹配成功则执行后面大括号里的相关命令。正则表达式的前面还能够有“~”或“~*”等特殊字符。
匹配这两种特殊字符“~”或“~*”的区别为:“~”用于区分大小写(大小写敏感)的匹配;“~*”用于不区分大小写的匹配。还能够用逻辑操做符“!”对上面的匹配取反,即“!~”和“!~*”。此外,“^~”的做用是先进行字符串的前缀匹配(必须之后边的字符串开头),若是能匹配到,就再也不进行其余location的正则匹配了。
location匹配示例
[root@localhost nginx]# cat /usr/local/nginx/conf/extra/www.conf server { listen 80; server_name www.yunjisuan.com; root /var/www/html/wwwcom; location / { return 401; } location = / { return 402; } location = /images/ { return 501; } location /documents/ { return 403; } location ^~ /images/ { return 404; } location ~* \.(gif|jpg|jpeg)$ { return 500; } }
匹配结果
[root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com 402 #匹配了=的状况 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/ 402 #匹配了=的状况 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/xxxx 401 #匹配不到默认匹配 /的状况 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/ 403 #匹配字符串 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/ 501 #优先匹配=的状况 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/images/1.jpg 404 #匹配 [root@localhost nginx]# curl -s -o /dev/null -w "%{http_code}\n" www.yunjisuan.com/documents/images/1.jpg 500 #匹配~*的状况
从多个location的配置匹配能够看出匹配的优先顺序
顺序 | 匹配标识的location | 匹配说明 |
---|---|---|
1 | " location = / { " | 精确匹配 |
2 | " location ^~ /images/ { " | 先进行字符串的前缀匹配,若是匹配到就不作正则匹配检查 |
3 | " loction ~* \.(gif | jpg | jpeg)$ { " | 正则匹配,*为不区分大小写 |
4 | " location /documents/ { " | 匹配常规字符串,模糊匹配,若是有正则检查,正则优先 |
5 | " location / { " | 全部location都不能匹配后的默认匹配原则 |
和Apache等Web服务软件同样,Nginx rewrite的主要功能也是实现URL地址重写。Nginx的rewrite规则须要PCRE软件的支持,即经过Perl兼容正则表达式语法进行规则匹配。默认参数编译时,Nginx就会安装支持rewrite的模块,可是,也必需要有PCRE软件的支持。
rewrite ^/(.*) http://www.baidu.com/$1 permanent;
在上述指令中,rewrite为固定关键字,表示开启一条rewrite匹配规则,regex部分是^(.*),这是一个正则表达式,表示匹配全部,匹配成功后跳转到http://www.baidu.com/$1 。这里的$1是取前面regex部分括号里的内容,结尾的permanent;是永久301重定向标记,即跳转到后面的http://www.baidu.com/$1 地址上。
rewrite指令的最后一项参数flag标记的说明
在以上的flag标记中,last和break用来实现URL重写,浏览器地址栏的URL地址不变,但在服务器端访问的程序及路径发生了变化。redirect和permanent用来实现URL跳转,浏览器地址栏会显示跳转后的URL地址。
last和break标记的实现功能相似,但两者之间有细微的差异,使用alias指令时必须用last标记,使用proxy_pass指令时要使用break标记。last标记在本条rewrite规则执行完毕后,会对其所在的server{...}标签从新发起请求,而break标记则会在本条规则匹配完成后,终止匹配,再也不匹配后面的规则。
以往咱们是经过别名方式实现yunjisuan.com和www.yunjisuan.com访问同一个地址的,事实上,除了这个方式外,还可使用nginx rewrite 301 跳转的方式来实现。实现的配置以下:
[root@localhost nginx]# cat conf/extra/www.conf #www virtualhost by Mr.chen server { listen 80; server_name www.yunjisuan.com; root /var/www/html/wwwcom; location / { index index.html index.htm; } # location = / { # return 402; # } location = /images/ { return 501; } location /documents/ { return 403; } location ^~ /images/ { return 404; } location ~* \.(gif|jpg|jpeg)$ { return 500; } } server{ listen 80; server_name yunjisuan.com; rewrite ^/(.*) http://www.yunjisuan.com/$1 permanent; #当用户访问yunjisuan.com及下面的任意内容时,都会经过这条rewrite跳转到www.yunjisuan.com对应的地址 }
upstream模块的语法至关简单,这里直接上范例给同窗们讲。
范例1:基本的upstream配置案例
upstream www_server_pools { # upstream是关键字必须有,后面的www_server_pools为一个Upstream集群组的名字,能够本身起名,调用时就用这个名字 server 192.168.103.123:80 weight=5; server 192.168.103.124:80 weight=10; server 192.168.103.125:80 weight=15;
#server关键字是固定的,后面能够接域名(门户会用)或IP。若是不指定端口,默认是80端口。weight表明权重,数值越大被分配的请求越多,结尾有分号,别忘了 }
范例2:较完整的upstream配置案例
upstream blog_server_pool { server 192.168.103.123; #这行标签和下行是等价的 server 192.168.103.124:80 weight=1 max_fails=1 fail_timeout=10s; #这行标签和上一行是等价的,此行多余的部分就是默认配置,不写也能够。 server 192.168.103.125:80 weight=1 max_fails=2 fail_timeout=20s backup; # server最后面能够加不少参数,具体参数做用看下文的表格 }
范例3:使用域名及socket的upstream配置案例
upstream backend { server backend1.example.com weight=5; server backend2.example.com:8080; #域名加端口。转发到后端的指定端口上 server unix:/tmp/backend3; #指定socket文件 #提示:server后面若是接域名,须要内网有DNS服务器或者在负载均衡器的hosts文件作域名解析。 server 192.168.103.123; server 192.168.103.124:8080; server backup1.example.com:8080 backup; #备份服务器,等上面指定的服务器都不可访问的时候会启动,backup的用法和Haproxy中用法同样 server backup2.example.com:8080 backup; }
若是是两台Web服务器作高可用,常规方案就须要keepalived配合,那么这里使用Nginx的backup参数经过负载均衡功能就能够实现Web服务器集群了,对于企业应用来讲,能作集群就不作高可用。
upstream模块的内容应放于nginx.conf配置的http{}标签内,其默认调度节点算法是wrr(weighted round-robin,即权重轮询)。
下图为upstream模块内部server标签部分参数说明
提示:
以上参数与专业的Haproxy参数很相似,但不如Haproxy的参数易懂。
来看个示例,以下:
upstream backend { server backend1.example.com weight=5; #若是就是单个Server,不必设置权重 server 127.0.0.1:8080 max_fail=5 fail_timeout=10s; #当检测次数等于5的时候,5次连续检测失败后,间隔10s再从新检测。 server unix:/tmp/backend3; server backup1.example.com:8080 backup; #热备机器设置 }
须要特别说明的是,若是是Nginx代理Cache服务,可能须要使用hash算法,此时若宕机,可经过设置down参数确保客户端用户按照当前的hash算法访问,这一点很重要。示例配置以下:
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
注意:ip_hash不能与backup共同使用
下面是Haproxy负载均衡器server标签的配置示例。
#开启对后端服务器的健康检测,经过GET /test/index.php来判断后端服务器的健康状况 server php_server_1 192.168.103.123:80 cookie 1 check inter 2000 rise 3 fall 3 weight 2 server php_server_2 192.168.103.124:80 cookie 2 check inter 2000 rise 3 fall 3 weight 1 server php_server_bak 192.168.103.125:80 cookie 3 check inter 1500 rise 3 fall 3 backup
上述命令的说明以下:
调度算法通常分为两类:
下面介绍一下常见的调度算法。
upstream yunjisuan_lb{ ip_hash; server 192.168.0.223:80; server 192.168.0.224:8080; } upstream backend{ ip_hash; server backend1.example.com; server backend2.example.com; server backend3.example.com down; server backend4.example.com; }
注意:
当负载调度算法为ip_hash时,后端服务器在负载均衡调度中的状态不能有weight和backup,即便有也不会生效。
upstream yunjisuan_lb{ server 192.168.103.123; server 192.168.103.124; fair; }
upstream yunjisuan_lb { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }
http { upstream test { consistent_hash $request_uri; server 127.0.0.1:9001 id=1001 weight=3; server 127.0.0.1:9002 id=1002 weight=10; server 127.0.0.1:9003 id=1003 weight=20; } }
虽然Nginx自己不支持一致性hash算法,但Nginx得分支Tengine支持。详细可参考http://tengine.taobao.org/document_cn/http_upstream_consistent_hash_cn.html
proxy_pass指令属于 ngx_http_proxy_module 模块,此模块能够将请求转发到另外一台服务器,在实际的反向代理工做中,会经过location功能匹配指定的URI,而后把接收到的符合匹配URI的请求经过proxy_pass抛给定义好的upstream节点池。该指令官方地址1见:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass
下面proxy_pass的使用案例:
location /name/ { proxy_pass http://127.0.0.1/remote/; }
location /some/path/ { proxy_pass http://127.0.0.1; }
location /name/ { rewrite /name/( [^/]+ ) /username=$1 break; proxy_pass http://127.0.0.1; }
Nginx的代理功能是经过http proxy模块来实现的。默认在安装Nginx时已经安装了http proxy模块,所以可直接使用http proxy模块。下面详细解释模块1中每一个选项表明的含义,见下表:
主机名 | IP地址 | 角色说明 |
---|---|---|
lb01 | 192.168.103.121 | nginx主负载均衡 |
lb02 | 192.168.103.122 | nginx从负载均衡 |
Web01 | 192.168.103.123 | nginx web01服务器 |
Web02 | 192.168.103.124 | nginx web02服务器 |
查看lb01的配置文件以下:
// lb01 [root@lb01 /]# cat /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream webpools { #默认调度算法wrr,即权重轮询算法 #虽然定义的www服务器池可是这个服务器池也能够做为BBS等业务的服务器池。由于节点服务器的虚拟主机都是根据访问的主机头字段区分的。 #若是就是单个Server,不必设置权重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #热备机器设置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; #经过proxy_pass功能把用过户的请求交给上面反向代理upstream定义的webpools服务器池处理。 } } }
如今配置hosts解析到代理服务器lb01上,从新加载服务,访问测试
[root@lb01 /]# tail -2 /etc/hosts 192.168.103.121 www.yunjisuan.com 192.168.103.121 bbs.yunjisuan.com [root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload [root@lb01 /]# tail -2 /etc/hosts 192.168.103.121 www.yunjisuan.com 192.168.103.121 bbs.yunjisuan.com [root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload [root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
从测试结果能够看出,已经实现了反向代理,负载均衡功能,可是有一个特殊问题,出来的结果并非带有www的字符串,而是bbs的字符串,根据访问结果,咱们推测是访问了Web节点下bbs的虚拟主机,明明代理的是www虚拟主机,为何结果是访问了后端的bbs虚拟主机了呢?问题又该如何解决?请同窗们继续往下看。
上一节代理的结果不对,究其缘由是当用户访问域名时确实是携带了www.yunjisuan.com主机头请求Nginx反向代理服务器,可是反向代理向下面节点从新发起请求时,默认并无在请求头里告诉节点服务器要找哪台虚拟主机,因此,Web节点服务器接收到请求后发现没有主机头信息,所以,就把节点服务器的第一个虚拟主机发给了反向代理了(节点上第一个虚拟主机放置的是故意这样放置的bbs)。解决这个问题的方法,就是当反向代理向后从新发起请求时,要携带主机头信息,以明确告诉节点服务器要找哪一个虚拟主机。具体的配置很简单,就是在Nginx代理www服务虚拟主机配置里增长以下一行配置便可:
proxy_set_header host $host;
在代理向后端服务器发送的http请求头中加入host字段信息后,若后端服务器配置有多个虚拟主机,它就能够识别代理的是哪一个虚拟主机。这是节点服务器多虚拟主机时的关键配置。整个Nginx代理配置为:
// lb01 [root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream webpools { #若是就是单个Server,不必设置权重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #热备机器设置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; proxy_set_header host $host; #在代理向后端服务器发送的http请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时,能够识别代理的是哪一个虚拟主机。这是节点服务器多虚拟主机时的关键配置。 } } }
此时,再从新加载Nginx服务,并用curl测试检查,结果以下:
[root@lb01 /]# curl www.yunjisuan.com 192.168.103.123 192.168.122.1 www [root@lb01 /]# curl www.yunjisuan.com 192.168.103.124 192.168.122.1 www [root@lb01 /]# curl bbs.yunjisuan.com 192.168.103.123 192.168.122.1 bbs [root@lb01 /]# curl bbs.yunjisuan.com 192.168.103.124 192.168.122.1 bbs
能够看到此次访问的结果和访问的域名就彻底对应上了,这样代理多虚拟主机的节点服务器就不会出问题了
修改 nginx.config 记录日志
// web01 [root@web01 conf]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"'; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } } // web02 [root@web02 conf]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"'; server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } }
完成了反向代理WWW服务后,天然很开心,可是,不久后你用其余客户端做为客户端测试时,就会发现一个问题,节点服务器对应的WWW虚拟主机的访问日志的第一个字段记录的并非客户端的IP,而是反向代理服务器的IP,最后一个字段也是“-”!
例如:使用任意windows客户端计算机( 192.168.103.204 ),访问已经解析好代理IP的www.yunjisuan.com后,去节点服务器www服务日志查看,就会发现以下日志:
[root@web02 logs]# tail -2 /usr/local/nginx/logs/access_www.log 192.168.103.121--[29/Aug/2019:17:29:23 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-" 192.168.103.121--[29/Aug/2019:17:29:33 +0800]"GET / HTTP/1.0"200 34 "-""curl/7.29.0""-"
Web01节点服务器对应的WWW虚拟主机的访问日志的第一个字段记录的并非客户端的IP而是反向代理服务器自己的IP(192.168.103.121),最后一个字段也是一个“-”,那么如何解决这个问题?其实很简单,一样是增长以下一行参数:
proxy_set_header X-Forwarded-For $remote_addr;
#这是反向代理时,节点服务器获取用户真实IP的必要功能配置
解决上述问题的整个Nginx代理配置为:
//lb01 [root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream webpools { #若是就是单个Server,不必设置权重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #热备机器设置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; proxy_set_header host $host; #在代理向后端服务器发送的http请求头中加入host字段信息,用于当后端服务器配置有多个虚拟主机时,能够识别代理的是哪一个虚拟主机。这是节点服务器多虚拟主机时的关键配置。 proxy_set_header X-Forwarded-For $remote_addr; #在代理向后端服务器发送的http请求头中加入X-Forwarded-For字段信息,用于后端服务器程序,日志等接收记录真实用户的IP,而不是代理服务器的IP } } }
从新加载Nginx反向代理服务:
[root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
特别注意,虽然反向代理已经配好了,可是节点服务器须要的访问日志若是要记录用户的真实IP,还必须进行日志格式配置,这样才能把代理传过来的X-Forwarded-For头信息记录下来,具体配置为:
// web01 [root@web01 /]# vim usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"'; #就是这里的“$http_x_forwarded_for”参数,若是但愿在第一行显示,能够替换掉第一行的$remote_addr变量。 server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } } // web02 [root@web02 /]# vim usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; log_format main '$remote_addr-$remote_user[$time_local]"$request"' '$status $body_bytes_sent "$http_referer"' '"$http_user_agent""$http_x_forwarded_for"'; #就是这里的“$http_x_forwarded_for”参数,若是但愿在第一行显示,能够替换掉第一行的$remote_addr变量。 server { listen 80; server_name bbs.yunjisuan.com; location / { root html/bbs; index index.html index.htm; } access_log logs/access_bbs.log main; } server { listen 80; server_name www.yunjisuan.com; location / { root html/www; index index.html index.htm; } access_log logs/access_www.log main; } }
完成Web01,Web02节点服务器的日志配置后,就能够检查了,注意,不要用curl从反向代理上检查,最好换一个客户端检查,这样才能看到效果。这里使用Windows客户端计算机(IP为192.168.103.204)访问已经解析好代理IP的www.yunjisuan.com,以下图所示:
// web01 [root@web01 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 192.168.103.121--[29/Aug/2019:18:02:38 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204" 192.168.103.121--[29/Aug/2019:18:02:42 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204" // web02 [root@web02 /]# tail -2 /usr/local/nginx/logs/access_bbs.log 192.168.103.121--[29/Aug/2019:18:02:41 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204" 192.168.103.121--[29/Aug/2019:18:02:44 +0800]"GET / HTTP/1.0"200 34 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36""192.168.103.204"
其中,日志里的192.168.103.121为反向代理的IP,对应Nginx日志格式里的$remote_addr变量,而日志结尾的192.168.103.204对应的时日志格式里的“$http_x_forwarded_for”变量,即接收了前面反向代理配置中“proxy_set_header X-Forwarded-For $remote_addr;”参数X-Forwarded-For的IP了。
关于X-Forwarded-For的详细说明,可见http://en.wikipedia.org/wiki/X-Forwwawrded-For。下图是反向代理相关重要基础参数的总结,供同窗们参考。
除了具备多虚拟主机代理以及节点服务器记录真实用户IP的功能外,Nginx软件还提供了至关多的做为反向代理和后端节点服务器对话的相关控制参数,具体见前面在讲解proxy模块时提供的图表。
相信同窗们对这些参数有了必定了解了,因为参数众多,最好把这些参数放到一个配置文件里,而后用include方式包含到虚拟主机配置里,效果以下:
//lb01 # 建立配置文件 [root@lb01 /]# vim /usr/local/nginx/conf/proxy.conf proxy_set_header host $host; proxy_set_header x-forwarded-for $remote_addr; proxy_connect_timeout 60; proxy_send_timeout 60; proxy_read_timeout 60; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; #修改配置 [root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream webpools { #若是就是单个Server,不必设置权重 server 192.168.103.123:80 weight=5 max_fails=1 fail_timeout=60s; #当检测次数等于1的时候,1次连续检测失败后,间隔60s再从新检测。 server 192.168.103.124:80 weight=5; server 192.168.103.124:80 weight=5 backup; #热备机器设置 } server { listen 80; server_name www.yunjisuan.com; location / { root html; index index.html index.htm; proxy_pass http://webpools; include proxy.conf; } } } # 从新加载 [root@lb01 /]# nginx -s reload
更多Nginx反向代理参数说明:
http://nginx.org/en/docs/http/ngx_http_proxy_module.html
案例背景:
经过Nginx实现动静分离,即经过Nginx反向代理配置规则实现让动态资源和静态资源及其余业务分别由不一样的服务器解析,以解决网站性能,安全,用户体验等重要问题。
下图为企业常见的动静分离集群架构图,此架构图适合网站前端只使用同一个域名提供服务的场景,例如,用户访问的域名是www.yunjisuan.com,而后,当用户请求www.yunjisuan.com/upload/xx地址时候,代理会分配请求到上传服务器池处理数据;当用户请求www.yunjisuan.com/static/xx地址的时候,代理会分配请求到静态服务器池请求数据;当用户请求www.yunjisuan.com/xx地址的时候,即不包含上述指定的目录地址路径时,代理会分配请求到默认的动态服务器池请求数据(注意:上面的xx表示任意路径)。
先进行企业案例需求梳理:
了解了需求后,就能够进行upstream模块服务器池的配置了。
//lb01 #static_pools为静态服务器池,有一个服务器,地址为192.168.103.123,端口为80. upstream staticpools { server 192.168.103.123:80 weght=1; } #upload_pools为上传服务器池,有一个服务器地址为192.168.103.124,端口为80. upstream uploadpools { server 192.168.103.124:80 weight=1; } #default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为192.168.103.125,端口为80. upstream defaultpools { server 192.168.103.125:80 weight=1; } #提示:须要增长一台测试Web节点Web03(ip:192.168.103.125),配置与Web01,Web02同样。
下面利用location或if语句把不一样的URI(路径)请求,分给不一样的服务器池处理,具体配置以下。
方案1:以location方案实现
//lb01 #将符合static的请求交给静态服务器池static_pools,配置以下: location /static/ { proxy_pass http://staticpools; include proxy.conf; } #将符合upload的请求交给上传服务器池upload_pools,配置以下: location /upload/ { proxy_pass http://uploadpools; include proxy.conf; } #不符合上述规则的请求,默认所有交给动态服务器池default_pools,配置以下: location / { proxy_pass http://defaultpools; include proxy.conf; }
方案2:以if语句实现。
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name www.yunjisuan.com; location / { if ($request_uri ~* "^/static/(.*)$") { proxy_pass http://staticpools/$1; } if ($request_uri ~* "^/upload/(.*)$") { proxy_pass http://uploadpools/$1; } proxy_pass http://defaultpools; include proxy.conf; } } }
从新加载配置生效,以下:
[root@lb01 /]# /usr/local/nginx/sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful [root@lb01 /]# /usr/local/nginx/sbin/nginx -s reload
暂时不要马上测试成果,为了实现上述代理的测试,还须要在Web01和Web02上作节点的测试配置,才能更好地展现测试效果。
以Web01做为static静态服务,地址端口为:192.168.103.123:80,须要事先配置一个用于测试静态的地址页面,并测试访问,肯定它会返回正确结果。操做步骤以下:
// web01 [root@web01 /]# mkdir -p /usr/local/nginx/html/www/static [root@web01 /]# echo "static_pools www" >> /usr/local/nginx/html/www/static/index.html [root@web01 /]# mkdir -p /usr/local/nginx/html/bbs/static [root@web01 /]# echo "static_pools bbs" >> /usr/local/nginx/html/bbs/static/index.html [root@web01 /]# curl http://www.yunjisuan.com/static/index.html #这里的www.yunjisuan.com是解析过的Web01的本地IP static_pools www [root@web01 /]# curl http://bbs.yunjisuan.com/static/index.html #这里的bbs.yunjisuan.com是解析过的Web01的本地IP static_pools bbs #提示:测试的静态地址为http://www.yunjisuan.com/static/index.html,注意,是带static路径的地址。
以Web02做为upload上传服务,地址端口为:192.168.103.124:80,须要事先配置一个用于测试上传服务的地址页面,并测试访问,肯定它会返回正确结果。操做步骤以下:
// web02 [root@web02 ~]# mkdir -p /usr/local/nginx/html/www/upload/ [root@web02 ~]# echo "upload_pools www" >> /usr/local/nginx/html/www/upload/index.html [root@web02 ~]# mkdir -p /usr/local/nginx/html/bbs/upload [root@web02 ~]# echo "upload_pools bbs" >> /usr/local/nginx/html/bbs/upload/index.html [root@web02 ~]# curl http://www.yunjisuan.com/upload/index.html #这里的www.yunjisuan.com是解析过的Web02的本地IP upload_pools www [root@web02 ~]# curl http://bbs.yunjisuan.com/upload/index.html #这里的bbs.yunjisuan.com是解析过的Web02的本地IP upload_pools bbs #提示:测试的上传地址为http://www.yunjisuan.com/upload/index.html,注意,是带upload路径的地址。
在Web03做为动态服务节点,地址端口为192.168.103.125:80,一样须要事先配置一个默认的地址页面,并测试访问,肯定它会返回正确结果。操做步骤以下:
[root@web03 /]# cd /usr/local/nginx/html/www [root@web03 www]# echo "default_pools" > index.html [root@web03 www]# curl http://www.yunjisuan.com default_pools
以上准备了上台Web节点服务器,分别加入到了upstream定义的不一样服务器池,表明三组不一样的业务集群组,从本机经过hosts解析各自的域名,而后测试访问,其地址与实际访问的内容输出请对照下表:
节点 | IP及端口 | 测试地址 | 字符串为表明业务 |
---|---|---|---|
web01 | 192.168.103.123:80 | http://www.yunjisuan.com/static/index.html | static_pools |
web02 | 192.168.103.124:80 | http://www.yunjisuan.com/upload/index.html | upload_pools |
web03 | 192.168.103.125:80 | http://www.yunjisuan.com | default_pools |
使用客户端计算机访问测试时,最好选用集群之外的机器,这里先在浏览器客户端的hosts文件里把www.yunjisuan.com解析到Nginx反向代理服务器的IP,而后访问上述URL,看代理是否是把请求正确地转发到了指定的服务器上。若是能够获得与上表对应的内容,表示配置的Nginx代理分发的彻底正确,由于若是分发请求到错误的机器上就没有对应的URL页面内容,输出会是404错误。
[root@lb01 /]# curl http://www.yunjisuan.com/static/index.html static_pools www [root@lb01 /]# curl http://www.yunjisuan.com/upload/index.html upload_pools www [root@lb01 /]# curl http://www.yunjisuan.com default_pools
实际配置以下:
// lb01
[root@lb01 /]# vim /usr/local/nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # static_pools为静态服务器池,有一个服务器,地址为192.168.103.123,端口为80. upstream staticpools { server 192.168.103.123:80 ; } # upload_pools为上传服务器池,有一个服务器地址为192.168.103.124,端口为80. upstream uploadpools { server 192.168.103.124:80 ; } # default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为192.168.103.125,端口为80. upstream defaultpools { server 192.168.103.125:80 ; } server { listen 80; server_name www.yunjisuan.com; location /static/ { proxy_pass http://staticpools; include proxy.conf; } location /upload/ { proxy_pass http://uploadpools; include proxy.conf; } location / { proxy_pass http://defaultpools; include proxy.conf; } } }
在企业中,为了让不一样的客户端设备用户访问有更好的体验,须要在后端架设不一样服务器来知足不一样的客户端访问,例如:移动客户端访问网站,就须要部署单独的移动服务器及程序,体验才能更好,并且移动端还分苹果,安卓,Ipad等,在传统的状况下,通常用下面的办法解决这个问题。
此解决方案的最大问题就是不一样客户端的用户要记住对应的域名!而绝大多数用户只会记住www.yunjisuan.com,不会记住wap.yunjisuan.com,这样一来就会致使用户体验不是很好。有没有办法让全部客户端用户只访问一个统一的www.yunjisuan.com这个地址,还能让不一样客户端设备都能有更好的访问体验呢?固然有!那就是下面的第7层负载均衡解决方案。
这里仍是使用static_pools,upload_pools做为本次实验的后端服务器池。下面先根据计算机客户端浏览器的不一样设置对应的匹配规则。(因为没有合适的实验验证环境,这里仅做需求实现的细节讲解)
//lb01 location / { if ($http_user_agent ~* "MSIE") # 若是请求的浏览器为微软IE浏览器(MSIE),则让请求由static_pools池处理 { proxy_pass http://staticpools; } if ($http_user_agent ~* "Chrome") # 若是请求的浏览器为谷歌浏览器(Chrome),则让请求由upload_pools池处理 { proxy_pass http://uploadpools; } # 其余客户端,由default_pools处理 proxy_pass http://defaultpools; include proxy.conf; }
除了针对浏览器外,上述“$http_user_agent”变量也可针对移动端,好比安卓,苹果,Ipad设备进行匹配,去请求指定的服务器,具体细节配置以下:
//lb01 location / { if ($http_user_agent ~* "android") { proxy_pass http://android_pools; #这里是android服务器池 } if ($http_user_agent ~* "iphone") { proxy_pass http://iphone_pools; #这里是iphone服务器池 } proxy_pass http://pc_pools; #这里是默认的pc服务器池 include extra/proxy.conf; }
192.168.0.110--[28/Jul/2017:02:12:10 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)""-" #PCwindows访问日志 192.168.0.106--[28/Jul/2017:02:12:22 -0400]"GET / HTTP/1.1"200 18 "-""Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_3 like Mac OS X) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.0 Mobile/14G60 Safari/602.1""-" #苹果iphone6手机设备访问的日志。
除了根据URI路径及user_agent转发外,还能够实现根据文件扩展名进行转发(这里仅以细节配置做为讲解内容,如需测试请同窗们自行实验)
#先看看location方法的匹配规则,以下: location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ { proxy_pass http://static_pools; include proxy.conf; } #下面是if语句方法的匹配规则: if ($request_uri ~* ".*\.(php|php5)$") { proxy_pass http://php_server_pools; } if ($request_uri ~* ".*\.(jsp|jsp*|do|do*)$") { proxy_pass http://java_server_pools; }
可根据扩展名实现资源的动静分离访问,如图片,视频等请求静态服务器池,PHP,JSP等请求动态服务器池。
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css|js)$ { proxy_pass http://static_pools; include proxy.conf; } location ~ .*\.(php|php3|php5)$ { proxy_pass http://dynamic_pools; include proxy.conf }
在开发没法经过程序实现动静分离的时候,运维能够根据资源实体进行动静分离,而不依赖于开发,具体实现策略是先把后端的服务器分红不一样的组。注意,每组服务器的程序都是相同的,由于开发没有把程序拆开,分组后,在前端代理服务器上经过讲解过的路径,扩展名进行规则匹配,从而实现请求的动静分离。
淘宝技术团队开发了一个Tengine(Nginx的分支)模块Nginx_upstream_check_module,用于提供主动式后端服务器健康检查。经过它能够检测后端realserver的健康状态,若是后端realserver不可用,则全部的请求就不会转发到该节点上。
Tengine原生支持这个模块,而Nginx则须要经过打补丁的方式将该模块添加到Nginx中。补丁下载地址:https://github.com/yaoweibin/nginx_upstream_check_module。下面介绍如何使用这个模块。
#系统已经安装了nginx-1.10.2软件 [root@lb01 ~]# /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.10.2 #下载补丁包 [root@lb01 ~]# wget https://codeload.github.com/786744873/nginx_upstream_check_module/zip/master [root@lb01 ~]# unzip master [root@lb01 ~]# ls anaconda-ks.cfg install.log install.log.syslog master nginx-1.10.2.tar.gz nginx_upstream_check_module-master [root@lb01 nginx-1.10.2]# mv ~/nginx_upstream_check_module-master /usr/src/ #由于是对源程序打补丁,因此还须要Nginx源程序 [root@lb01 ~]# cd /usr/src/nginx-1.10.2/ [root@lb01 nginx-1.10.2]# patch -p0 < /usr/src/nginx_upstream_check_module-master/check_1.9.2+.patch patching file src/http/modules/ngx_http_upstream_hash_module.c patching file src/http/modules/ngx_http_upstream_ip_hash_module.c patching file src/http/modules/ngx_http_upstream_least_conn_module.c patching file src/http/ngx_http_upstream_round_robin.c patching file src/http/ngx_http_upstream_round_robin.h #备份源安装程序 [root@lb01 nginx-1.10.2]# cd /usr/local/ [root@lb01 local]# ls bin etc games include lib lib64 libexec nginx sbin share src [root@lb01 local]# mv nginx{,.ori} [root@lb01 local]# ls bin etc games include lib lib64 libexec nginx.ori sbin share src [root@lb01 local]# cd /usr/src/nginx-1.10.2/ #从新进行编译,编译的参数要和之前一致,最后加上 --add-module=/usr/src/nginx_upstream_check_module-master/ [root@lb01 nginx-1.10.2]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/ [root@lb01 local]# /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.10.2 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) built with OpenSSL 1.0.1e-fips 11 Feb 2013 TLS SNI support enabled configure arguments: --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_stub_status_module --add-module=/usr/src/nginx_upstream_check_module-master/ #拷贝源配置文件到当前Nginx的安装目录下 [root@lb01 local]# pwd /usr/local [root@lb01 local]# cp nginx.ori/conf/nginx.conf nginx/conf/ cp: overwrite `nginx/conf/nginx.conf'? y [root@lb01 local]# cp nginx.ori/conf/proxy.conf nginx/conf/ [root@lb01 local]# /usr/local/nginx/sbin/nginx -t nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@lb01 local]# vim nginx/conf/nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; # static_pools为静态服务器池,有一个服务器,地址为192.168.103.123,端口为80. upstream staticpools { server 192.168.103.123:80 ; check interval=3000 rise=2 fall=5 timeout=1000 type=http; #对static服务器池开启健康监测 } # upload_pools为上传服务器池,有一个服务器地址为192.168.103.124,端口为80. upstream uploadpools { server 192.168.103.124:80 ; check interval=3000 rise=2 fall=5 timeout=1000 type=http; #对static服务器池开启健康监测 } # default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为192.168.103.125,端口为80. upstream defaultpools { server 192.168.103.125:80 ; check interval=3000 rise=2 fall=5 timeout=1000 type=http; #对static服务器池开启健康监测 } server { listen 80; server_name www.yunjisuan.com; location / { if ($http_user_agent ~* "MSIE") #若是请求的浏览器为微软IE浏览器(MSIE),则让请求由static_pools池处理 { proxy_pass http://staticpools; } if ($http_user_agent ~* "Chrome") #若是请求的浏览器为谷歌浏览器(Chrome),则让请求由upload_pools池处理 { proxy_pass http://uploadpools; } proxy_pass http://defaultpools; include proxy.conf; } location /status { check_status; #启动健康检查模块 access_log off; #关闭此location的访问日志记录 } } }
[root@lb01 local]# killall nginx [root@lb01 local]# /usr/local/nginx/sbin/nginx [root@lb01 local]# netstat -antup | grep nginx tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 20908/nginx: master
check interval=3000 rise=2 fall=5 timeout=1000 type=http;
上面配置的意思时,对static_pools这个负载均衡条目中的全部节点,每隔3秒检测一次,请求2次正常则标记realserver状态为up,若是检测5次都失败,则标记realserver的状态为down,超时时间为1秒,检查的协议是HTTP。
详细用法见官网:http://tengine.taobao.org/document_cn/http_upstream_check_cn.html
关闭任意一个RS节点后(3个Web服务器任选一个关闭nginx服务)
当Nginx接收后端服务器返回proxy_next_upstream参数定义的状态码时,会将这个请求转发给正常工做的后端服务器,例如500,502,503,504,此参数能够提高用户的访问体验,具体配置以下:
server { listen 80; server_name www.yunjisuan.com; location / { proxy_pass http://static_pools; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; include proxy.conf; } }