Debian下搭建Nginx和Tomcat服务器实现负载均衡的方案

负载均衡的基本概念

负载平衡(Load balancing)是一种计算机网络技术,用来在多个计算机(计算机集群)、网络连接、CPU、磁盘驱动器或其他资源中分配负载,以达到最佳化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。

使用带有负载平衡的多个服务器组件,取代单一的组件,可以通过冗余提高可靠性。负载平衡服务通常是由专用软体和硬件来完成。

负载平衡最重要的一个应用是利用多台服务器提供单一服务,这种方案有时也称之为服务器农场。通常,负载平衡主要应用于Web网站,大型的Internet Relay Chat网络,高流量的文件下载网站,NNTP(Network News Transfer Protocol)服务和DNS服务。现在负载平衡器也开始支持数据库服务,称之为数据库负载平衡器。

对于互联网服务,负载平衡器通常是一个软体程序,这个程序侦听一个外部端口,互联网用户可以通过这个端口来访问服务,而作为负载平衡器的软体会将用户的请求转发给后台内网服务器,内网服务器将请求的响应返回给负载平衡器,负载平衡器再将响应发送到用户,这样就向互联网用户隐藏了内网结构,阻止了用户直接访问后台(内网)服务器,使得服务器更加安全,可以阻止对核心网络栈和运行在其它端口服务的攻击。

当所有后台服务器出现故障时,有些负载平衡器会提供一些特殊的功能来处理这种情况。例如转发请求到一个备用的负载平衡器、显示一条关于服务中断的消息等。负载平衡器使得IT团队可以显著提高容错能力。它可以自动提供大量的容量以处理任何应用程序流量的增加或减少。

下面我们就来看一下如何搭建具备负载均衡能力的Nginx+Tomcat服务器组合:

0.前期准备

使用Debian环境。安装Nginx(默认安装),一个web项目,安装tomcat(默认安装)等。

1.一份Nginx.conf配置文件

# 定义Nginx运行的用户 和 用户组 如果对应服务器暴露在外面的话建议使用权限较小的用户 防止被入侵
# user www www;
#Nginx进程数, 建议设置为等于CPU总核心数
worker_processes 8;
#开启全局错误日志类型
error_log /var/log/nginx/error.log info;
#进程文件
pid /var/run/nginx.pid;
#一个Nginx进程打开的最多文件描述数目 建议与ulimit -n一致
#如果面对高并发时 注意修改该值 ulimit -n 还有部分系统参数 而并非这个单独确定
worker_rlimit_nofile 65535;
events{
 #使用epoll模型提高性能
 use epoll;
 #单个进程最大连接数
 worker_connections 65535;
}
http{
 #扩展名与文件类型映射表
 include mime.types;
 #默认类型
 default_type application/octet-stream;
 sendfile on;
 tcp_nopush on;
 tcp_nodelay on;
 keepalive_timeout 65;
 types_hash_max_size 2048;
 #日志
 access_log /var/log/nginx/access.log;
 error_log /var/log/nginx/error.log;
 #gzip 压缩传输
 gzip on;
 gzip_min_length 1k; #最小1K
 gzip_buffers 16 64K;
 gzip_http_version 1.1;
 gzip_comp_level 6;
 gzip_types text/plain application/x-javascript text/css application/xml application/javascript;
 gzip_vary on;
 #负载均衡组
 #静态服务器组
 upstream static.zh-jieli.com {
 server 127.0.0.1:808 weight=1;
 }
 #动态服务器组
 upstream zh-jieli.com {
 server 127.0.0.1:8080;
 #server 192.168.8.203:8080;
 }
 #配置代理参数
 proxy_redirect off;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 client_max_body_size 10m;
 client_body_buffer_size 128k;
 proxy_connect_timeout 65;
 proxy_send_timeout 65;
 proxy_read_timeout 65;
 proxy_buffer_size 4k;
 proxy_buffers 4 32k;
 proxy_busy_buffers_size 64k;
 #缓存配置
 proxy_cache_key '$host:$server_port$request_uri';
 proxy_temp_file_write_size 64k;
 proxy_temp_path /dev/shm/JieLiERP/proxy_temp_path;
 proxy_cache_path /dev/shm/JieLiERP/proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=5d max_size=1g;
 proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;
server{
 listen 80;
 server_name erp.zh-jieli.com;
 location / {
 index index; #默认主页为 /index
 #proxy_pass http://jieli;
 }
 location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
 proxy_cache cache_one;
 proxy_cache_valid 200 304 302 5d;
 proxy_cache_valid any 5d;
 proxy_cache_key '$host:$server_port$request_uri';
 add_header X-Cache '$upstream_cache_status from $host';
 proxy_pass http:
//static.zh-jieli.com;
 #所有静态文件直接读取硬盘
 # root /var/lib/tomcat7/webapps/JieLiERP/WEB-INF ;
 expires 30d; #缓存30天
 }
 #其他页面反向代理到tomcat容器
 location ~ .*$ {
 index index;
 proxy_pass http:
//zh-jieli.com;
 }
 }
 server{
 listen 808;
 server_name static;
 location / {
}
 location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
 #所有静态文件直接读取硬盘
 root /var/lib/tomcat7/webapps/JieLiERP/WEB-INF ;
 expires 30d; #缓存30天
 }
 }
}

