关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » HTML5 »Nginx + Tomcat 动静分离实现负载均衡

    Nginx + Tomcat 动静分离实现负载均衡

    2015-12-01 00:00:00 出处:InfoQ
    分享

    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段进行基本配置

    1 #缓存配置
     2 proxy_cache_key '$host:$server_port$request_uri';
     3 proxy_temp_file_write_size 64k;
     4 proxy_temp_path /dev/shm/JieLiERP/proxy_temp_path;
     5 proxy_cache_path /dev/shm/JieLiERP/proxy_cache_path levels=1:2 keys_zone=cache_one:200m inactive=5d max_size=1g;
     6 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头里面指定

    1 <meta http-equiv="pragma" content="no-cache">
     2 <meta http-equiv="cache-control" content="no-cache">
     3 <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的统一存储管理。具体的做法我还没有试验过,参考资料有相关的文章,可以了解一下。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    Cornell大神Kleinberg的经典教材《算法设计》是最好入门的算法教材

    从 Microsoft 下载中心安装 Windows 7 SP1 和 Windows Server 2008 R2 SP1 之前要执行的步骤

    Llama 2基于UCloud UK8S的创新应用

    火山引擎DataTester:如何使用A/B测试优化全域营销效果

    腾讯云、移动云继阿里云降价后宣布大幅度降价

    字节跳动数据平台论文被ICDE2023国际顶会收录,将通过火山引擎开放相关成果

    这个话题被围观超10000次,火山引擎VeDI如此解答

    误删库怎么办?火山引擎DataLeap“3招”守护数据安全

    IT头条

    平替CUDA!摩尔线程发布MUSA 4性能分析工具

    00:43

    三起案件揭开侵犯个人信息犯罪的黑灰产业链

    13:59

    百度三年开放2.1万实习岗,全力培育AI领域未来领袖

    00:36

    工信部:一季度,电信业务总量同比增长7.7%,业务收入累计完成4469亿元

    23:42

    Gartner:2024年全球半导体营收6559亿美元,AI助力英伟达首登榜首

    18:04

    技术热点

    iOS 8 中如何集成 Touch ID 功能

    windows7系统中鼠标滑轮键(中键)的快捷应用

    MySQL数据库的23个特别注意的安全事项

    Kruskal 最小生成树算法

    Ubuntu 14.10上安装新的字体图文教程

    Ubuntu14更新后无法进入系统卡在光标界面解怎么办?

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。