目录
前言
1 nginx与apache的区别
2 软件安装
2.1 安装说明
2.2 nginx安装
2.2.1 依赖包安装
2.2.2 nginx安装
2.2.3 测试
2.3 redis安装
3 集群配置
3.1 nginx配置
3.2 测试
3.2.1 创建测试项目
3.2.2 发布项目
3.2.3 测试集群
4 session共享
4.1 相关jar包下载
4.2 相关配置
4.3 测试
4.3.1 修改项目文件
4.3.2 测试
5 总结
之前,我们对服务器集群也有了一定的理解,这里就不多做解释了,可参考此处Tomcat集群搭建(APACHE+MOD_JK+TOMCAT配置)。
在搭建apache服务器的时候,就发现其中的步骤很复杂,因为其依赖了很多包,如apr、apr-util、expat-devel和libtool-ltdl-devel等等,同时在安装的过程中根据不同的环境还得修改相应的安装文件才能成功安装。而且,apache处理http请求并非像nginx那样非阻塞,而是阻塞的,故其处理请求的效率上并没有nginx那么高。
二者最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程 。nginx处理静态文件好,耗费内存少.但无疑apache仍然是目前的主流,有很多丰富的特性.所以还需要搭配着来.当然如果能确定nginx就适合需求,那么使用nginx会是更经济的方式。
nginx是很不错的前端服务器,负载性能很好,用webbench模拟10000个静态文件请求毫不吃力,其负载能力比apache高很多。但是,apache在处理动态有优势,nginx并发性比较好,CPU内存占用低,如果rewrite频繁,那还是apache比较好。
下面说下两者间的优缺点
nginx相对于apache的优点:
(1)轻量级,同样web 服务,比apache 占用更少的内存及资源 ;
(2)抗并发,nginx 本身就是一个反向代理服务器,处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能,而apache 则不然;
(3)高度模块化的设计,编写模块相对简单,其社区也非常活跃,各种高性能模块出品迅速;
(4)nginx 配置文件写的很简洁,正则配置让很多事情变得简单运行效率高,占用资源少,代理功能强大,很适合做前端响应服务器。
apache相对于nginx的优点:
(1)rewrite,比nginx 的rewrite 强大;
(2)很多模块,毕竟发展的时间比较长,基本想到的都可以找到;
(3)稳定和成熟,比较少bug,而nginx 相对来说还是比较年轻,nginx的bug 相对比较多。
这里用的linux版本是centos 7,需要安装的软件有jdk、tomcat、redis和nginx,其中nginx又依赖于gzip模块(需要zlib库,可在http://www.zlib.net/下载)、rewrite模块(需要pcre库,可在http://www.pcre.org/下载)和ssl模块(需要openssl库,可在http://www.openssl.org/下载)。
nginx的依赖包安装顺序依次为openssl、zlib、pcre。
相关软件包说明如下
jdk:jdk-8u181-linux-x64.tar.gz
tomcat:apache-tomcat-7.0.90.tar.gz
redis:redis-4.0.10.tar.gz
nginx:nginx-1.6.2.tar.gz、openssl-1.0.2o.tar.gz、zlib-1.2.11.tar.gz、pcre-8.38.tar.gz
其中,jdk和tomcat的下载安装这里就不多说了,网上很多可以找到,或参考此处Tomcat集群搭建(APACHE+MOD_JK+TOMCAT配置)。
(1)安装需要依赖的其他库
yum -y install make gcc-c++ libtool
yum -y install lrzsz
(2)解压openssl依赖库
#将下载的openssl-1.0.2o.tar.gz上传到系统目录/usr/softwares
rz
#进入安装包目录
cd /usr/softwares
#解压安装包
tar -xzvf openssl-1.0.2o.tar.gz
#不需要安装,下面步骤可以不用执行
#安装
cd openssl-1.0.2o
./config --prefix=/usr/openssl #此处将安装的所有文件配置到/usr/openssl
#编译和安装
make && make install
(3)解压zlib依赖库
#将下载的zlib-1.2.11.tar.gz上传到系统目录/usr/softwares
rz
#进入安装包目录
cd /usr/softwares
#解压安装包
tar -xzvf zlib-1.2.11.tar.gz
#不需要安装,下面步骤可以不用执行
#安装
cd zlib-1.2.11
./configure --prefix=/usr/zlib #此处将安装的所有文件配置到/usr/zlib
#编译和安装
make && make install
(4)解压pcre依赖库
#将下载的pcre-8.38.tar.gz上传到系统目录/usr/softwares
rz
#进入安装包目录
cd /usr/softwares
#解压安装包
tar -xzvf pcre-8.38.tar.gz
#不需要安装,下面步骤可以不用执行
#安装
cd pcre-8.38
./configure --prefix=/usr/pcre #此处将安装的所有文件配置到/usr/pcre
#编译和安装
make && make install
1) 解压
#将下载的nginx-1.6.2.tar.gz上传到系统目录/usr/softwares
rz
#进入安装包目录
cd /usr/softwares
#解压安装包
tar -xzvf nginx-1.6.2.tar.gz
2) 安装
cd nginx-1.6.2
./configure --prefix=/usr/nginx --with-openssl=/usr/softwares/openssl-1.0.2o --with-zlib=/usr/softwares/zlib-1.2.11 --with-pcre=/usr/softwares/pcre-8.38
#这里需要注意的是,nginx的安装与apache的安装不一样,apache安装时--with的目录地址均是编译安装后的目录地址,而nginx安装时--with的目录地址是原始解压后的目录地址
#故我在想是不是openssl、zlib和pcre是不是压根就不需要安装,只要直接解压出来就可以了,实时证明是真的不需要安装的
#编译和安装
make && make install
开启nginx
cd /usr/nginx
./sbin/nginx
nginx的相关命令
前提,需要在nginx的安装编译后的目录下
./sbin/nginx #开启nginx服务
./sbin/nginx -s reload|reopen|stop|quit #重新加载配置|重启|停止|退出 nginx
./sbin/nginx -t #测试配置是否有语法错误
访问网页,http://192.168.17.132/,这里需要注意的是,若80端口没开放则访问不了,需要防火墙开启80端口可参考这里https://blog.csdn.net/qq_15092079/article/details/81460237。
1) 解压
#将下载的redis-4.0.10.tar.gz上传到系统目录/usr/softwares
rz
#进入安装包目录
cd /usr/softwares
#将安装包移至/usr/redis目录
mkdir /usr/redis
mv redis-4.0.10.tar.gz /usr/redis
#解压安装包
cd /usr/redis
tar -xzvf redis-4.0.10.tar.gz
2) 安装
cd redis-4.0.10
make
3) 启动
./src/redis-server
#注意这种方式启动redis 使用的是默认配置。也可以通过启动参数告诉redis使用指定配置文件使用下面命令启动。
./src/redis-server ./redis.conf
#redis.conf 是一个默认的配置文件。我们可以根据需要使用自己的配置文件。
启动redis服务进程后,就可以使用测试客户端程序redis-cli和redis服务交互了。
cd src
.src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"
至此redis安装成功!
这里需要特别说明一下,若redis与tomcat不在同一台机器的话,还需作相应的配置,否则会报错redis拒绝连接
#编辑redis的配置文件redis.conf
vim /usr/redis/redis-4.0.10/redis.conf
#找到requirepass将其前面的#去掉,设置密码(永久型,不会因为redis重启而失效)如下,否则redis在受保护状态拒绝局域网访问
requirepass 123456
#找到bind 127.0.0.1,将其用#注释掉,否则redis只能被本机访问
#bind的意思是只运行指定IP访问
#密码登陆
127.0.0.1:6379> auth 123456
1) 进入nginx安装后的目录
cd /usr/nginx
2) 修改nginx的配置文件nginx.conf
vim conf/nginx.conf
在http { 内添加:
#Tomcat
upstream sky {
server 192.168.33.10:8080 max_fails=1 fail_timeout=10s;
server 192.168.33.10:8081 max_fails=1 fail_timeout=10s;
}
在http { 的 server { 的 location / { 内添加:
proxy_pass http://sky;
保存配置::wq
3) 重新加载nginx配置
./sbin/nginx -s reload
说明,nginx的负载均衡方式有好几种,分别有轮询方式(默认)、weight加权轮询、ip_hash方式、fair方式和url_hash方式。
weight加权轮询,指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
upstream qwe{
server 10.0.0.77 weight=5;#访问率比较低
server 10.0.0.88 weight=10;#访问率比较高
}
ip_hash方式,每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream qwe{
ip_hash;
server 10.0.0.77;
server 10.0.0.88;
}
fair方式,按后端服务器的响应时间来分配请求,响应时间短的优先分配。与weight分配策略类似。
upstream qwe{
fair;
server 10.0.0.77;
server 10.0.0.88;
}
url_hash方式,按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。注意:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法。
upstream qwe{
hash $request_uri;
hash_method crc32;
server 10.0.0.77;
server 10.0.0.88;
}
关于nginx.conf配置文件的详细说明,可见下面
########### 每个指令必须有分号结束。#################
#user administrator administrators; #配置用户或者组,默认为nobody nobody。
#worker_processes 2; #允许生成的进程数,默认为1
#pid /nginx/pid/nginx.pid; #指定nginx进程运行文件存放地址
error_log log/error.log debug; #制定日志路径,级别。这个设置可以放入全局块,http块,server块,级别以此为:debug|info|notice|warn|error|crit|alert|emerg
worker_processes 2; #Nginx 请求处理进程数量, 一般设定为CPU 数量的倍数
events {
accept_mutex on; #设置网路连接序列化,防止惊群现象发生,默认为on
multi_accept on; #设置一个进程是否同时接受多个网络连接,默认为off
#use epoll; #事件驱动模型,select|poll|kqueue|epoll|resig|/dev/poll|eventport
worker_connections 1024; #最大连接数,默认为512
}
http {
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream; #默认文件类型,默认为text/plain
#access_log off; #取消服务日志
log_format myFormat '$remote_addr–$remote_user [$time_local] $request $status $body_bytes_sent $http_referer $http_user_agent $http_x_forwarded_for'; #自定义格式
access_log log/access.log myFormat; #combined为日志格式的默认值
sendfile on; #允许sendfile方式传输文件,默认为off,可以在http块,server块,location块。
sendfile_max_chunk 100k; #每个进程每次调用传输数量不能大于设定的值,默认为0,即不设上限。
keepalive_timeout 65; #连接超时时间,默认为75s,可以在http,server,location块。
#一组被代理的服务器地址,然后配置负载均衡的算法,默认是按照轮询方式进行负载
upstream mysvr {
ip_hash; #每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题
#fair; #按后端服务器的响应时间来分配请求,响应时间短的优先分配。与weight分配策略类似。
server 127.0.0.1:7878;
server 192.168.10.121:3333 backup; #热备,如果你有2台服务器,当一台服务器发生事故时,才启用第二台服务器给提供服务。
#参数说明:
#down,表示当前的server暂时不参与负载均衡。
#backup,预留的备份机器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。
#max_fails,允许请求失败的次数,默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
#fail_timeout,在经历了max_fails次失败后,暂停服务的时间。max_fails可以和fail_timeout一起使用。
#weight,加权轮询,跟据配置的权重的大小而分发给不同服务器不同数量的请求,weight和访问比率成正比。如果不设置,则默认为1。
}
error_page 404 https://www.baidu.com; #错误页
proxy_intercept_errors on; #如果被代理服务器返回的状态码为400或者大于400,设置的error_page配置起作用,则需开启这一项为on。默认为off。
server {
keepalive_requests 120; #单连接请求上限次数。
listen 4545; #监听端口
server_name 127.0.0.1; #监听地址
location ~*^.+$ { #请求的url过滤,正则匹配,~为区分大小写,~*为不区分大小写。
#root path; #根目录
#index vv.txt; #设置默认页
proxy_pass http://mysvr; #请求转向mysvr 定义的服务器列表
deny 127.0.0.1; #拒绝的ip
allow 172.18.5.54; #允许的ip
}
}
}
新建一个项目:项目名称都为TestTomcat
新建一个jsp页面:名称为testjsp.jsp
<%@ page language="java" import="java.util.Date" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
欢迎访问
<%
System.out.println(new Date()+"=============tomcat1=================");
%>
tomcat1=======<%=new Date()%>
(1)将测试项目发布到tomcat1服务器上 。
(2)修改项目testjsp.jsp文件
<%@ page language="java" import="java.util.Date" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
欢迎访问
<%
System.out.println(new Date()+"=============tomcat2=================");
%>
tomcat2=======<%=new Date()%>
(3)将修改后的项目发布到tomcat2服务器上
分别在不同的客户端上访问nginx代理服务器。
http://192.168.17.132/TestTomcat/testjsp.jsp
访问结果,以下两种情况轮询切换:
tomcat2=======Wed Jun 29 13:25:03 CST 2011
或者
tomcat1======Wed Jun 29 13:26:03 CST 2011
为什么之前apache搭建集群的时候是直接用tomcat自带的session复制的方式来达成session共享,而这里则通过redis存储session的方式来达成session共享呢?其实,这里也可以直接用tomcat自带的session复制方式,但是这种方式只适用于中小型系统,若稍微大一些的系统仍然用这种方式的话,可能会造成网络风暴的风险(意思就是各个服务器上都在复制session,都在广播session消息,系统很可能会崩溃)。因此,用redis存储session的方式来达成session共享就不会有这种风险了。
(1)下载commons-pool,这里只需下载bin即打包好的jar包就好,commons-pool-1.6-bin.tar.gz中的commons-pool-1.6.jar(由于tomcat-redis-session-manager的版本一直未更新,目前只支持commons-pool1版本的)。
(2)下载tomcat-redis-session-manager,这里下载的版本,tomcat-redis-session-manager-1.2-tomcat-7.jar。
(3)下载jedis-2.1.0.jar,作为java的redis客户端,这里注意由于commons-pool用的是版本1,故此处jedis的版本也不能太高,否则会报错找不到commons-pool2的相应类。
最后将这三个jar均放在这两个tomcat的lib中。
(1)修改tomcat配置文件conf/context.xml
#编辑tomcat的context.xml文件
vim /usr/tomcat/apache-tomcat-7.0.90_1/conf/context.xml
在节点中,添加以下内容:
port="6379"
password=""
database="0"
maxInactiveInterval="60"
/>
说明,maxInactiveInterval="60"的设置并没有用,tomcat的session失效间隔仍然是读conf/web.xml中的session-config节点中配置的session-timeout属性值,且是以分钟为单位,验证也是没用的。。。
[root@172-30-4-6 ~] cd /usr/tomcat/apache-tomcat-7.0.90_1/webapps/TestTomcat #进入到web应用项目中
[root@172-30-4-6 webapps] vim /TestTomcat/testjsp.jsp #修改testjsp.jsp
<%@ page language="java" import="java.util.Date" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
欢迎访问
<%
System.out.println(new Date()+"=============tomcat1=================");
session.setAttribute("tomcat1", "I am tomcat1");
%>
tomcat1=======<%=new Date()%>===<%=session.getId()%>==<%=session.getAttribute("tomcat1")%>==<%=session.getAttribute("tomcat2")%>
[root@172-30-4-6 ~] cd /usr/tomcat/apache-tomcat-7.0.90_2/webapps/TestTomcat #进入到tomcat2的web应用项目中
[root@172-30-4-6 webapps] vim /TestTomcat/testjsp.jsp #修改testjsp.jsp
<%@ page language="java" import="java.util.Date"contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
欢迎访问
<%
System.out.println(new Date()+"=============tomcat2=================");
session.setAttribute("tomcat2", "I am tomcat2");
%>
tomcat2=======<%=new Date()%>===<%=session.getId()%>==<%=session.getAttribute("tomcat1")%>==<%=session.getAttribute("tomcat2")%>
测试结果发现,session成功的共享了
访问http://192.168.17.132/TestTomcat/testjsp.jsp结果显示
tomcat1=======Wed Aug 08 20:12:43 CST 2018===12B141B8BEDD905A893937119506D70B.tomcat1==I am tomcat1==I am tomcat2
再刷新访问http://192.168.17.132/TestTomcat/testjsp.jsp结果显示
tomcat2=======Wed Aug 08 20:12:48 CST 2018===12B141B8BEDD905A893937119506D70B.tomcat2==I am tomcat1==I am tomcat2
至此,在centos7系统上的一个简单nginx+tomcat7+redis的tomcat集群就搭建完成了。
总的来说,用nginx来搭建tomcat集群比用apache来搭建要简单得多了,而且其高并发的性能加上简单的配置,都是我所看好的。然而,这里需要注意的是通过redis实现session共享的时候,那三个jar包的版本对不上的话,分分钟会报错。最后,仍然要提及下防火墙端口的开放,第一,nginx的tcp端口号,默认80;第二,若tomcat和nginx不在同一台机器,则需要开放各个tomcat的tcp端口号,默认8080;第三,若tomcat和redis不在同一台机器,则需要开放该redis的tcp端口,默认6379,同时还需注意redis的相应配置,详看本文2.3尾部。
在程序中将对象放到Redis里时,该对象必须实现java.io.Serializable接口,否则将报错,如果对象中有其它对象的引用,该引用对象也需实现java.io.Serializable接口,所以在使用request.getSession().setAttribute()方法时,一定要注意一下这一个细节。