基本配置这个文件,就可以实现负载了。但是里面的各种关系要了解就比较麻烦了。

2.基础讲解

现在假使有一台电脑192.168.8.203这台电脑,上面部署了Tomcat,里面8080端口有J2EE的服务,通过浏览器可以正常浏览网页。现在有一个问题tomcat是一个比较全面的web容器,对静态网页的处理,应该是比较费资源的,特别是每次都要从磁盘读取静态页面,然后返回。这中间会消耗Tomcat的资源,可能会使那些动态页面解析性能影响。秉承Linux哲学,一个软件只做一件事的原则。Tomcat就应该只处理JSP动态页面。这里就用到以前了解的Nginx来进行反向代理。第一步代理,实现动静网页分离。这个很简单的。

worker_processes 8;

 pid /var/run/nginx.pid;

 worker_rlimit_nofile 65535;

 events{
 use epoll;
 worker_connections 65535;
 }

 http{
 include mime.types;
 default_type application/octet-stream;
 sendfile on;
 tcp_nopush on;
 tcp_nodelay on;
 keepalive_timeout 65;
 types_hash_max_size 2048;
proxy_redirect off;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 client_max_body_size 10m;
 client_body_buffer_size 128k;
 proxy_connect_timeout 65;
 proxy_send_timeout 65;
 proxy_read_timeout 65;
 proxy_buffer_size 4k;
 proxy_buffers 4 32k;
 proxy_busy_buffers_size 64k;

 server{
 listen 80;
 server_name xxx.com;
 location / {
 index index;
 }
 location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
 proxy_pass http:
//192.168.8.203:8080;
 expires 30d;
 }
 location ~ .*$ {
 index index;
 proxy_pass http:
//192.168.8.203:8080;
 }
 }
 }

worker_processes 8;
pid /var/run/nginx.pid;
worker_rlimit_nofile 65535;
events{
 use epoll;
 worker_connections 65535;
 }
http{
 include mime.types;
 default_type application/octet-stream;
 sendfile on;
 tcp_nopush on;
 tcp_nodelay on;
 keepalive_timeout 65;
 types_hash_max_size 2048;
proxy_redirect off;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 client_max_body_size 10m;
 client_body_buffer_size 128k;
 proxy_connect_timeout 65;
 proxy_send_timeout 65;
 proxy_read_timeout 65;
 proxy_buffer_size 4k;
 proxy_buffers 4 32k;
 proxy_busy_buffers_size 64k;
server{
 listen 80;
 server_name xxx.com;
 location / {
 index index;
 }
 location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
 proxy_pass http:
//192.168.8.203:8080;
 expires 30d;
 }
 location ~ .*$ {
 index index;
 proxy_pass http:
//192.168.8.203:8080;
 }
 }
 }

修改nginx的配置文件 /etc/nginx/nginx.conf 默认有个配置文件的。其实大部分都差不多,关键还是server段的设置。这里我设置server段如上所示,其他段复制就可以了。server段里面的解释如下:第35行为监听本机80端口。37-39行表示默认主页,这里的默认主页我是index.jsp 对应到我项目中是一个index。 这里根据需要可以改为

index index.jsp index.html index.htm index.php

