当前位置: 首页 > news >正文

通向架构师的道路之tomcat集群

一、为何要集群

 

单台App Server再强劲,也有其瓶劲,先来看一下下面这个真实的场景。

https://img-my.csdn.net/uploads/201212/12/1355288240_3071.jpg

当时这个工程是这样的,tomcat这一段被称为web zone,里面用spring+ws,还装了一个jboss的规则引擎Guvnor5.x,全部是ws没有service layer也没有dao layer。

然后App Zone这边是weblogic,传输用的是spring rmi,然后App Zone这块全部是service layer, dao layer和数据库打交道。

用户这边用的是.net,以ws和web zone连的。

时间一长,数据一多,就出问题了。

拿Loader Runner跑下来,发觉是Web Zone这块,App Server已经被用到极限了。因为客户钱不多,所以当时的Web Zone是2台服务器,且都是32位的,内存不少,有8GB,测试下来后发觉cpu loader又不高,但是web server这边的吞吐量始终上不去,且和.net客户端那边响应越来越慢。

分析了一下原因:单台tomcat能够承受的最大负载已经到头了,单台tomcat的吞吐量就这么点,还要负担Guvnor的运行,Guvnor内有数百条业务规则要执行。

再看了一下其它方面的代码、SQL调优都已经到了极限了,所以最后没办法,客户又不肯拿钱投在内存和新机器上或者是再买台Weblogic,只能取舍一下,搞Tomcat集群了。

二、集群分类

https://img-my.csdn.net/uploads/201212/12/1355288252_2473.jpg

Tomcat作集群的逻辑架构是上面这样的一张图,关键是我们的production环境还需要规划好我们的物理架构。

2.1 横向集群

比如说,有两台Tomcat,分别运行在2台物理机上,好处是最大的即CPU扩展,内存也扩展了,处理能力也扩展了。

https://img-my.csdn.net/uploads/201212/12/1355288263_3419.jpg

2.2 纵向集群

即,两个Tomcat的实例运行在一台物理器上,充分利用原有内存,CPU未得到扩展。

https://img-my.csdn.net/uploads/201212/12/1355288271_7504.jpg

2.3 横向还是纵向

一般来说,广为人们接受的是横向扩展的集群,可做大规模集群布署。但是我们这个case受制于客户即:

ü   不会再投入新机器了

ü   不会增加内存了

但是呢,通过压力测试报告我们可知:

ü   原有TomcatServer的CPU Loader不高,在23%左右

ü   原有TomcatServer上有8GB内存,而且是32位的,单台Tomcat只使用了1800MB左右的内存

ü   网络流量不高,单块千兆以太网卡完全可以处理掉

因此,我们只能做熊掌与鱼不能兼得的事,即采用了:纵向集群。

2.4 Load Balance与High Available

ü   Load Balance

简称LB即负载均衡,相当于1000根线程每个集群节点:Node负责处理500个,这样的效率是最高的。

ü   High Available

简称HA即高可用性,相当于1000根线程还是交给一台机器去慢慢处理,如果这台机器崩了,另一台机器顶上。

三、集群架构中需要解决的问题

集群规划好了怎么分,这不等于就可以开始实现集群了,一旦你的系统实现了集群,随之而来的问题就会出现了。

我们原有系统中有这样几个问题,在集群环境中是需要解决的,来看:

3.1 解决上传文件同步的问题

集群后就是两个Tomcat了,即和两个线程读同一个resource的问题是一样的,还好,我们原有上传文件是专门有一台文件伺服器的,这个问题不大,两个tomcat都往一台file server里上传,文件伺服器已经帮我们解决了同名文件冲突的这个问题了,如果原先的做法是把文件上传到Tomcat的目录中,那问题就大了,来看:

集群环境中,对于用户来说一切操作都是透明的,他也不知道我有几个Tomcat的实例运行在那边。

用户一点上传,可能上传到了Tomcat2中,但是下次要显示这个文件时,可能用到的是Tomcat1内的jsp或者是class,对不对?

