.征服 Apache + Tomcat 博客分类: Server Architecture/Basic
ApacheTomcat应用服务器配置管理Ubuntu .
Apache 和 Tomcat原本就是一家,更是一家亲!Apache与Tomcat整合,无非是将Apache作为前端根据请求路径、端口、代理分发给多个Tomcat,以到达转发和负载均衡的目的!同时,通过Apache和Tomcat相互作用,进行粘性会话,会话拷贝构建集群!这一切的最终结果就是“云服务”!不要说Session不重要,当下火爆的团购,如果离开Session还能快活多久?如何保证Session同步,仍然是不能回避的问题!
这里要说的是基于HTTP和AJP跳转方式的负载均衡实现,关于JK,由于效率问题一直成为诟病,并且mod_jk2模块已经不再被更新了,这里就不折腾它的复杂配置了!
至于说Apache+Tomcat+SSL,并不是难题!只要完成了Apache+SSL然后配置相应的负载均衡、反向代理等等就可以达到目的,相关Apache+SSL参考征服 Apache + SSL
Ubuntu Server 10.04版本,Apache选用2.2.14,Tomcat选用6.0.24。
相关内容:
征服 Apache + SSL
征服 Apache + SVN
征服 Apache + SVN + LDAP
征服 Apache + Tomcat
征服 Nginx
征服 Nginx + Tomcat
步骤:
1.安装Apache基本模块
2.后台监控
3.负载均衡简单测试
4.配置Tomcat相关模块(AJP)
5.保持Session唯一,粘性会话
6.Tomcat集群,Session复制
1.安装Apache相关模块
负载均衡需要的主要是代理模块!
经过几次Apache配置尝试,在Ubuntu下配置Apache实在是太容易了。加载什么模块、取消什么模块两个命令搞定。
Shell代码
1.#启用模块
2.sudo a2enmod <model>
3.#禁用模块
4.sudo a2dismod <model>
#启用模块
sudo a2enmod <model>
#禁用模块
sudo a2dismod <model>
这里,我们需要让Apache提供代理服务,其中又包含基于http、ftp、ajp等等协议的代理功能,同时还需要负载均衡模块。我们可以通过命令逐个加载:
Shell代码
1.#代理核心模块
2.sudo a2enmod proxy
3.#代理AJP模块
4.sudo a2enmod proxy_ajp
5.#代理负载均衡模块
6.sudo a2enmod proxy_balancer
7.#代理HTTP模块
8.sudo a2enmod proxy_http
9.#代理FTP模块
10.sudo a2enmod proxy_ftp
#代理核心模块
sudo a2enmod proxy
#代理AJP模块
sudo a2enmod proxy_ajp
#代理负载均衡模块
sudo a2enmod proxy_balancer
#代理HTTP模块
sudo a2enmod proxy_http
#代理FTP模块
sudo a2enmod proxy_ftp
完成上述操作后,系统会提示重启Apache!
先不着急重启,现学现卖,了解下Apache的目录结构。在Ubuntu下配置Apache主要是在/etc/apache2目录下:
分述:
•apache2.conf核心配置文件,一般不需要修改!
•conf.d目录,里面包含了一些字符集设置,文档等设置!
•dav_svn.authz和dav_svn.passwd是前面做SVN时,相关权限、密码文件。
•envvars定义了运行时的用户身份——www-data。
•httpd.conf是Apache留给我们自己折腾的配置文件,默认为空。apache2.conf会加载这个文件。
•ports.conf端口默认配置。apache2.conf会加载这个文件。
•magic为mod_mime_magic模块服务。
•mods-enabled和mods-available mods-enabled会被apache2.conf加载,里面包含*.load和*.conf文件。*.load文件中是加载相应的模块(位于/usr/lib/apache2/modules/中),而*.conf中是对应的基本配置。但这些文件其实都是链接到mods-available中相应的文件上。当我们通过a2enmod操作时,实际上正是操作了这些软链接。
•sites-available和sites-enabled 与 mods-enabled和mods-available的关系类似,只是其中包含的是站点内容。
罗嗦了一堆,下面配置负载均衡部分。
执行修改:
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
上图红框中的内容是原始内容,白框中的内容是我新加的部分。
注意红框中的配置:
Conf代码
1.<Proxy *>
2. AddDefaultCharset off
3. Order deny,allow
4. #Deny from all
5. Allow from localhost ip6-localhost
6.</Proxy>
<Proxy *>
AddDefaultCharset off
Order deny,allow
#Deny from all
Allow from localhost ip6-localhost
</Proxy>
在默认配置中,Deny from all处于可用状态。当我们配置其他代理节点时,将导致杜绝访问!使用Allow from localhost ip6-localhost 限制仅允许本机访问!
再说,白框中的内容:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember http://localhost:8080/
3. BalancerMember http://192.168.49.1:8080/
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember http://localhost:8080/
BalancerMember http://192.168.49.1:8080/
</Proxy>
这里,我配置了一个负载均衡节点balancer://zlex,其中包含了两个服务http://localhost:8080/和http://192.168.49.1:8080/,一个是虚拟机上的Tomcat、一个是真机上的Tomcat。这里使用的Http的转发方式,当然,使用AJP未尝不可,稍后详述!
这里的节点次序会有一个先后关系,Apache会将请求按照FIFO的方式调度顺次分配到各个节点上!如果其中有一个节点挂掉,将跳过该节点顺次寻找可用节点。
再说代理和反向代理:
Conf代码
1.ProxyPass /zlex balancer://zlex
2.ProxyPassReverse /zlex balancer://zlex
ProxyPass /zlex balancer://zlex
ProxyPassReverse /zlex balancer://zlex
这里配置,如果要访问/zlex路径时,将跳转到balancer://zlex上,也就是享受负载均衡!
2.后台监控
我们如何知道某个节点负载多少,响应时间多久,服务是否正常呢?Apache提供了负载均衡监控平台:http://localhost/balancer-manager。但是,这个服务默认是不存在。
除了用于负载均衡配置、监控的balancer-manager还有http://localhost/server-status和http://localhost/server-info
我们需要添加info模块:
Shell代码
1.#系统信息模块
2.sudo a2enmod info
#系统信息模块
sudo a2enmod info
同时,为了能够使用balancer-manager,我们需要配置:
Conf代码
1.<Location /balancer-manager>
2. SetHandler balancer-manager
3. Order Deny,Allow
4. #Deny from all
5. Allow from localhost ip6-localhost
6.</Location>
<Location /balancer-manager>
SetHandler balancer-manager
Order Deny,Allow
#Deny from all
Allow from localhost ip6-localhost
</Location>
把这段代码放到哪?由于它同属系统信息配置,我把它放到了info.conf中,说白了就是照猫画虎:
Shell代码
1.sudo vi /etc/apache2/mods-available/info.conf
sudo vi /etc/apache2/mods-available/info.conf
注意,这段代码放到了<IfModule mod_info.c>和</IfModule>之间!
现在,我们重启Apache:
Shell代码
1.sudo /etc/init.d/apache2 restart
sudo /etc/init.d/apache2 restart
来看看管理界面http://localhost/balancer-manager:
我们再来看看服务器基本信息http://localhost/server-info:
上述两个服务需要加载info模块,而服务器状态(server-status)不需要http://localhost/server-status:
3.负载均衡简单测试
疯狂访问http://localhost/zlex,直到手酸眼烦!
我这里故意使用不同了Tomcat界面,来验证自己的配置是否生效。更疯狂的是,我甚至把节点指向了百度、搜狐,来测试负载均衡的效果。如果你细致观察,Apache是将请求顺次分配到各个节点上的。
如果其中一个节点发生问题(例如,强行关闭一个Tomcat,或配置一个错误节点)Apache将会经过几次尝试后,绕过这个问题节点,寻找可以成功访问的节点。如果这个节点恢复正常使用,Apache将在该Tomcat恢复正常工作后大约1分钟内将该节点标识为可用!
现在,再看看现在的后台(http://localhost/balancer-manager)啥样子:
如果我们控制一个节点的状态是否可用,该怎么做:
涉及到负载量,session同步等等,我们最后讨论!
4.配置Tomcat相关模块(AJP)
基于Http协议分发并不复杂,但AJP效果更好!一次诡异事件中,内网访问正常,外网访问多次失败,最后通过AJP方式完美解决了!
在Tomcat中配置AJP也很简单,修改server.xml开启AJP模块:
Shell代码
1.sudo vi /etc/tomcat6/server.xml
sudo vi /etc/tomcat6/server.xml
开启AJP配置:
Xml代码
1.<Connector port="8009" protocol="AJP/1.3"
2. URIEncoding="UTF-8"
3. redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3"
URIEncoding="UTF-8"
redirectPort="8443" />
注意使用的端口port="8009",字符集URIEncoding="UTF-8",这是输入框、请求字符集乱码的入口!
接下里就可以通过AJP方式进行节点分发了。修改/etc/apache2/mods-available/proxy.conf :
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
将http改为ajp,将8080改为8009:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://localhost:8009/
3. BalancerMember ajp://192.168.49.1:8009/
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember ajp://localhost:8009/
BalancerMember ajp://192.168.49.1:8009/
</Proxy>
重启Apache:
Shell代码
1.sudo /etc/init.d/apache2 restart
sudo /etc/init.d/apache2 restart
再看看管理界面http://localhost/balancer-manager
至此,我们完成了基本负载均衡的基本配置!
/etc/apache2/mods-available/proxy.conf还有一些属性:
noFailOver是否打开失败转移,On|Off,默认为Off,添加在ProxyPass后面,如:
Conf代码
1.ProxyPass /zlex balancer://zlex stickySession=JSESSIONID noFailOver=On
ProxyPass /zlex balancer://zlex stickySession=JSESSIONID noFailOver=On
如果这样配置,当提供给你服务的服务器发生异常,那么你将一直看着它返回给你503,直到系统恢复正常!
loadfactor表示后台服务器负载到由Apache发送请求的权值,默认值为1添加在BalancerMember后面:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://localhost:8009/
3. BalancerMember ajp://192.168.49.1:8009/
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember ajp://localhost:8009/
BalancerMember ajp://192.168.49.1:8009/
</Proxy>
可以实现三种策略:
1.轮询均衡策略的配置
2.按权重分配均衡策略的配置
3.权重请求响应负载均衡策略的配置
5.Session唯一,粘性会话
Apache已经可以轻松将内容处理的工作分配给各个Tomcat了!
当然,这还不够,Session还是个问题!
WHY?
我们来做一系列修改,来检测Session到底出现了什么问题!
先来改造Tomcat,修改server.xml:
Shell代码
1.sudo vi /etc/tomcat6/server.xml
sudo vi /etc/tomcat6/server.xml
修改<Engine />节点,增加jvmRoute属性:
Xml代码
1.<Engine
2. name="Catalina"
3. defaultHost="localhost"
4. jvmRoute="tomcat1">
<Engine
name="Catalina"
defaultHost="localhost"
jvmRoute="tomcat1">
另一个Tomcat设置改为
Xml代码
1.<Engine
2. name="Catalina"
3. defaultHost="localhost"
4. jvmRoute="tomcat2">
<Engine
name="Catalina"
defaultHost="localhost"
jvmRoute="tomcat2">
通过jvmRoute,指定了Tomcat唯一标识!
然后修改/etc/apache2/mods-available/proxy.conf
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
如下:
Java代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://localhost:8009/zlex route=tomcat1
3. BalancerMember ajp://192.168.49.1:8009/zlex route=tomcat2
4.</Proxy>
5.
6.ProxyPass /zlex balancer://zlex
7.ProxyPassReverse /zlex balancer://zlex
<Proxy balancer://zlex>
BalancerMember ajp://localhost:8009/zlex route=tomcat1
BalancerMember ajp://192.168.49.1:8009/zlex route=tomcat2
</Proxy>
ProxyPass /zlex balancer://zlex
ProxyPassReverse /zlex balancer://zlex
这里需要通过修改route属性,将Apache与Tomcat关联起来!
注意,Tomcat中定义的jvmRoute需要与Apache定义的route相对应!
我们来看一下http://localhost/balancer-manager发生了什么变化:
我们注意到route字段有了新的标识,当然,我们也可以通过这个配置界面修改这些信息,但当前修改不会真的修改/etc/apache2/mods-available/proxy.conf文件,Apache重启后将丢失。
为了更细致的对比进过复杂均衡的结果,这里增加了zlex应用!主要是监控Session的变化!
只看核心代码:
Jsp代码
1.<b>当前SessionID:</b>
2.<br />
3.<%
4. String sessionID = session.getId();
5. out.println(sessionID);
6. System.err.println("sessionID = " + sessionID);
7.
8. // 如果有新的 Session 属性设置
9. String dataName = request.getParameter("dataName");
10. if (dataName != null && !dataName.isEmpty()) {
11. String dataValue = request.getParameter("dataValue");
12. session.setAttribute(dataName, dataValue);
13. }
14.%>
15.<br />
16.<br />
17.<b>Session属性列表:</b>
18.
19.<br />
20.<%
21. Enumeration<String> e = (Enumeration<String>) session
22. .getAttributeNames();
23. while (e.hasMoreElements()) {
24. String name = e.nextElement();
25. String value = (String) session.getAttribute(name);
26. out.println(name + " = " + value + "<br>");
27. System.err.println(name + " = " + value);
28. }
29.%>
30.<form method="POST">
31.<ul style="list-style-type: none;">
32. <li><label for="dataName">键:</label><input size="20" id="dataName"
33. name="dataName"></li>
34. <li><label for="dataValue">值:</label><input size="20"
35. id="dataValue" name="dataValue"></li>
36. <li><input type="submit" value="提交" /></li>
37.</ul>
38.</form>
<b>当前SessionID:</b>
<br />
<%
String sessionID = session.getId();
out.println(sessionID);
System.err.println("sessionID = " + sessionID);
// 如果有新的 Session 属性设置
String dataName = request.getParameter("dataName");
if (dataName != null && !dataName.isEmpty()) {
String dataValue = request.getParameter("dataValue");
session.setAttribute(dataName, dataValue);
}
%>
<br />
<br />
<b>Session属性列表:</b>
<br />
<%
Enumeration<String> e = (Enumeration<String>) session
.getAttributeNames();
while (e.hasMoreElements()) {
String name = e.nextElement();
String value = (String) session.getAttribute(name);
out.println(name + " = " + value + "<br>");
System.err.println(name + " = " + value);
}
%>
<form method="POST">
<ul style="list-style-type: none;">
<li><label for="dataName">键:</label><input size="20" id="dataName"
name="dataName"></li>
<li><label for="dataValue">值:</label><input size="20"
id="dataValue" name="dataValue"></li>
<li><input type="submit" value="提交" /></li>
</ul>
</form>
将其做成一个名为zlex的web应用,分别部署到两个Tomcat上!
然后重启Apache:
Shell代码
1.sudo /etc/init.d/apache2 restart
sudo /etc/init.d/apache2 restart
不断刷新http://localhost/zlex,看看真正的结果:
第1次:
第2次:
第3次:
第4次:
仔细观察,每次请求都按照负载均衡配置的节点次序依次请求到不同的Tomcat上。尤其是当我们通过jvmRoute和route做了绑定之后,信息更加准确。但是,仔细观察,每次请求的SessionID都是不一样!对于纯Web应用,尤其是依靠SessionID区分唯一用户的应用,这将是一场噩梦——解决了服务器压力均衡问题,却带来了SessionID不唯一问题!这就需要SessionID绑定,或者说叫做“会话复制”。
如果这时候你在页面上提交表单,将键值对保持在session中,在页面刷新后,将无法获得该信息,因为Seesion丢失了!
接着修改/etc/apache2/mods-available/proxy.conf,让SeesionID保持唯一:
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
增加stickySession属性:
Conf代码
1.ProxyPass /zlex balancer://zlex stickySession=JSESSIONID
ProxyPass /zlex balancer://zlex stickySession=JSESSIONID
stickySession粘性会话,根据这一属性,浏览器将通过cookie绑定SeesionID。如果这个时候再次访问http://localhost/zlex,你会发现,页面不会来回跳转了!
sticky是什么?
引用
sticky模式
利用负载均衡器的sticky模式的方式把所有同一session的请求都发送到相同的Tomcat节点。这样不同用户的请求就被平均分配到集群中各个tomcat节点上,实现负载均衡的能力。这样做的缺点是没有灾难恢复的能力。一旦一个节点发生故障,这个节点上所有的session信息全部丢失;
同一用户同一session只和一个webServer交互,一旦这个webserver发生故障,本次session将丢失,用户不能继续使用 !
提交一个Session设定看看http://localhost/zlex:
观察后台日志:
再看看返回页面,这相当于一次页面刷新,如果正常粘性会话,我们将获得当前SessionID对应的一切信息:
这说明粘性会话生效了!
我们得到了形如
引用
50DAF14C6CDF8ACFBDC1095A5EE8E2CF.tomcat1
的SessionID。这样,我们就能知道当前访问的是哪台服务器了!
如果,换一个浏览器打开该页面http://localhost/zlex,将会获得一个新的SessionID,并且,根据Apache中配置的负载均衡节点列表依次访问下一个节点!
如果这时候负载均衡节点列表中某一节点发生异常,那么Apache将按照惯例,跳转该节点,并在该节点恢复正常后约1分钟内重新将其纳入可用节点!
修改刚才的jsp页面,看看Http头中都有些什么:
Jsp代码
1.<b>Cookie信息:</b>
2.<br />
3.${header["cookie"]}
4.<br />
5.<b>Host信息:</b>
6.<br />
7.${header["host"]}
8.<br />
<b>Cookie信息:</b>
<br />
${header["cookie"]}
<br />
<b>Host信息:</b>
<br />
${header["host"]}
<br />
sticky模式的根本在于浏览器支持cookie,如果浏览器不支持cookie,则需要修改server.xml文件中的<Context />节点,将cookie置为false,关闭cookie功能,让jsessionid显式传递!
6.Tomcat集群,Session复制
经过两天反复研究,两只互不相认的Tomcat终于在网络上“资源共享”了——Session复制成功!
关于Tomcat集群以及Session复制,网上已经有很多很多,但是否真的能用?!为了确认这一问题,周末还跑到书店翻了翻《Apache Tomcat 高级编程》,参考Clustering/Session Replication HOW-TO(有点小错误),经过两天苦战,克服种种小问题,终于拿下!
整理概念:
引用
群集,是包含多个服务器实例的指定集合,这些服务器实例共享相同的应用程序、资源以及配置信息。您可以将不同计算机上的服务器实例分组到一个逻辑群集中并将其作为一个单元来管理。您可以使用 DAS 轻松控制多机群集的生命周期。
群集可以实现水平可伸缩性、负载平衡和故障转移保护。根据定义,群集中的所有实例都具有相同的资源和应用程序配置。当群集中的服务器实例或计算机出现故障时,负载平衡器检测到该故障,会将通信从出现故障的实例重定向至群集中的其他实例,并恢复用户会话状态。由于群集中所有实例上的应用程序和资源都相同,因此一个实例可以故障转移至群集中的任何其他实例。
引用
Session复制,主要是指集群环境下,多台应用服务器之间同步Session,确保Session保持一致,且Session中的内容保持一致,对外透明——看起来就像是一台应用服务器!
如果其中一台服务器发生故障,根据负载均衡的原理,Apache会遍历寻找可用节点,分发请求。与此同时,当前用户Session不能发生数据丢失,其余各节点服务器应保证用户Session数据同步。
Session复制核心内容主要是:
1.Session内容序列化(serialize),会消耗系统性能。
2.Session内容通过广播同步给成员,会造成网络流量瓶颈,即便是内网瓶颈。
因此,Session复制的这两个潜在问题,致使复杂均衡节点最多不会超过4个。因为,当节点数大于4时,整个集群的吞吐量将不再上升!
为了搭建Tomcat集群,我将两个Tomcat分别部署到两台虚拟机上,确保网段一致。(这一步很关键,我最初将Tomcat1(192.168.49.132)部署在虚拟机上,将Tomcat2(192.168.49.128)部署在本机上,结果,网络总有问题,耽误了很多时间。 )
由于变换了IP,我需要修改Apache的/etc/apache2/mods-available/proxy.conf文件:
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
修改负载均衡节点如下:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://192.168.49.128:8009/zlex route=tomcat1
3. BalancerMember ajp://192.168.49.132:8009/zlex route=tomcat2
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember ajp://192.168.49.128:8009/zlex route=tomcat1
BalancerMember ajp://192.168.49.132:8009/zlex route=tomcat2
</Proxy>
对于windows系统,不需要考虑网络问题,广播地址(这里用到224.0.0.0和240.0.0.0)默认开放,对于linux则需要通过命令开放地址。
Ubuntu上开放广播地址(eth0网卡):
Shell代码
1.sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
然后通过-v参数查看当前开放的广播地址:
Shell代码
1.route -v
route -v
注意,重启后,该路由设置将丢失!
在Ubuntu下,可以考虑修改/etc/networks文件!
如果有必要,Windows上开放广播地址(192.168.49.128本机地址):
Cmd代码
1.route add 224.0.0.0 mask 240.0.0.0 192.168.49.128
route add 224.0.0.0 mask 240.0.0.0 192.168.49.128
然后通过print参数查看当前开放的广播地址:
Shell代码
1.route print
route print
然后,修改tomcat的server.xml文件:
Shell代码
1.sudo vi /etc/tomcat6/server.xml
sudo vi /etc/tomcat6/server.xml
在<Engine /> 节点中加入如下内容:
Xml代码
1. <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
2. channelSendOptions="8">
3.
4. <Manager className="org.apache.catalina.ha.session.DeltaManager"
5. expireSessionsOnShutdown="false"
6. notifyListenersOnReplication="true"/>
7.
8. <Channel className="org.apache.catalina.tribes.group.GroupChannel">
9. <Membership className="org.apache.catalina.tribes.membership.McastService"
10. address="224.0.0.0"
11. port="45564"
12. frequency="500"
13. dropTime="3000"/>
14. <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
15. address="192.168.49.1"
16. port="4000"
17. autoBind="100"
18. selectorTimeout="5000"
19. maxThreads="6"/>
20.
21. <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
22. <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
23. </Sender>
24. <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
25. <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
26. </Channel>
27.
28. <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
29. filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
30. <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
31.
32. <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
33. <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
34.</Cluster>
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="224.0.0.0"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="192.168.49.1"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
这里需要注意<Membership />和Receiver:<Membership />节点的address属性是广播地址;Receiver节点的address属性是本地绑定地址。当然,默认为auto。由于我在启动Tomcat时,Tomcat频频将地址指向127.0.0.1,无奈只好使用固定IP。
此外,为了降低Session复制的成本,Tomcat通过<Valve />节点,以过滤器的方式控制哪些请求可以忽略Session复制:
Xml代码
1.<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
2. filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
同时,在<Host>节点中加入如下内容:
Xml代码
1.<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
2. tempDir="/tmp/war-temp/"
3. deployDir="/tmp/war-deploy/"
4. watchDir="/tmp/war-listen/"
5. watchEnabled="false"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
在Tomcat的官方文档(Tomcat 6)中,对于<Deployer />节点的部署位置是错误的,通过观察Tomcat启动日志,确认该节点应当不属于<Host />节点中!
注意:Tomcat 6与Tomcat5在上述节点中使用的类包(包中名称由cluster变化为ha)有所不同,且结构有所调整。
先别急着重启,我们需要修改应用中的web.xml文件,将<distributable />节点部署到<web-app />节点中,开启分布式服务:
注意:如果没有设置该节点,SessionID将不能保持同步,不同的服务器将各自建立独立的SessionID!
监控Tomcat日志:
Shell代码
1.tail -f /var/lib/tomcat6/logs/catalina.out
tail -f /var/lib/tomcat6/logs/catalina.out
然后重启Tomcat1:
Shell代码
1.sudo /etc/init.d/tomcat6 restart
sudo /etc/init.d/tomcat6 restart
观察日志:
注意两处红框:
第一处,Cluster启动,并绑定192.168.49.132:4000上,进行TCP通讯,并等待其它成员(Member)。
第二处,在管理器中注册/zlex,绑定JvmRouteBinderValve。
至此,说明集群设置已经生效,但不能说明集群配置成功!
接着我们启动Tomcat2,观察其日志:
Cluster启动,并绑定192.168.49.128:4000上并发现成员192.168.49.132!
再看Tomcat1的日志:
Tomcat1发现其成员Tomcat2!这说明TCP通讯已建立,Tomcat成员可以进行Session同步!
同时,Tomcat成员直接会每隔一个时间段相互侦测/验证其他成员是否正常:
现在,开始访问http://localhost/zlex,并不断刷新当前页面:
除了两处标识主机来源的tomcatX不同外,session是完全一致的!
提交一次修改,并不断刷新当前页:
如果仔细观察,当前SessionID在不断交替变化,这说明负载均衡在起作用!
我们再来看看2个Tomcat后台日志都做了什么!
Tomcat1:
Tomcat2:
两只猫都打印了相同的内容(a=1)不同的细节在于,sessionID带有服务器标识!
如果我们强行关闭Tomcat2:
首先,Tomcat1会很快侦测到Tomcat2离线,因为这是TCP通讯,成员之间很容易检测到其他成员是否离线!Tomcat1后台日志如下:
其次,Apache会侦测到Tomcat2发生异常,将其余请求转交给其他节点,即交由Tomcat1处理!
继续刷新http://localhost/zlex当前页面,耐心等待几秒。你会发现,即便再次刷新页面,sessionID仍旧绑定在标识tomcat1服务器上。
然后,我们恢复Tomcat2服务,Tomcat1会马上侦测到Tomcat2已经恢复正常:
最后,我们再次刷新当前页,Apache已经将请求分发给Tomcat2了,从后台日志可以看到session信息会很快被同步了!
如果带有tomcatX标识的sessionID有很多不便之处,可以关闭粘性会话。简单的讲,就是取消Tomcat中server.xml中<Engine/ >节点的jvmRoute属性!然后,重启tomcat、apache!
页面提交一个b=3!
左边为Tomcat1,右边为Tomcat2!SessionID一致!
除了上述几种方案外,还有Terracotta模式。一种第三方集群组件,2009年收购了缓存组件EhCache,可以结合Tomcat、JBoss等多种服务器,提供多种负载均衡、集群等功能实现,且当负载均衡节点超过8个时,仍然能够保持集群吞吐量的线性增长。
Eclipse插件地址:
http://download.terracotta.org/eclipse/update
下载地址:
http://www.terracotta.org/dl/oss-download-catalog
至此,Apache + Tomcat成功完成,征服Apache系列暂告一段落!
作为开博以来的第100帖,算是很成功了!
测试应用见附件!
相关内容:
征服 Apache + SSL
征服 Apache + SVN
征服 Apache + SVN + LDAP
征服 Apache + Tomcat
征服 Nginx
征服 Nginx + Tomcat
ApacheTomcat应用服务器配置管理Ubuntu .
Apache 和 Tomcat原本就是一家,更是一家亲!Apache与Tomcat整合,无非是将Apache作为前端根据请求路径、端口、代理分发给多个Tomcat,以到达转发和负载均衡的目的!同时,通过Apache和Tomcat相互作用,进行粘性会话,会话拷贝构建集群!这一切的最终结果就是“云服务”!不要说Session不重要,当下火爆的团购,如果离开Session还能快活多久?如何保证Session同步,仍然是不能回避的问题!
这里要说的是基于HTTP和AJP跳转方式的负载均衡实现,关于JK,由于效率问题一直成为诟病,并且mod_jk2模块已经不再被更新了,这里就不折腾它的复杂配置了!
至于说Apache+Tomcat+SSL,并不是难题!只要完成了Apache+SSL然后配置相应的负载均衡、反向代理等等就可以达到目的,相关Apache+SSL参考征服 Apache + SSL
Ubuntu Server 10.04版本,Apache选用2.2.14,Tomcat选用6.0.24。
相关内容:
征服 Apache + SSL
征服 Apache + SVN
征服 Apache + SVN + LDAP
征服 Apache + Tomcat
征服 Nginx
征服 Nginx + Tomcat
步骤:
1.安装Apache基本模块
2.后台监控
3.负载均衡简单测试
4.配置Tomcat相关模块(AJP)
5.保持Session唯一,粘性会话
6.Tomcat集群,Session复制
1.安装Apache相关模块
负载均衡需要的主要是代理模块!
经过几次Apache配置尝试,在Ubuntu下配置Apache实在是太容易了。加载什么模块、取消什么模块两个命令搞定。
Shell代码
1.#启用模块
2.sudo a2enmod <model>
3.#禁用模块
4.sudo a2dismod <model>
#启用模块
sudo a2enmod <model>
#禁用模块
sudo a2dismod <model>
这里,我们需要让Apache提供代理服务,其中又包含基于http、ftp、ajp等等协议的代理功能,同时还需要负载均衡模块。我们可以通过命令逐个加载:
Shell代码
1.#代理核心模块
2.sudo a2enmod proxy
3.#代理AJP模块
4.sudo a2enmod proxy_ajp
5.#代理负载均衡模块
6.sudo a2enmod proxy_balancer
7.#代理HTTP模块
8.sudo a2enmod proxy_http
9.#代理FTP模块
10.sudo a2enmod proxy_ftp
#代理核心模块
sudo a2enmod proxy
#代理AJP模块
sudo a2enmod proxy_ajp
#代理负载均衡模块
sudo a2enmod proxy_balancer
#代理HTTP模块
sudo a2enmod proxy_http
#代理FTP模块
sudo a2enmod proxy_ftp
完成上述操作后,系统会提示重启Apache!
先不着急重启,现学现卖,了解下Apache的目录结构。在Ubuntu下配置Apache主要是在/etc/apache2目录下:
分述:
•apache2.conf核心配置文件,一般不需要修改!
•conf.d目录,里面包含了一些字符集设置,文档等设置!
•dav_svn.authz和dav_svn.passwd是前面做SVN时,相关权限、密码文件。
•envvars定义了运行时的用户身份——www-data。
•httpd.conf是Apache留给我们自己折腾的配置文件,默认为空。apache2.conf会加载这个文件。
•ports.conf端口默认配置。apache2.conf会加载这个文件。
•magic为mod_mime_magic模块服务。
•mods-enabled和mods-available mods-enabled会被apache2.conf加载,里面包含*.load和*.conf文件。*.load文件中是加载相应的模块(位于/usr/lib/apache2/modules/中),而*.conf中是对应的基本配置。但这些文件其实都是链接到mods-available中相应的文件上。当我们通过a2enmod操作时,实际上正是操作了这些软链接。
•sites-available和sites-enabled 与 mods-enabled和mods-available的关系类似,只是其中包含的是站点内容。
罗嗦了一堆,下面配置负载均衡部分。
执行修改:
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
上图红框中的内容是原始内容,白框中的内容是我新加的部分。
注意红框中的配置:
Conf代码
1.<Proxy *>
2. AddDefaultCharset off
3. Order deny,allow
4. #Deny from all
5. Allow from localhost ip6-localhost
6.</Proxy>
<Proxy *>
AddDefaultCharset off
Order deny,allow
#Deny from all
Allow from localhost ip6-localhost
</Proxy>
在默认配置中,Deny from all处于可用状态。当我们配置其他代理节点时,将导致杜绝访问!使用Allow from localhost ip6-localhost 限制仅允许本机访问!
再说,白框中的内容:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember http://localhost:8080/
3. BalancerMember http://192.168.49.1:8080/
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember http://localhost:8080/
BalancerMember http://192.168.49.1:8080/
</Proxy>
这里,我配置了一个负载均衡节点balancer://zlex,其中包含了两个服务http://localhost:8080/和http://192.168.49.1:8080/,一个是虚拟机上的Tomcat、一个是真机上的Tomcat。这里使用的Http的转发方式,当然,使用AJP未尝不可,稍后详述!
这里的节点次序会有一个先后关系,Apache会将请求按照FIFO的方式调度顺次分配到各个节点上!如果其中有一个节点挂掉,将跳过该节点顺次寻找可用节点。
再说代理和反向代理:
Conf代码
1.ProxyPass /zlex balancer://zlex
2.ProxyPassReverse /zlex balancer://zlex
ProxyPass /zlex balancer://zlex
ProxyPassReverse /zlex balancer://zlex
这里配置,如果要访问/zlex路径时,将跳转到balancer://zlex上,也就是享受负载均衡!
2.后台监控
我们如何知道某个节点负载多少,响应时间多久,服务是否正常呢?Apache提供了负载均衡监控平台:http://localhost/balancer-manager。但是,这个服务默认是不存在。
除了用于负载均衡配置、监控的balancer-manager还有http://localhost/server-status和http://localhost/server-info
我们需要添加info模块:
Shell代码
1.#系统信息模块
2.sudo a2enmod info
#系统信息模块
sudo a2enmod info
同时,为了能够使用balancer-manager,我们需要配置:
Conf代码
1.<Location /balancer-manager>
2. SetHandler balancer-manager
3. Order Deny,Allow
4. #Deny from all
5. Allow from localhost ip6-localhost
6.</Location>
<Location /balancer-manager>
SetHandler balancer-manager
Order Deny,Allow
#Deny from all
Allow from localhost ip6-localhost
</Location>
把这段代码放到哪?由于它同属系统信息配置,我把它放到了info.conf中,说白了就是照猫画虎:
Shell代码
1.sudo vi /etc/apache2/mods-available/info.conf
sudo vi /etc/apache2/mods-available/info.conf
注意,这段代码放到了<IfModule mod_info.c>和</IfModule>之间!
现在,我们重启Apache:
Shell代码
1.sudo /etc/init.d/apache2 restart
sudo /etc/init.d/apache2 restart
来看看管理界面http://localhost/balancer-manager:
我们再来看看服务器基本信息http://localhost/server-info:
上述两个服务需要加载info模块,而服务器状态(server-status)不需要http://localhost/server-status:
3.负载均衡简单测试
疯狂访问http://localhost/zlex,直到手酸眼烦!
我这里故意使用不同了Tomcat界面,来验证自己的配置是否生效。更疯狂的是,我甚至把节点指向了百度、搜狐,来测试负载均衡的效果。如果你细致观察,Apache是将请求顺次分配到各个节点上的。
如果其中一个节点发生问题(例如,强行关闭一个Tomcat,或配置一个错误节点)Apache将会经过几次尝试后,绕过这个问题节点,寻找可以成功访问的节点。如果这个节点恢复正常使用,Apache将在该Tomcat恢复正常工作后大约1分钟内将该节点标识为可用!
现在,再看看现在的后台(http://localhost/balancer-manager)啥样子:
如果我们控制一个节点的状态是否可用,该怎么做:
涉及到负载量,session同步等等,我们最后讨论!
4.配置Tomcat相关模块(AJP)
基于Http协议分发并不复杂,但AJP效果更好!一次诡异事件中,内网访问正常,外网访问多次失败,最后通过AJP方式完美解决了!
在Tomcat中配置AJP也很简单,修改server.xml开启AJP模块:
Shell代码
1.sudo vi /etc/tomcat6/server.xml
sudo vi /etc/tomcat6/server.xml
开启AJP配置:
Xml代码
1.<Connector port="8009" protocol="AJP/1.3"
2. URIEncoding="UTF-8"
3. redirectPort="8443" />
<Connector port="8009" protocol="AJP/1.3"
URIEncoding="UTF-8"
redirectPort="8443" />
注意使用的端口port="8009",字符集URIEncoding="UTF-8",这是输入框、请求字符集乱码的入口!
接下里就可以通过AJP方式进行节点分发了。修改/etc/apache2/mods-available/proxy.conf :
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
将http改为ajp,将8080改为8009:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://localhost:8009/
3. BalancerMember ajp://192.168.49.1:8009/
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember ajp://localhost:8009/
BalancerMember ajp://192.168.49.1:8009/
</Proxy>
重启Apache:
Shell代码
1.sudo /etc/init.d/apache2 restart
sudo /etc/init.d/apache2 restart
再看看管理界面http://localhost/balancer-manager
至此,我们完成了基本负载均衡的基本配置!
/etc/apache2/mods-available/proxy.conf还有一些属性:
noFailOver是否打开失败转移,On|Off,默认为Off,添加在ProxyPass后面,如:
Conf代码
1.ProxyPass /zlex balancer://zlex stickySession=JSESSIONID noFailOver=On
ProxyPass /zlex balancer://zlex stickySession=JSESSIONID noFailOver=On
如果这样配置,当提供给你服务的服务器发生异常,那么你将一直看着它返回给你503,直到系统恢复正常!
loadfactor表示后台服务器负载到由Apache发送请求的权值,默认值为1添加在BalancerMember后面:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://localhost:8009/
3. BalancerMember ajp://192.168.49.1:8009/
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember ajp://localhost:8009/
BalancerMember ajp://192.168.49.1:8009/
</Proxy>
可以实现三种策略:
1.轮询均衡策略的配置
2.按权重分配均衡策略的配置
3.权重请求响应负载均衡策略的配置
5.Session唯一,粘性会话
Apache已经可以轻松将内容处理的工作分配给各个Tomcat了!
当然,这还不够,Session还是个问题!
WHY?
我们来做一系列修改,来检测Session到底出现了什么问题!
先来改造Tomcat,修改server.xml:
Shell代码
1.sudo vi /etc/tomcat6/server.xml
sudo vi /etc/tomcat6/server.xml
修改<Engine />节点,增加jvmRoute属性:
Xml代码
1.<Engine
2. name="Catalina"
3. defaultHost="localhost"
4. jvmRoute="tomcat1">
<Engine
name="Catalina"
defaultHost="localhost"
jvmRoute="tomcat1">
另一个Tomcat设置改为
Xml代码
1.<Engine
2. name="Catalina"
3. defaultHost="localhost"
4. jvmRoute="tomcat2">
<Engine
name="Catalina"
defaultHost="localhost"
jvmRoute="tomcat2">
通过jvmRoute,指定了Tomcat唯一标识!
然后修改/etc/apache2/mods-available/proxy.conf
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
如下:
Java代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://localhost:8009/zlex route=tomcat1
3. BalancerMember ajp://192.168.49.1:8009/zlex route=tomcat2
4.</Proxy>
5.
6.ProxyPass /zlex balancer://zlex
7.ProxyPassReverse /zlex balancer://zlex
<Proxy balancer://zlex>
BalancerMember ajp://localhost:8009/zlex route=tomcat1
BalancerMember ajp://192.168.49.1:8009/zlex route=tomcat2
</Proxy>
ProxyPass /zlex balancer://zlex
ProxyPassReverse /zlex balancer://zlex
这里需要通过修改route属性,将Apache与Tomcat关联起来!
注意,Tomcat中定义的jvmRoute需要与Apache定义的route相对应!
我们来看一下http://localhost/balancer-manager发生了什么变化:
我们注意到route字段有了新的标识,当然,我们也可以通过这个配置界面修改这些信息,但当前修改不会真的修改/etc/apache2/mods-available/proxy.conf文件,Apache重启后将丢失。
为了更细致的对比进过复杂均衡的结果,这里增加了zlex应用!主要是监控Session的变化!
只看核心代码:
Jsp代码
1.<b>当前SessionID:</b>
2.<br />
3.<%
4. String sessionID = session.getId();
5. out.println(sessionID);
6. System.err.println("sessionID = " + sessionID);
7.
8. // 如果有新的 Session 属性设置
9. String dataName = request.getParameter("dataName");
10. if (dataName != null && !dataName.isEmpty()) {
11. String dataValue = request.getParameter("dataValue");
12. session.setAttribute(dataName, dataValue);
13. }
14.%>
15.<br />
16.<br />
17.<b>Session属性列表:</b>
18.
19.<br />
20.<%
21. Enumeration<String> e = (Enumeration<String>) session
22. .getAttributeNames();
23. while (e.hasMoreElements()) {
24. String name = e.nextElement();
25. String value = (String) session.getAttribute(name);
26. out.println(name + " = " + value + "<br>");
27. System.err.println(name + " = " + value);
28. }
29.%>
30.<form method="POST">
31.<ul style="list-style-type: none;">
32. <li><label for="dataName">键:</label><input size="20" id="dataName"
33. name="dataName"></li>
34. <li><label for="dataValue">值:</label><input size="20"
35. id="dataValue" name="dataValue"></li>
36. <li><input type="submit" value="提交" /></li>
37.</ul>
38.</form>
<b>当前SessionID:</b>
<br />
<%
String sessionID = session.getId();
out.println(sessionID);
System.err.println("sessionID = " + sessionID);
// 如果有新的 Session 属性设置
String dataName = request.getParameter("dataName");
if (dataName != null && !dataName.isEmpty()) {
String dataValue = request.getParameter("dataValue");
session.setAttribute(dataName, dataValue);
}
%>
<br />
<br />
<b>Session属性列表:</b>
<br />
<%
Enumeration<String> e = (Enumeration<String>) session
.getAttributeNames();
while (e.hasMoreElements()) {
String name = e.nextElement();
String value = (String) session.getAttribute(name);
out.println(name + " = " + value + "<br>");
System.err.println(name + " = " + value);
}
%>
<form method="POST">
<ul style="list-style-type: none;">
<li><label for="dataName">键:</label><input size="20" id="dataName"
name="dataName"></li>
<li><label for="dataValue">值:</label><input size="20"
id="dataValue" name="dataValue"></li>
<li><input type="submit" value="提交" /></li>
</ul>
</form>
将其做成一个名为zlex的web应用,分别部署到两个Tomcat上!
然后重启Apache:
Shell代码
1.sudo /etc/init.d/apache2 restart
sudo /etc/init.d/apache2 restart
不断刷新http://localhost/zlex,看看真正的结果:
第1次:
第2次:
第3次:
第4次:
仔细观察,每次请求都按照负载均衡配置的节点次序依次请求到不同的Tomcat上。尤其是当我们通过jvmRoute和route做了绑定之后,信息更加准确。但是,仔细观察,每次请求的SessionID都是不一样!对于纯Web应用,尤其是依靠SessionID区分唯一用户的应用,这将是一场噩梦——解决了服务器压力均衡问题,却带来了SessionID不唯一问题!这就需要SessionID绑定,或者说叫做“会话复制”。
如果这时候你在页面上提交表单,将键值对保持在session中,在页面刷新后,将无法获得该信息,因为Seesion丢失了!
接着修改/etc/apache2/mods-available/proxy.conf,让SeesionID保持唯一:
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
增加stickySession属性:
Conf代码
1.ProxyPass /zlex balancer://zlex stickySession=JSESSIONID
ProxyPass /zlex balancer://zlex stickySession=JSESSIONID
stickySession粘性会话,根据这一属性,浏览器将通过cookie绑定SeesionID。如果这个时候再次访问http://localhost/zlex,你会发现,页面不会来回跳转了!
sticky是什么?
引用
sticky模式
利用负载均衡器的sticky模式的方式把所有同一session的请求都发送到相同的Tomcat节点。这样不同用户的请求就被平均分配到集群中各个tomcat节点上,实现负载均衡的能力。这样做的缺点是没有灾难恢复的能力。一旦一个节点发生故障,这个节点上所有的session信息全部丢失;
同一用户同一session只和一个webServer交互,一旦这个webserver发生故障,本次session将丢失,用户不能继续使用 !
提交一个Session设定看看http://localhost/zlex:
观察后台日志:
再看看返回页面,这相当于一次页面刷新,如果正常粘性会话,我们将获得当前SessionID对应的一切信息:
这说明粘性会话生效了!
我们得到了形如
引用
50DAF14C6CDF8ACFBDC1095A5EE8E2CF.tomcat1
的SessionID。这样,我们就能知道当前访问的是哪台服务器了!
如果,换一个浏览器打开该页面http://localhost/zlex,将会获得一个新的SessionID,并且,根据Apache中配置的负载均衡节点列表依次访问下一个节点!
如果这时候负载均衡节点列表中某一节点发生异常,那么Apache将按照惯例,跳转该节点,并在该节点恢复正常后约1分钟内重新将其纳入可用节点!
修改刚才的jsp页面,看看Http头中都有些什么:
Jsp代码
1.<b>Cookie信息:</b>
2.<br />
3.${header["cookie"]}
4.<br />
5.<b>Host信息:</b>
6.<br />
7.${header["host"]}
8.<br />
<b>Cookie信息:</b>
<br />
${header["cookie"]}
<br />
<b>Host信息:</b>
<br />
${header["host"]}
<br />
sticky模式的根本在于浏览器支持cookie,如果浏览器不支持cookie,则需要修改server.xml文件中的<Context />节点,将cookie置为false,关闭cookie功能,让jsessionid显式传递!
6.Tomcat集群,Session复制
经过两天反复研究,两只互不相认的Tomcat终于在网络上“资源共享”了——Session复制成功!
关于Tomcat集群以及Session复制,网上已经有很多很多,但是否真的能用?!为了确认这一问题,周末还跑到书店翻了翻《Apache Tomcat 高级编程》,参考Clustering/Session Replication HOW-TO(有点小错误),经过两天苦战,克服种种小问题,终于拿下!
整理概念:
引用
群集,是包含多个服务器实例的指定集合,这些服务器实例共享相同的应用程序、资源以及配置信息。您可以将不同计算机上的服务器实例分组到一个逻辑群集中并将其作为一个单元来管理。您可以使用 DAS 轻松控制多机群集的生命周期。
群集可以实现水平可伸缩性、负载平衡和故障转移保护。根据定义,群集中的所有实例都具有相同的资源和应用程序配置。当群集中的服务器实例或计算机出现故障时,负载平衡器检测到该故障,会将通信从出现故障的实例重定向至群集中的其他实例,并恢复用户会话状态。由于群集中所有实例上的应用程序和资源都相同,因此一个实例可以故障转移至群集中的任何其他实例。
引用
Session复制,主要是指集群环境下,多台应用服务器之间同步Session,确保Session保持一致,且Session中的内容保持一致,对外透明——看起来就像是一台应用服务器!
如果其中一台服务器发生故障,根据负载均衡的原理,Apache会遍历寻找可用节点,分发请求。与此同时,当前用户Session不能发生数据丢失,其余各节点服务器应保证用户Session数据同步。
Session复制核心内容主要是:
1.Session内容序列化(serialize),会消耗系统性能。
2.Session内容通过广播同步给成员,会造成网络流量瓶颈,即便是内网瓶颈。
因此,Session复制的这两个潜在问题,致使复杂均衡节点最多不会超过4个。因为,当节点数大于4时,整个集群的吞吐量将不再上升!
为了搭建Tomcat集群,我将两个Tomcat分别部署到两台虚拟机上,确保网段一致。(这一步很关键,我最初将Tomcat1(192.168.49.132)部署在虚拟机上,将Tomcat2(192.168.49.128)部署在本机上,结果,网络总有问题,耽误了很多时间。 )
由于变换了IP,我需要修改Apache的/etc/apache2/mods-available/proxy.conf文件:
Shell代码
1.sudo vi /etc/apache2/mods-available/proxy.conf
sudo vi /etc/apache2/mods-available/proxy.conf
修改负载均衡节点如下:
Conf代码
1.<Proxy balancer://zlex>
2. BalancerMember ajp://192.168.49.128:8009/zlex route=tomcat1
3. BalancerMember ajp://192.168.49.132:8009/zlex route=tomcat2
4.</Proxy>
<Proxy balancer://zlex>
BalancerMember ajp://192.168.49.128:8009/zlex route=tomcat1
BalancerMember ajp://192.168.49.132:8009/zlex route=tomcat2
</Proxy>
对于windows系统,不需要考虑网络问题,广播地址(这里用到224.0.0.0和240.0.0.0)默认开放,对于linux则需要通过命令开放地址。
Ubuntu上开放广播地址(eth0网卡):
Shell代码
1.sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
sudo route add -net 224.0.0.0 netmask 240.0.0.0 dev eth0
然后通过-v参数查看当前开放的广播地址:
Shell代码
1.route -v
route -v
注意,重启后,该路由设置将丢失!
在Ubuntu下,可以考虑修改/etc/networks文件!
如果有必要,Windows上开放广播地址(192.168.49.128本机地址):
Cmd代码
1.route add 224.0.0.0 mask 240.0.0.0 192.168.49.128
route add 224.0.0.0 mask 240.0.0.0 192.168.49.128
然后通过print参数查看当前开放的广播地址:
Shell代码
1.route print
route print
然后,修改tomcat的server.xml文件:
Shell代码
1.sudo vi /etc/tomcat6/server.xml
sudo vi /etc/tomcat6/server.xml
在<Engine /> 节点中加入如下内容:
Xml代码
1. <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
2. channelSendOptions="8">
3.
4. <Manager className="org.apache.catalina.ha.session.DeltaManager"
5. expireSessionsOnShutdown="false"
6. notifyListenersOnReplication="true"/>
7.
8. <Channel className="org.apache.catalina.tribes.group.GroupChannel">
9. <Membership className="org.apache.catalina.tribes.membership.McastService"
10. address="224.0.0.0"
11. port="45564"
12. frequency="500"
13. dropTime="3000"/>
14. <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
15. address="192.168.49.1"
16. port="4000"
17. autoBind="100"
18. selectorTimeout="5000"
19. maxThreads="6"/>
20.
21. <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
22. <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
23. </Sender>
24. <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
25. <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
26. </Channel>
27.
28. <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
29. filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
30. <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
31.
32. <ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
33. <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
34.</Cluster>
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="8">
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
<Channel className="org.apache.catalina.tribes.group.GroupChannel">
<Membership className="org.apache.catalina.tribes.membership.McastService"
address="224.0.0.0"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="192.168.49.1"
port="4000"
autoBind="100"
selectorTimeout="5000"
maxThreads="6"/>
<Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
</Sender>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
<Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
这里需要注意<Membership />和Receiver:<Membership />节点的address属性是广播地址;Receiver节点的address属性是本地绑定地址。当然,默认为auto。由于我在启动Tomcat时,Tomcat频频将地址指向127.0.0.1,无奈只好使用固定IP。
此外,为了降低Session复制的成本,Tomcat通过<Valve />节点,以过滤器的方式控制哪些请求可以忽略Session复制:
Xml代码
1.<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
2. filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;"/>
同时,在<Host>节点中加入如下内容:
Xml代码
1.<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
2. tempDir="/tmp/war-temp/"
3. deployDir="/tmp/war-deploy/"
4. watchDir="/tmp/war-listen/"
5. watchEnabled="false"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
在Tomcat的官方文档(Tomcat 6)中,对于<Deployer />节点的部署位置是错误的,通过观察Tomcat启动日志,确认该节点应当不属于<Host />节点中!
注意:Tomcat 6与Tomcat5在上述节点中使用的类包(包中名称由cluster变化为ha)有所不同,且结构有所调整。
先别急着重启,我们需要修改应用中的web.xml文件,将<distributable />节点部署到<web-app />节点中,开启分布式服务:
注意:如果没有设置该节点,SessionID将不能保持同步,不同的服务器将各自建立独立的SessionID!
监控Tomcat日志:
Shell代码
1.tail -f /var/lib/tomcat6/logs/catalina.out
tail -f /var/lib/tomcat6/logs/catalina.out
然后重启Tomcat1:
Shell代码
1.sudo /etc/init.d/tomcat6 restart
sudo /etc/init.d/tomcat6 restart
观察日志:
注意两处红框:
第一处,Cluster启动,并绑定192.168.49.132:4000上,进行TCP通讯,并等待其它成员(Member)。
第二处,在管理器中注册/zlex,绑定JvmRouteBinderValve。
至此,说明集群设置已经生效,但不能说明集群配置成功!
接着我们启动Tomcat2,观察其日志:
Cluster启动,并绑定192.168.49.128:4000上并发现成员192.168.49.132!
再看Tomcat1的日志:
Tomcat1发现其成员Tomcat2!这说明TCP通讯已建立,Tomcat成员可以进行Session同步!
同时,Tomcat成员直接会每隔一个时间段相互侦测/验证其他成员是否正常:
现在,开始访问http://localhost/zlex,并不断刷新当前页面:
除了两处标识主机来源的tomcatX不同外,session是完全一致的!
提交一次修改,并不断刷新当前页:
如果仔细观察,当前SessionID在不断交替变化,这说明负载均衡在起作用!
我们再来看看2个Tomcat后台日志都做了什么!
Tomcat1:
Tomcat2:
两只猫都打印了相同的内容(a=1)不同的细节在于,sessionID带有服务器标识!
如果我们强行关闭Tomcat2:
首先,Tomcat1会很快侦测到Tomcat2离线,因为这是TCP通讯,成员之间很容易检测到其他成员是否离线!Tomcat1后台日志如下:
其次,Apache会侦测到Tomcat2发生异常,将其余请求转交给其他节点,即交由Tomcat1处理!
继续刷新http://localhost/zlex当前页面,耐心等待几秒。你会发现,即便再次刷新页面,sessionID仍旧绑定在标识tomcat1服务器上。
然后,我们恢复Tomcat2服务,Tomcat1会马上侦测到Tomcat2已经恢复正常:
最后,我们再次刷新当前页,Apache已经将请求分发给Tomcat2了,从后台日志可以看到session信息会很快被同步了!
如果带有tomcatX标识的sessionID有很多不便之处,可以关闭粘性会话。简单的讲,就是取消Tomcat中server.xml中<Engine/ >节点的jvmRoute属性!然后,重启tomcat、apache!
页面提交一个b=3!
左边为Tomcat1,右边为Tomcat2!SessionID一致!
除了上述几种方案外,还有Terracotta模式。一种第三方集群组件,2009年收购了缓存组件EhCache,可以结合Tomcat、JBoss等多种服务器,提供多种负载均衡、集群等功能实现,且当负载均衡节点超过8个时,仍然能够保持集群吞吐量的线性增长。
Eclipse插件地址:
http://download.terracotta.org/eclipse/update
下载地址:
http://www.terracotta.org/dl/oss-download-catalog
至此,Apache + Tomcat成功完成,征服Apache系列暂告一段落!
作为开博以来的第100帖,算是很成功了!
测试应用见附件!
相关内容:
征服 Apache + SSL
征服 Apache + SVN
征服 Apache + SVN + LDAP
征服 Apache + Tomcat
征服 Nginx
征服 Nginx + Tomcat
相关推荐
3. **Tomcat 5以上**: Apache Tomcat是一个开源的Servlet容器,用于部署Java Web应用。 4. **Eclipse 3.0**: 集成开发环境,支持Java和JavaScript开发,便于构建和调试Ajax应用。 **四、学习资源** 本资源可能包含...
8. 《Tomcat 权威指南》:做 Java Web 的一般都必须学习这个,为 Apache 的开源项目。 9. 《Head First Servlets & Jsp》:Servlet 和 Jsp 是 JavaEE 程序员必须要掌握好的。 10. 《Head First HTML与 CSS.XHTML 》...
内容概要:本文详细介绍了基于FPGA的四相八拍步进电机控制系统的开发过程。主要内容包括:1. 使用VHDL和Verilog编写LED显示屏驱动代码,用于显示角度、学号和姓名等信息;2. 实现步进电机的正反转控制,通过状态机管理相序变化;3. 开发加速减速控制模块,确保电机启动和停止时的平稳性;4. 设计调速功能,通过调节脉冲频率实现速度控制。此外,文中还讨论了调试过程中遇到的问题及其解决方案。 适合人群:对FPGA开发和步进电机控制感兴趣的电子工程师、嵌入式系统开发者以及相关专业的学生。 使用场景及目标:适用于需要高精度运动控制的应用场合,如工业自动化、机器人技术和精密仪器等领域。目标是帮助读者掌握FPGA控制步进电机的基本原理和技术细节。 其他说明:文中提供了详细的代码片段和调试经验分享,有助于读者更好地理解和应用所学知识。同时,作者还提到了一些实用技巧,如通过PWM调节实现多级变速,以及如何避免步进电机的共振问题。
内容概要:本文详细介绍了基于Android Studio开发的日历备忘录记事本项目,涵盖日历查看、添加备忘录、闹钟提醒和删除备忘录等功能。项目使用SQLite数据库进行数据存储,通过CalendarView、EditText、Button等控件实现用户交互,并利用AlarmManager和PendingIntent实现闹钟提醒功能。此外,项目还包括数据库的设计与管理,如创建DatabaseHelper类来管理数据库操作,确保数据的安全性和完整性。文章还探讨了一些常见的开发技巧和注意事项,如时间戳的使用、手势监听的实现等。 适用人群:适用于初学者和有一定经验的Android开发者,尤其是希望深入了解Android开发基础知识和技术细节的人群。 使用场景及目标:该项目旨在帮助开发者掌握Android开发的基本技能,包括UI设计、数据库操作、闹钟提醒机制等。通过实际项目练习,开发者能够更好地理解和应用这些技术,提升自己的开发能力。 其他说明:文中提到一些进阶任务,如用Room替换SQLite、增加分类标签、实现云端同步等,鼓励开发者进一步扩展和优化项目。同时,项目源码公开,便于学习和参考。
内容概要:本文档详细介绍了一个基于SVM(支持向量机)和Adaboost集成学习的时间序列预测项目。该项目旨在通过结合这两种强大算法,提升时间序列预测的准确性和稳定性。文档涵盖了项目的背景、目标、挑战及其解决方案,重点介绍了模型架构、数据预处理、特征选择、SVM训练、Adaboost集成、预测与误差修正等环节。此外,文档还探讨了模型在金融市场、气象、能源需求、交通流量和医疗健康等多个领域的应用潜力,并提出了未来改进的方向,如引入深度学习、多任务学习、联邦学习等先进技术。 适合人群:具备一定机器学习基础的研究人员和工程师,特别是那些从事时间序列预测工作的专业人士。 使用场景及目标:①用于金融市场、气象、能源需求、交通流量和医疗健康等领域的复杂时间序列数据预测;②通过结合SVM和Adaboost,提升预测模型的准确性和稳定性;③处理噪声数据,降低计算复杂度,提高模型的泛化能力和实时预测能力。 其他说明:文档不仅提供了详细的理论解释,还附有完整的Matlab代码示例和GUI设计指导,帮助读者理解和实践。此外,文档还讨论了模型的部署与应用,包括系统架构设计、实时数据流处理、可视化界面、GPU加速推理等方面的技术细节。
#游戏之追逐奶酪123
内容概要:本文详细介绍了威纶通触摸屏配方管理系统的实现方法及其应用场景。首先,文章讲解了配方管理的基本概念和技术背景,强调了配方管理在工业自动化中的重要性。接着,通过具体的宏程序代码示例,展示了如何实现配方的保存、加载以及安全校验等功能。文中还提到配方数据结构的设计,如使用寄存器地址偏移来确保数据不冲突,并通过CSV文件格式方便地管理和维护配方数据。此外,文章深入探讨了UI设计方面的内容,包括动态图层技术和按钮交互效果的应用,使得用户界面更加友好和直观。最后,作者分享了一些实际项目中的经验和技巧,如文件操作的异常处理和宏指令调试方法。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是对触摸屏配方管理系统感兴趣的读者。 使用场景及目标:适用于需要频繁切换设备参数的生产环境,如食品加工、注塑成型等行业。通过使用威纶通触摸屏配方管理系统,可以提高工作效率,减少人为错误,同时简化设备调试和维护流程。 其他说明:附带的工具包提供了完整的宏指令注释版、图库资源和调试工具,帮助用户更好地理解和应用该系统。
张彩明-图形学简明教程 PPT课件
计算机术语.pdf
内容概要:本文详细介绍了利用改进粒子群算法(IPSO)进行微电网多目标优化调度的方法和技术。首先指出了传统粒子群算法(PSO)存在的局限性,如初始化随机性和易陷入局部最优等问题。接着提出了多种改进措施,包括混沌映射初始化、动态权重调整、自适应变异以及引入帕累托前沿机制等。文中通过具体的代码实例展示了这些改进的具体实现,并通过实验验证了改进后的算法在处理微电网优化调度问题时的有效性,尤其是在应对风光发电不确定性方面表现突出。此外,文章还讨论了实际应用场景中的约束处理方法,如功率平衡约束的修复策略,确保理论与实践相结合。 适合人群:对智能优化算法及其在电力系统特别是微电网中的应用感兴趣的科研人员、工程师及研究生。 使用场景及目标:适用于需要对微电网进行多目标优化调度的研究和工程项目,旨在提高微电网运行效率,降低成本并减少环境污染。通过学习本文提供的改进算法和技术手段,能够更好地理解和掌握如何针对特定业务场景定制化地改进经典优化算法。 其他说明:文章不仅提供了详细的理论分析和算法改进思路,还包括了大量的代码片段和实验结果,有助于读者深入理解并快速应用于实际项目中。
内容概要:本文详细介绍了基于西门子S7-1200 PLC和组态王的7车位3x3升降横移立体车库控制系统的设计与实现。主要内容涵盖IO分配、梯形图程序、接线图、组态画面设计以及安全防护逻辑等方面。文中强调了硬件互锁、软件互锁、模块化编程、精确控制和平移控制等关键技术点,并分享了一些调试经验和注意事项。此外,还讨论了光电传感器误触发、急停按钮处理、故障记录等实际应用中的挑战及其解决方案。 适合人群:从事工业自动化领域的工程师和技术人员,特别是熟悉PLC编程和组态软件使用的专业人员。 使用场景及目标:适用于需要设计和实施立体车库控制系统的工程项目。目标是帮助读者掌握S7-1200 PLC与组态王的具体应用方法,提高系统可靠性和安全性。 其他说明:文中提供了详细的代码片段和配置示例,有助于读者更好地理解和实践相关技术。同时,作者分享了许多宝贵的实战经验,对于初学者和有一定经验的技术人员都非常有价值。
内容概要:本文详细介绍了线性表及其顺序表示的概念、原理和操作。线性表作为一种基础数据结构,通过顺序表示将元素按顺序存储在连续的内存空间中。文中解释了顺序表示的定义与原理,探讨了顺序表与数组的关系,并详细描述了顺序表的基本操作,包括初始化、插入、删除和查找。此外,文章分析了顺序表的优点和局限性,并讨论了其在数据库索引、图像处理和嵌入式系统中的实际应用。最后,对比了顺序表和链表的性能特点,帮助读者根据具体需求选择合适的数据结构。 适合人群:计算机科学专业的学生、软件开发人员以及对数据结构感兴趣的自学者。 使用场景及目标:①理解线性表顺序表示的原理和实现;②掌握顺序表的基本操作及其时间复杂度;③了解顺序表在实际应用中的优势和局限性;④学会根据应用场景选择合适的数据结构。 其他说明:本文不仅提供了理论知识,还附带了具体的代码实现,有助于读者更好地理解和实践线性表的相关概念和技术。
计算机数学1 -5 重言式与蕴含式.pdf
内容概要:本文详细介绍了风电永磁直驱发电并网系统的构成及其关键控制部分。首先探讨了真实的风速模型构建方法,利用MATLAB生成带有随机扰动和突风成分的风速曲线,用于模拟自然界的风况。接着深入解析了永磁电机的转速控制机制,特别是最大功率点跟踪(MPPT)算法的具体实现方式,以及如何通过PI控制器调节电磁转矩。随后讨论了并网过程中LCL滤波器的设计要点,确保谐波失真小于3%的同时保持系统稳定性。此外,还涉及到了网侧变流器的锁相环(PLL)设计,增强了其在电网电压跌落情况下的快速跟踪能力。最后讲述了整套系统联调时遇到的问题及解决方案,如协同惯量控制策略应对电网扰动等。 适合人群:从事风力发电研究的技术人员、高校相关专业师生、对新能源发电感兴趣的工程爱好者。 使用场景及目标:适用于希望深入了解永磁直驱风力发电系统的工作原理和技术细节的人群。目标是掌握从风速建模到最终并网控制的完整流程,能够独立进行系统仿真和优化。 其他说明:文中提供了大量具体的代码示例,涵盖MATLAB、Python、C等多种编程语言,有助于读者更好地理解和实践所介绍的内容。
资源内项目源码是均来自个人的课程设计、毕业设计或者具体项目,代码都测试ok,包含核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,答辩评审绝对信服的,拿来就能用。放心下载使用!源码、数据集、部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.dataset.txt文件,仅供学习参考, 切勿用于商业用途。
本程序使用于:思迅软件、科脉软件、百威软件、泰格软件、嬴通软件等。 安装配置完连接参数后,用默认管理员账号:辞郁,密码:ciyu登录,主界面左上角,双击输入管理员辞郁密码:ciyu 进入设计模式。下载内容中有详细示例截图。 辞郁POP打印工具是一款专业的打印解决方案,主要针对零售行业的商品POP促销单。它支持多种零售软件系统,包括但不限于思迅软件、科脉软件、百威软件、泰格软件和嬴通软件。这种工具的出现极大地便利了零售业者在商品推广和营销方面的操作,通过快速生成并打印商品促销单,帮助商家更好地吸引顾客、提升销售业绩。
内容概要:本文详细介绍了利用蒙特卡洛法对电动汽车负荷进行预测的方法。首先解释了基本原理,即通过建立电动汽车出行时间、行驶里程和充电时间的概率模型,采用蒙特卡洛法进行抽样并累加每辆车的充电负荷,从而得出负荷预测结果。随后展示了具体的MATLAB代码实现,包括初始化参数设置、蒙特卡洛仿真循环、结果处理和可视化。代码中涉及到随机数生成、概率分布、数组操作等关键技术点。通过对不同类型的电动汽车(如私家车和出租车)进行建模,模拟了它们的充电行为,并分析了充电负荷的时间分布特点。最后讨论了模型的可扩展性和改进方向,如引入智能充电策略等。 适合人群:对电力系统、电动汽车技术和蒙特卡洛仿真方法感兴趣的科研人员、工程师和技术爱好者。 使用场景及目标:适用于研究和评估电动汽车对电网的影响,帮助规划和设计充电基础设施,确保电网稳定运行。同时,也为进一步优化充电策略提供了理论支持。 其他说明:文中提供的MATLAB代码可以作为学习和研究的基础,用户可以根据具体情况进行修改和完善。此外,还提到了一些常见的编程技巧和注意事项,有助于提高代码质量和效率。
内容概要:本文详细介绍了如何利用Python进行电网故障仿真,重点在于不同类型故障(单相接地、相间短路、相间短路接地)下的序分量分析。文中首先准备了必要的工具包,定义了系统参数,并通过具体的代码实例展示了如何计算和可视化各种故障状态下的正序、负序和零序分量。此外,还讨论了不同类型的故障对序分量的具体影响及其在继电保护中的应用。通过这些仿真,能够更好地理解和预测保护装置的动作特性。 适合人群:从事电力系统分析、继电保护设计以及相关领域的工程师和技术人员。 使用场景及目标:适用于研究和开发电力系统的故障检测和保护机制,帮助工程师们优化继电保护装置的参数设置,提高电力系统的稳定性和可靠性。 其他说明:文章强调了仿真过程中需要注意的关键点,如接地电阻设置、变压器接线方式、线路参数单位等,确保仿真结果的准确性。同时,提供了多个代码片段作为参考,便于读者快速上手实践。
6G中基于量子计算的路由 该代码使用量子退火来优化6G网络中的路径选择 基于图的网络,在考虑干扰和拥塞的同时,根据最短路径优化路由路径。