具体可参考其他文章。 关键的第40行,这个是正则匹配,网上也有很多介绍。这里匹配我项目中用到的所有静态网页后缀。第41行是代理地址。这里我代理到我的web应用中。expires 30d缓存为30天,这里的缓存是对应到前端页面,用户的Cache-Control字段,

第44行中那个正则是匹配无后缀的页面。我项目中jsp页面是无后缀的。这里可以根据需要进行修改。同样代理到192.168.8.203:8080这里。到这里你可能会问,我艹,这有毛意思啊?当然不是这样了。简单的实现静动分离,我们可以把第41行进行修改,改为

root  /var/lib/tomcat7/webapps/JieLiERP/WEB-INF

表示不代理,直接从本地磁盘拿。通过查tomcat日志可以看到静态页面是没有访问到的。但这样又有一个问题。这样的灵活性不好,对下面要讲到的内存缓存和集群部署来说都是不友好的,所以又有了下面的这种写法。再写一个server段。

server{
 listen 808;
 server_name static;
 location / {
}
location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
 #所有静态文件直接读取硬盘
 root /var/lib/tomcat7/webapps/JieLiERP/WEB-INF ;
 expires 30d; #缓存30天
 }
 }

这次监听808端口,然后上上面的代码41行就可以修改为 proxy_pass http://192.168.8.203:808了,到这里就实现了动静分离了。如果多台服务器,就修改对应的ip就可以了。如果发现连接不上的,要检查一下防火墙,权限等外部问题,这个配置是这样的。

如果单纯这样的话,我们会发现页面直接传输过于占用带宽。对应web的优化,这里想到的是通过对页面进行gzip压缩,然后传到用户那里,再解压,这样可以有效的减少带宽。这里就会用到Nginx 的gzip模块了。默认的Nginx是集成有gzip模块的。只需在http段增加下面配置即可。

gzip on;
 gzip_min_length 1k; #最小1K
 gzip_buffers 16 64K;
 gzip_http_version 1.1;
 gzip_comp_level 6;
 gzip_types text/plain application/x-javascript text/css application/xml application/javascript;
 gzip_vary on;

给个首页看看效果

不要在意请求数不一样,那两个请求是谷歌插件来的。不用觉得我在骗你。

作为假使有很多人访问的网站来说,缓存肯定是很重要的东西了。一开始是想通过插件,让Nginx和Redis进行合成,然后Nginx使用Redis来缓存的,但是发现配置起来很麻烦,还要自己下载插件,重新编译Nginx,比较麻烦,所以这里觉得用Nginx自带的缓存也是不错的选择。虽然效率比不上redis,但是有还是比没有好。Nginx默认的缓存是磁盘文件系统的缓存,而不是像Redis那样的内存级别的缓存。一开始我以为Nginx就只有这样。后来查了写资料,才知道是我太天真了,对Linux不是很了解导致的。Linux的一切皆文件。原来我们可以把文件缓存到内存对应的Linux文件系统中。我说的可能比较难以理解,请自行搜索/dev/shm 这个文件目录。我们把文件缓存到这个文件目录里,其实就相当与内存的缓存了。只不过还是靠文件系统管理。所以比不上自定义格式的Redis那样的内存缓存。

在http段进行基本配置

#缓存配置
proxy_cache_key '$host:$server_port$request_uri';
proxy_temp_file_write_size 64k;
proxy_temp_path /dev/shm/JieLiERP/proxy_temp_path;
proxy_cache_path /dev/shm/JieLiERP/proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=5d max_size=1g;
proxy_ignore_headers X-Accel-Expires Expires Cache-Control Set-Cookie;

location ~ .*\.(js|css|ico|png|jpg|eot|svg|ttf|woff) {
 proxy_cache cache_one;
 proxy_cache_valid 200 304 302 5d;
 proxy_cache_valid any 5d;
 proxy_cache_key '$host:$server_port$request_uri';
 add_header X-Cache '$upstream_cache_status from $host';
 proxy_pass http:
//192.168.8.203:808;
expires 30d; #缓存30天
 }

经过这两个的配置就基本能实现了,这里说几个注意项,也是困扰我很久的问题。上面第一段代码第6行,proxy_ignore_headers 如果web项目中的html的head头里面指定

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">