于是,因为你把图片存在了Tomcat的目录中,因此导致了Tomcat1在显示图片时,取不到Tomcat2目录中存放的图片。

因此我们在工程一开始就强调存图片时要用一台专门的文件服务器或者是FTP服务器来存,就是为了避免将来出现这样的问题。

3.2 解决Quartz在集群环境中的同步问题

我们的系统用到一个Quartz(一个定时服务组件)来定时触发一些自动机制,现在有了两个Tomcat,粗想想每个Tomcat里运行自己的Quartz不就行了?

但是问题来了,如果两个Quartz在同一时间都触发了处理同一条定单,即该条定单会被处理两边。。。这不是影响效率和增加出错机率了吗?

因为本身Quartz所承受的压力几乎可以忽略不计的,它只是定时会触发脚本去运行,关键在于这个定时脚本的同步性,一致性的问题上。

我们曾想过的解决方法:

我们可以让一个Tomcat布署Quartz,另一个Tomcat里不布署Quartz

但这样做的结果就是如果布署Quartz的这个Tomcat崩溃掉了,这个Quartz是不是也崩啦?

最后解决的办法:

所 以我们还是必须在两台Tomcat里布署Quartz,然后使用HA的原则,即一个Quartz在运行时,另一台Quartz在监视着,并且不断的和另一 个Quartz之间保持勾通,一旦运行着的Quartz崩掉了,另一个Quartz在指定的秒数内起来接替原有的Quartz继续运行,对于 Quartz,我们同样也是面临着一个熊掌与鱼不能皆得的问题了,Quartz本身是支持集群的,而它支持的集群方式正是HA,和我们想的是一致的。

具体Quartz是如何在集群环境下作布署的,请见我的另一篇文章:quartz在集群环境下的最终解决方案

解决了上述的问题后基本我们可以开始布署Tomcat这个集群了。

四、布署Tomcat集群

准备两个版本一致的Tomcat,分别起名为tomcat1,tomcat2。

4.1 Apache中的配置

²  worker.properties文件内容的修改

打开Apache HttpServer中的apache安装目录/conf/work.properties文件,大家还记得这个文件吗?

这是原有文件内容:

workers.tomcat_home=d:/tomcat2

workers.java_home=C:/jdk1.6.32

ps=/

worker.list=ajp13

worker.ajp13.port=8009

worker.ajp13.host=localhost

worker.ajp13.type=ajp13

