Nginx介绍
nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。由俄罗斯的程序设计师Igor Sysoev所开发,最初供俄国大型的入口网站及搜寻引擎Rambler(俄文:Рамблер)使用。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好.目前中国大陆使用nginx网站用户有:新浪、网易、 腾讯等。
nginx的负载均衡策略可以划分为两大类:内置策略和扩展策略。
内置策略包含加权轮询和ip hash,在默认情况下这两种策略会编译进nginx内核,只需在nginx配置中指明参数即可。
扩展策略有很多,如fair、通用hash、consistent hash,sticky(支持Session sticky) 等,默认不编译进nginx内核。
Nginx环境安装
CentOS6.3安装
[如果已安装略过该步骤]
1. 可以使用安装盘centos6.3(可以从网上下载最新的镜像文件刻录成光盘)进行linux-centos的安装,安装后设置IP等网络信息可以参考svn地址
http://192.168.1.4/svn/product_repos/AtmanDoc/TechStudy/NetWork/ Centos6.3静态IP设置.docx
JDK1.7安装
[如果已安装略过该步骤]
1. 下载lrzsz,可以通过Xshell客户端进行拖拽上传到服务器任意目录下
yum install lrzsz
2. 查看老jdk版本并卸载
#rpm -qa | grep jdk
java-1.6.0-openjdk-1.6.0.0-1.45.1.11.1.el6.x86_64
卸载
#yum remove java-1.6.0-openjdk-1.6.0.0-1.45.1.11.1.el6.x86_64
# rpm -qa | grep gcj
java-1.5.0-gcj-1.5.0.0-29.1.el6.x86_64
libgcj-4.4.6-4.el6.x86_64
#yum remove java-1.5.0-gcj-1.5.0.0-29.1.el6.x86_64
#yum remove libgcj-4.4.6-4.el6.x86_64
3. 上传jdk1.7,安装包并安装
#rpm -ivh jdk-7u10-linux-x64.rpm
4. 配置环境变量
JAVA_HOME=/usr/java/jdk1.7.0_10
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export JAVA_HOME
export PATH
export CLASSPATH
5. 立即生效
source /etc/profile
6. 检查jdk安装情况
#echo $JAVA_HOME
#echo java -version
TOMCAT7安装
[如果已安装略过该步骤]
1. 下载apache-tomcat-7.0.34.tar.gz
2. 上传并解压
tar -zxvf apache-tomcat-7.0.34.tar.gz
3. 复制并重新命名
cp -R apache-tomcat-7.0.34 /usr/local/tomcat7
4. 配置环境变量(见红色字体部分)
JAVA_HOME=/usr/java/jdk1.7.0_10
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
TOMCAT_HOME=/usr/local/tomcat7
CATALINA_HOME=/usr/local/tomcat7
export JAVA_HOME
export PATH
export CLASSPATH
export TOMCAT_HOME
export CATALINA_HOME
5. 启动/停止服务
#cd /usr/local/tomcat7/bin
#./startup.sh
#./shutdown.sh
Nginx1.2.7安装
1. 安装nginx的基础环境,如c编译环境等
yum install gcc gcc-c++ gcc-g77 pcre-devel openssl-devel bison autoconf automake make cmake libcurl-devel gd-devel zlib* fiex* libxml* ncurses-devel libmcrypt* libtool-ltdl-devel*
2. [nginx依赖]上传pcre,解压,安装pcre
#./configure --prefix=/usr/local/pcre-8.32
#make && make install
3. [nginx依赖]上传zlib,解压,安装zlib
#./configure --prefix=/usr/local/zlib-1.2.7
#make && make install
4. [nginx扩展]-黏性session模块(备注:如果不需要黏性session,该步骤可以掠过)
4.1和4.2两种黏性session方案可选1种,建议选择第二种。具体原因请看后面分析。
4.1 nginx_upstream_jvm_route
#tar -zxvf nginx-1.2.7.tar.gz
#svn checkout http://nginx-upstream-jvm-route.googlecode.com/svn/trunk/ /usr/local/nginx-jvm-route
#cd nginx源码路径
#patch -p0 < /usr/local/nginx-jvm-route/jvm_route.patch
4.2 nginx-sticky-module
#上传、解压nginx-sticky-module-1.1.tar.gz
5. [nginx安装]安装nginx(注意:pcre、zlib为源包路径,非安装后的路径)
选择nginx_upstream_jvm_route的configure命令
#./configure --prefix=/usr/local/nginx --with-pcre=/tmp/pcre-8.32 --with-zlib=/tmp/zlib-1.2.7 --with-http_stub_status_module --add-module=/usr/local/nginx-jvm-route/
选择/nginx-sticky-module的configure命令
#./configure --prefix=/usr/local/nginx --with-pcre=/tmp/pcre-8.32 --with-zlib=/tmp/zlib-1.2.7 --with-http_stub_status_module --add-module=/usr/local/nginx-sticky-module-1.1/
#make && make install
(备注:如果不需要黏性session,则“--with-http_stub_status_module --add-module=/usr/local/nginx-jvm-route/”参数可以去掉)
6. 启动/停止nginx服务
#cd /usr/local/nginx/sbin
#./nginx -c /usr/local/nginx/conf/nginx.conf (加载指定路径的配置文件)
#./nginx -s stop
Nginx负载均衡算法
轮训算法[内置]
默认情况下,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况
加权轮询的原理很简单,首先我们介绍一下轮询的基本流程。如下是处理一次请求的流程图:
图中有两点需要注意,第一,如果可以把加权轮询算法分为先深搜索和先广搜索,那么nginx采用的是先深搜索算法,即将首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器;第二,当所有后端机器都down掉时,nginx会立即将所有机器的标志位清成初始状态,以避免造成所有的机器都处在timeout的状态,从而导致整个前端被夯住。
这里处理请求时,用到了Nginx指令upstream,来实现负载均衡
nginx.conf文件:
upstream tomcat {
server 192.168.1.181:8080; //默认轮询(round robin)算法,加weight按权重排序
server 192.168.1.182:8080;
}
server{
listen 80;
server_name 192.168.1.181;
location / {
proxy_pass http://tomcat;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
配置介绍
1. 这里的upstream的name=tomcat,与server中的,location指令中proxy_pass属性的值相对应(除http://部分)
2. 在一个http{…..}指令中可以配置多个upstream 和server 指令来处理多个端口和地址。
Server指令监听地址的端口号默认为:80,请求地址为:http://localhost/
3. 在upstream 中server可以监听TCP协议和Unix域套接字混合使用:
upstream backend {
server backend1.example.com weight=5;
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3; //这里unix: 为固定模式
}
参数:weight 表示权重,默认值是1,指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。;
max_fails=number,在一段时间内,允许与服务器之间请求连接失败的次数,超过设置的次数后,Nginx将视该服务器已宕机(这里的一段时间是由fail_timeout=time 属性决定),默认值为1,值设置为0时,将不统计尝试连接的次数;
fail_timeout=time 默认值为10秒;
backup 该属性表示这个服务器是用来备用的;
down 表示该服务器永远被禁用,通常与指令ip_hash一起使用。
IP_HASH算法[内置]
ip hash是nginx内置的另一个负载均衡的策略,流程和轮询很类似,只是其中的算法和具体的策略有些变化,如下图所示:
从本质上说,ip hash算法是一种变相的轮询算法,如果两个ip的初始hash值恰好相同,那么来自这两个ip的请求将永远落在同一台服务器上,这为均衡性埋下了很深的隐患。
使用ip_hash指令来实现负载均衡和解决session问题。
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session 的问题
nginx.conf文件:
upstream tomcat {
ip_hash;
server 192.168.1.181:8080;
server 192.168.1.182:8080;
}
server{
listen 80;
server_name 192.168.1.181;
location / {
proxy_pass http://tomcat;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
这里server监听了80端口,地址拦截是冲”/”开始,与上面例子的区别在于,这里的upstream指令中,引用一个指令ip_hash,只有所有请求这个端口的客户端,都会通过cookie来实现会话的保持。
[备注:如何客户端经常变化,那么ip_hash算法则不适合,所以ip_hash适合客户端ip不变化的场合]
location指令介绍:
语法规则: location [=|~|~*|^~] /uri/ { … }
= 开头表示精确匹配
^~ 开头表示uri以某个常规字符串开头,理解为匹配 url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~ /static/ /aa匹配到(注意是空格)。
~ 开头表示区分大小写的正则匹配
~* 开头表示不区分大小写的正则匹配
!~和!~*分别为区分大小写不匹配及不区分大小写不匹配 的正则
/ 通用匹配,任何请求都会匹配到。
黏性session算法[扩展]
nginx_upstream_jvm_route方式
原理:基于cookie的stickly session(JSESSIONID)的实现
参考网页:http://code.google.com/p/nginx-upstream-jvm-route/
Tomcat1 (修改conf/server.xml)
<Engine name="Catalina" defaultHost="localhost" jvmRoute="a">
Tomcat2 (修改conf/server.xml)
<Engine name="Catalina" defaultHost="localhost" jvmRoute="b">
nginx.conf文件:
upstream tomcat {
server 192.168.1.181:8080 srun_id=a;
server 192.168.1.182:8080 srun_id=b;
jvm_route $cookie_JSESSIONID reverse;
}
server{
listen 80;
server_name 192.168.1.181;
location / {
proxy_pass http://tomcat;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
在两个tomcat部署两个测试工程,在一个测试的jsp分别打印出session和cookie信息
Tomcat1上的index.jsp
主机A </br>
session:<%out.print(request.getSession()) ;%></br>
cookie:<%out.println(request.getHeader("Cookie")); %>
Tomcat2上的index.jsp
主机B </br>
session:<%out.print(request.getSession()) ;%></br>
cookie:<%out.println(request.getHeader("Cookie")); %>
打开IE,地址栏输入http://192.168.1.181/test/index.jsp
可以看到第一次访问时,cookie为null,以后每一次cookie的值保持不变,按F5刷新,打印信息一直不变(说明所有的请求,访问的是后台tomcat是固定的)。
当关闭浏览器,重新敲入地址,访问到另外一台机器,一直刷新仍然是那个机器。
说明在一个session周期,访问的后台tomcat是固定的。下次session,可以到另外的tomcat,一旦确定,请求所访问的tomcat则固定。
只能通过JSESSIONID来实现,不能指定另外的key。而JSESSIOINID是会话cookie,当前浏览器关闭,重新开始。
nginx-sticky-module方式
原理:基于cookie的stickly session(用户自己指定的key,不能用JSESSIONID,默认为route)的实现
参考网页: https://code.google.com/p/nginx-sticky-module/wiki/Documentation
nginx.conf
upstream tomcat {
sticky name=cookieD;
server 192.168.1.181:8080;
server 192.168.1.182:8080;
}
支持用户自己指定的key,stickly的用法请参考上述网页.
很显然对两种方式,应该采用该方式!
FAIR算法[扩展]
fair策略是扩展策略,其原理是根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进行分流。这种策略具有很强的自适应性,但是实际的网络环境往往不是那么简单,因此要慎用。
通用HASH算法[扩展]
这两种也是扩展策略,在具体的实现上有些差别,通用hash比较简单,可以以nginx内置的变量为key进行hash,一致性hash采用了nginx内置的一致性hash环,可以支持memcache。
负载均衡算法比较
均衡性:是否能够将请求均匀的发送给后端
一致性:同一个key的请求,是否能落到同一台机器
容灾性:当部分后端机器挂掉时,是否能够正常工作