这些不缓存的话,就要加上proxy_ignore_headers的配置项了。还有一点就是/dev/shm下面的文件系统权限默认只给root用户,所以要chmod 777 -R /dev/shm 这样不是很安全的做法,如果实际上线可以给定某个用户组,关于用户组的设置是配置的第一行

user www www;

上面第二段代码的第6行是增加一个header字段方便查看是否击中缓存。

我们rm -rf /dev/shm/JieLiERP/proxy_* 下面的所有文件(注意这里如果是进行多次测试的话要nginx -s reload 重新读取配置或重启服务,因为你rm -rf只是删除了缓存文件,但是缓存的结构信息还在nginx进程里面,结构还在,如果不重启的话,是会出现访问不到的)

所以要记得重启哦。下面是运行效果

第一次访问

第二次访问,在浏览器中Ctrl+Shift+R 强制刷新

到这里就可以看到效果了。我们查看一下/dev/shm这个里面

到这里已经快结束了。最后也是比较关键的一个技术点,就是集群,集群,集群。这个就要用到upstream了,看到最开头的配置文件了吗,就是那个

#负载均衡组
#静态服务器组
upstream static {
 server 127.0.0.1:808 weight=1;
 server 192.168.8.203:808 weight=1;
}

#动态服务器组
upstream dynamic {
 server 127.0.0.1:8080;
 #server 192.168.8.203:8080;
}

上面那个就是集群组了。upstream是关键字,static 和 dynamic是两个服务器集群组的名称。以第一个为例,server 127.0.0.1:808 是服务器地址,后面的weight=1 是权重。有多个就写多个。亲测试过,集群中的一个坏了,不影响系统运行。至于更多的轮询规则,可以参考网上更多的资料。这里不多说。至于怎么使用呢? proxy_pass http://192.168.8.203:808 改为 proxy_pass http://static; 这样即可实现均衡。

到这里就结束了。把上面各个部分根据自己需求配置起来就可以实现单机房负载均衡了。 上面这种做法有一个缺点就是在前面的那一台nginx如果当机,后面所以机器就失去了被访问的能力了,所以需要在前面实现多个nginx多机房的负载。关于这个就是另外一个话题了。目前还没有研究。以后有机会再说了。

上面动态服务器组如果是那种需要保存用户状态的话,会有问题,就是session问题,比如我在server1进行登录后,下一次动态服务器组进行轮询后可能分配到server2,就会造成要重新登录。治标的办法是,配置轮询规则,根据用户请求的IP进行Hash,然后分配对应的服务器。具体配置如下:

upstream dynamic{
ip_hash;
server 127.0.0.1:8080;
server 192.168.0.203:8080;
}

这样就可以实现一个用户对应一个服务器节点。这样就不会有重复登录的问题。另一种治本的办法是,利用缓存系统进行session的统一存储管理。

(0)