现在开始改动成下面这样的内容(把原有的worker.properties中的内容前面都加上#注释掉):

#workers.tomcat_home=d:/tomcat2

#workers.java_home=C:/jdk1.6.32

#ps=/

#worker.list=ajp13

#worker.ajp13.port=8009

#worker.ajp13.host=localhost

#worker.ajp13.type=ajp13

worker.list = controller

#tomcat1

worker.tomcat1.port=8009       

worker.tomcat1.host=localhost

worker.tomcat1.type=ajp13

worker.tomcat1.lbfactor=1

#tomcat2

worker.tomcat2.port=9009     

worker.tomcat2.host=localhost

worker.tomcat2.type=ajp13

worker.tomcat2.lbfactor=1

#========controller========

worker.controller.type=lb

worker.controller.balance_workers=tomcat1,tomcat2

worker.lbcontroller.sticky_session=0

worker.controller.sticky_session_force=true

worker.connection_pool_size=3000

worker.connection_pool_minsize=50

worker.connection_pool_timeout=50000

上面的这些设置的意思用中文来表达就是:

ü   两个tomcat,都位于localhost

ü   两个tomcat,tomcat1用8009,tomcat2用9009与apache保持jk_mod的通讯

ü   不采用sticky_session的机制

sticky_session即:假设现在用户正连着tomcat1,而tomcat1崩了,那么此时它的session应该被复制到tomcat2上,由tomcat2继续负责该用户的操作,这就是load balance,此时这个用户因该可以继续操作。

如果你的sticky_session设成了1,那么当你连的这台tomcat崩了后,你的操作因为是sticky(粘)住被指定的集群节点的,因此你的session是不会被复制和同步到另一个还存活着的tomcat节点上的。

ü   两台tomcat被分派到的任务的权重(lbfactor)为一致

你也可以设tomcat1 的worker.tomcat2.lbfactor=10,而tomcat2的worker.tomcat2.lbfactor=2,这个值越高,该tomcat节点被分派到的任务数就越多

²  httpd.conf文件内容的修改

找到下面这一行:

Include conf/extra/httpd-ssl.conf

我们将它注释掉,因为我们在集群环境中不打算采用https,如果采用是https也一样,只是为了减省开销(很多人都是用自己的开发电脑在做实验哦)。

#Include conf/extra/httpd-ssl.conf

找到原来的“”段

改成如下形式:

DocumentRoot d:/www

    AllowOverride None

    Order allow,deny

          Allow from all

         Order deny,allow

         Deny from all

ServerAdmin localhost

DocumentRoot d:/www/

ServerName shnlap93:80

DirectoryIndex index.html index.htm index.jsp index.action

ErrorLog logs/shsc-error_log.txt

CustomLog logs/shsc-access_log.txt common

JkMount /*WEB-INF controller

JkMount /*j_spring_security_check controller

JkMount /*.action controller

JkMount /servlet/* controller

JkMount /*.jsp controller

JkMount /*.do controller

JkMount /*.action controller

JkMount /*fckeditor/editor/filemanager/connectors/*.* controller

JkMount /fckeditor/editor/filemanager/connectors/* controller

注意:

原来的JKMount *** 后的 ajp13变成了什么了?

controller

4.2 tomcat中的配置

可以拿原有的tomcat复制成另一个tomcat,分别为d:\tomcat, d:\tomcat2。

打开tomcat中的conf目录中的server.xml,找到下面这行

1

记得:

一定要把tomcat2中的这边的”SHUTDOWN”的port改成另一个端口号,两个tomcat如果是在集群环境中,此处的端口号绝不能一样。

2)找到

确保tomcat2中此处的端口不能为8080,我们就使用9090这个端口吧

3)把两个tomcat中原有的https的配置,整段去除

4)找到

               URIEncoding="UTF-8"  minSpareThreads="25" maxSpareThreads="75"

               enableLookups="false" disableUploadTimeout="true" connectionTimeout="20000"

                   acceptCount="300"  maxThreads="300" maxProcessors="1000" minProcessors="5"

                   useURIValidationHack="false"

                             compression="on" compressionMinSize="2048"

                             compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"

               redirectPort="8443" />

确保tomcat2中这边的redirectPort为9443

5)找到

改为:

                    URIEncoding="UTF-8"  minSpareThreads="25" maxSpareThreads="75"

                            enableLookups="false" disableUploadTimeout="true" connectionTimeout="20000"

                            acceptCount="300"  maxThreads="300" maxProcessors="1000" minProcessors="5"

                            useURIValidationHack="false"

                                      compression="on" compressionMinSize="2048"

compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"

   

/>

确保tomcat2的server.xml中此处的8009被改成了9009且其它内容与上述内容一致(redirectPort不要忘了改成9443

6)找到

      

改成

tomcat1">

同时把tomcat2中此处内容改成

  

tomcat2">

7

在刚才的

tomcat1">

的下面与在

     

之上,在这之间加入如下一大陀的东西:

               

                  channelSendOptions="6"> 

             

                    expireSessionsOnShutdown="false" 

                    notifyListenersOnReplication="true" 

                    mapSendOptions="6"/> 

            

            

                         bind="127.0.0.1" 

                         address="228.0.0.4" 

                         port="45564" 

                         frequency="500" 

                         dropTime="3000"/> 

            

                       address="auto" 

                       port="4001" 

                       selectorTimeout="100" 

                       maxThreads="6"/> 

              

                

              

              

              

              

            

             

                  filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/> 

               

        

此处有一个Receiver port=”xxxx”,两个tomcat中此处的端口号必须唯一,即tomcat中我们使用的是port=4001,那么我们在tomcat2中将使用port=4002

8)把系统环境变更中的CATALINA_HOME与TOMCAT_HOME这两个变量去除掉

9)在每个tomcat的webapps目录下布署同样的一个工程,在布署工程前先确保你把工程中的WEB-INF\we b.xml文件做了如下的修改,在web.xml文件的最未尾即“”这一行前加入如下的一行:

使该工程中的session可以被tomcat的集群节点进行轮循复制。


 

4.3 启动集群

好了,现在启动tomcat1, 启动tomcat2(其实无所谓顺序的),来看效果:

分别访问http://localhost:8080/cbbs与http://localhost:9090/cbbs

确保两个tomcat节点都起来了,然后此时,我们启动Apache

然后访问直接用http://localhost/cbbs不加端口的形式访问:

用sally/abcdefg登录,瞧,应用起来了。

然后我们拿另一台物理客户端,登录这个web应用,我们可以看到:

第一个tomcat正在负责处理我们第一次登录的请求。

当有第二个HTTP请求时,另一个tomcat自动开始肩负起我们第二个HTTP请求了,这就是Load Balance。

相关文章:

通向架构师的道路之tomcat集群

一、为何要集群 单台App Server再强劲,也有其瓶劲,先来看一下下面这个真实的场景。 当时这个工程是这样的,tomcat这一段被称为web zone,里面用springws,还装了一个jboss的规则引擎Guvnor5.x,全部是ws没有se…...

结构体,枚举,联合大小的计算规则

目录 1.结构体大小的计算 补充(位段) 2.枚举的大小(4个字节) 3.联合大小的计算 1.结构体大小的计算 (1)结构体内存对齐的规则 1. 第一个成员在与结构体变量偏移量为 0 的地址处。 2. 其他成员变量要对…...

Vue2 第十七节 Vue中的Ajax

1.Vue脚手架配置代理 2.vue-resource 一.Vue脚手架配置代理 1.1 使用Ajax库 -- axios ① 安装 : npm i axios ② 引入: import axios from axios ③ 使用示例 1.2 解决开发环境Ajax跨域问题 跨域:违背了同源策略,同源策略规定协议名&#xff0…...

ES6 - 字符串新增的一些常用方法

文章目录 0,新增的一些方法1,includes()、startsWith()、endsWith()2,repeat()3,padStart()、padEnd()4,trimStart()、trimEnd()5,replaceAll()6,at() 0,新增的一些方法 介绍一些ES6…...

最新SQLMap安装与入门技术

点击星标,即时接收最新推文 本文选自《web安全攻防渗透测试实战指南(第2版)》 五折购买链接:u.jd.com/3ibjeF6 SQLMap详解 SQLMap是一个自动化的SQL注入工具,其主要功能是扫描、发现并利用给定URL的SQL注入漏洞。SQLMa…...

Java 使用 Google Guava 实现接口限流

一、引入依赖 <dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>30.0-jre</version> </dependency>二、自定义注解及限流拦截器 自定义注解&#xff1a;Limiter package com.haita…...

帮助中心的价值是什么?怎样才能在线搭建官网网站帮助中心?

帮助中心&#xff08;Help Center&#xff09;是一个提供公司或组织产品或服务相关信息的在线平台。它的价值在于为用户提供便捷的自助服务和解决问题的渠道&#xff0c;同时也能减轻客服人员的负担。 如何在线搭建官网网站帮助中心的步骤 确定需求&#xff1a;在搭建帮助中心…...

Kubernetes——理论基础

Kubernetes——理论基础 一、Kubernetes 概述1.K8S 是什么&#xff1f;2.为什么要用 K8S?3.Kubernetes 主要功能 二、Kubernetes 集群架构与组件三、Master 组件1.Kube-apiserver2.Kube-controller-manager3.Kube-scheduler4.配置存储中心——etcd 四、Node 组件1.Kubelet2.Ku…...

【VUE3】

Vue 3 是当下最流行的前端框架之一&#xff0c;其主要特点是性能更好、体积更小、更易于维护。下面是 Vue 3 的一些重要知识点和代码示例&#xff1a; 创建 Vue 实例 import { createApp } from vueconst app createApp({data() {return {message: Hello, Vue 3!}} })app.mo…...

《金融数据保护治理白皮书》发布(137页)

温馨提示&#xff1a;文末附完整PDF下载链接 导读 目前业界已出台数据保护方面的治理模型&#xff0c;但围绕金融数据保护治理的实践指导等尚不成熟&#xff0c;本课题围绕数据保护治理的金融实践、发展现状&#xff0c;探索和标准化相关能力要求&#xff0c;归纳总结相关建…...

上海亚商投顾:沪指震荡微涨 金融、地产午后大幅走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数早盘震荡&#xff0c;午后集体拉升反弹&#xff0c;创业板指涨超1%。券商等大金融板块午后再度走强&#…...

Linux文件管理知识:查找文件

前几篇文章一一介绍了LINUX进程管理控制命令及网络层面的知识体系&#xff0c;综所周知&#xff0c;一个linux系统是由很多文件组成的&#xff0c;那么既然有那么多文件&#xff0c;那我们该如何管理这些文件呢&#xff1f; Linux中的所有数据都是以文件形式存在的&#xff0c…...

【TypeScript】安装的坑!

TypeScript安装 安装TypeScript安装时候可能报错这样开头的数据&#xff08;无法枚举容器中的对象&#xff09;——原因&#xff1a;没权限先解决没权限的问题如果发现无法修改-高级-修改继续安装想使用tsc-发现&#xff0c;tsc不能用解决方法&#xff1a;配置环境变量最后的最…...

spring boot 2.x 使用 jpa 映射 json mysql列数据映射乱码

通过下面的依赖&#xff0c;可以将 mysql 的 json 列字段&#xff08;mysql 5.7及以上的版本支持&#xff09;&#xff0c;映射成 Java Bean <dependency><groupId>com.vladmihalcea</groupId><artifactId>hibernate-types-52</artifactId><v…...

创建Helm脚本

一、创建脚本 Helm 是 Kubernetes 的包管理工具&#xff0c;它可以帮助您简化和自动化 Kubernetes 应用程序的部署和管理。使用 Helm&#xff0c;您可以创建和管理称为 Helm Chart 的应用程序打包&#xff0c;这些 Chart 包含了 Kubernetes 资源和配置信息&#xff0c;可以在不…...

2.05 购物车后台刷新并显示

一.用户登录添加商品使用cookie存入购物车&#xff0c;并把购物车商品传入到后台 步骤1&#xff1a;创建购物车BO对象 public class ShopcartBO {private String itemId;private String itemImgUrl;private String itemName;private String specId;private String specName;p…...

2023年第四届“华数杯”数学建模思路 - 案例:异常检测

文章目录 赛题思路一、简介 -- 关于异常检测异常检测监督学习 二、异常检测算法2. 箱线图分析3. 基于距离/密度4. 基于划分思想 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 一、简介 – 关于异常检测 异常…...

inline的盒子设置transform不生效

目录 如何遇到的问题原因为什么会这样怎么解决 如何遇到的问题 最近在开发过程中&#xff0c;因为需要对一个icon进行旋转&#xff0c;而icon本身&#xff0c;是设置span的伪类来进行的&#xff0c;结果我发现无论怎么设置transform都无法使其生效。 span::before {font-famil…...

自然语言处理学习笔记(四)————词典分词

目录 1.中文分词 2.词典分词 &#xff08;1&#xff09;词的定义 &#xff08;2&#xff09;词典性质——齐夫定律 &#xff08;3&#xff09;词典 &#xff08;4&#xff09;加载词典 &#xff08;5&#xff09;hanlp词典路径 1.中文分词 中文分词&#xff1a;指的是将一…...

jsoncpp库和nlohmann-json库实现JSON与字符串类型转换

在ROS中&#xff0c;可以使用jsoncpp库来实现JSON与字符串类型之间的转换。jsoncpp是ROS自带的一个JSON库&#xff0c;它提供了一些函数来解析和生成JSON数据。 下面是一个使用jsoncpp库实现JSON与字符串类型转换的示例代码&#xff1a; #include <ros/ros.h> #include…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...