相关推荐

  • 搭建Tomcat 8源码开发环境的步骤详解

    前言 最近在网上搜索了很多关于tomcat源码环境搭建的文章,发现按照文章的步骤,几乎都启动不了,于是自己尝试搭建,下面是搭建的方法. 基础环境搭建 1.下载tomcat源代码,我这里是通过svn的方式下载的,svn下载地址 2.下载安装maven工具,这里我就不多说了,安装说明太多了,自己网上找. 3.IDE,我这里使用idea 生成maven工程 我的代码本地目录是: /Users/helanzhou/Documents/helanzhou/java/Tomcat/tomcat8/tomca

  • 用apache和tomcat搭建集群(负载均衡)

    一.集群和负载均衡的概念 (一)集群的概念 集群(Cluster)是由两台或多台节点机(服务器)构成的一种松散耦合的计算节点集合,为用户提供网络服务或应用程序(包括数据库.Web服务和文件服务等)的单一客户视图,同时提供接近容错机的故障恢复能力.集群系统一般通过两台或多台节点服务器系统通过相应的硬件及软件互连,每个群集节点都是运行其自己进程的独立服务器.这些进程可以彼此通信,对网络客户机来说就像是形成了一个单一系统,协同起来向用户提供应用程序.系统资源和数据.除了作为单一系统提供服务,集群系统还

  • Docker 搭建 Tomcat 运行环境的方法

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何接口. 1 Docker与虚拟机   2 搭建过程 2.1 准备宿主系统 准备一个 CentOS 7操作系统,具体要求如下: 必须是 64 位操作系统 建议内核在 3.8 以上 通过以下命令查看您的 CentOS 内核: # uname -r 2.2 安装Docker # yum install d

  • Tomcat服务器搭建教程

    分享Tomcat服务器搭建教程,具体如下 第一步:Tomcat 的下载 官方下载网址为:http://tomcat.apache.org/下载界面如下:选则Download下你要安装的版本进行下载. 第二步:安装Tomcat 1:环境设置 下载的是windows安装版,直接点击即可安装,但在安装前必须要进行环境设置–>设置Tomcat运行时依赖的JDK/JRE. JDK设置方法:选择我的电脑->属性->高级系统设置->环境变量->用户变量下选择"新建" 如

  • Docker学习之基于Dockerfile搭建JAVA Tomcat运行环境的方法

    前言 在第一篇文字中,我们完全人工方式,一个命令一个命令输入,实现一个java tomcat运行环境,虽然也初见成效,但很累人.如果依靠依靠脚本构建一个Tomcat容器实例,一个命令可以搞定,何乐而不为呢.好在Docker提供了Dockerfile作为构建Docker镜像脚本,避免人们一行一行的输入,真是善莫大焉.Dockerfile脚本可以做到随时维护修改,即可以分享,更有利于在模板化,更不用说传输了,好处那是一大箩筐! 最终目的:打造一个支持SSH终端登录.Tomcat7自动运行的Docke

  • Docker下搭建一个JAVA Tomcat运行环境的方法

    前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序,并通过配置文件可以轻松实现应用程序的自动化安装.部署和升级,非常方便.因为使用了容器,所以可以很方便的把生产环境和开发环境分开,互不影响,这是 docker 最普遍的一个玩法.更多的玩法还有大规模 web 应用.数据库部署.持续部署.集群.测试环境.面向服务的云计算.虚拟桌面 VDI 等等. 主观的印象:Docker 使用 Go 语言编写,用 cgroup 实现

  • 在Windows下如何安装Tomcat服务器搭建

     相关阅读: 在MyEclipse上部署Tomcat服务器的方法 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选服务器. 在Windows下安装Tomcat服务器的方式有两种,一种是直接安装,一种是绿色版,解压后就可以直接使用的 这篇文章为大家介绍第二种方式 首先从http://download.csdn.net/detail/u010105970/9493219中下载To

  • 详解通过Docker搭建Mysql容器+Tomcat容器连接环境

    1.实验目的:web容器能访问部署在另外容器中的MySQL 2.步骤1:拉取mysql镜像,拉取命令如下: docker pull mysql//官网的最新mysql进行 3.步骤2:拉取tomcat镜像,拉取命令如下: docker pull tomcat --name xuguokun/jdk-tomcat 4.步骤3:创建mysql的一个容器,容器的名字是mymysql,创建命令如下: 复制代码 代码如下: docker run --name mymysql -p 3306:3306  -

  • 详解Docker学习笔记之搭建一个JAVA Tomcat运行环境

    前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序,并通过配置文件可以轻松实现应用程序的自动化安装.部署和升级,非常方便.因为使用了容器,所以可以很方便的把生产环境和开发环境分开,互不影响,这是 docker 最普遍的一个玩法.更多的玩法还有大规模 web 应用.数据库部署.持续部署.集群.测试环境.面向服务的云计算.虚拟桌面 VDI 等等. 主观的印象:Docker 使用 Go 语言编写,用 cgroup 实现

  • Docker-利用dockerfile来搭建tomcat服务的方法

    在前面的例子中,我们从下载镜像,启动容器,在容器中输入命令来运行程序,这些命令都是手工一条条往里输入的,无法重复利用,而且效率很低.所以就需要一 种文件或脚本,我们把想执行的操作以命令的方式写入其中,然后让docker读取并分析.执行,那么重复构建.更新将变得很方便,所以Dockerfile就此诞生了. 常用参数: FROM命令.用法,FROM <image>:<tag>.FROM命令告诉docker我们构建的镜像是以哪个(发行版)镜像为基础的 RUN命令.用法RUN <co

随机推荐