最外层每一个server代表一个实例,一个server内部可以容纳多个service,但是service主要存在目的是实现
connector和engine建立关联关系,一个connector只能属于一个engine,但一个engine可以拥有多个connector,connector有点类似于对应的服务监听地址和端口的定义,但事实上connector本身还拥有一些此前其他讲过的服务中
所不具有的强大功能,比如最大并发连接数等等,都可以在一个连接器组件来实现,与其说是license,比如说是一个完整的
连接池管理器
engine是真正的容器类组件,
对于tomcat来讲,容器类组件就是能存放webapp,并得以解析以后响应结果给用户的组件有engine,host,context
还有一些能实现了嵌套类组件,如valve等
这些就是tomcat对应的核心组件,定义在server.xml主配置文件当中
后面又讲了tomcat如何能够实现被前端反代,因为对于tomcat而言,用户请求是由connector来处理的,比如并发链接请求,由connect定义的max_threads最大连接数来建立连接,
其实就是由java内部运行的线程来处理用户的链接请求,这种并发处理能力从根本上来讲,是非常有限的,且不说本身是java程序,建构方式来讲,性能也十分有限,因此一般不会让tomcat直接面向客户端的user agent而是用主机,或者用某个应用进行反代,这种反代的方式曾经讲过,有这么几种
第一种可以使用httpd反代,httpd进行反代时其实可以有两种方式与tomcat建立连接,一种使用httpd连接器,一种使用ajp连接器(at)
如果使用nginx反代,通常只有http连接器使用(nt)
如果单个tomcat不足以承载用户请求的时候,可能需要对它们做横向扩展。,要多加主机来实现,意味着前端应该有负载均衡器接收用户请求,将用户请求分发给后端主机,反代以后加负载均衡(在这种情况下,一般也不会让tomcat工作在一台主机上,仍然基于反代模式来处理用户请求,也就意味着每一个主机,前面可能是一个nginx,可以在7层缓存反代)
静态内容的图片应该发给缓存服务器,由缓存服务器反代给纯静态内容的web服务器,如nginx
对nginx来讲反代的动态内容,反代到tomcat主机之上,每一台tomcat主机上都有一个反代服务,而后反代用户请求至本地主机后端的tomcat实例,即便如此,也不会让tomcat直接,面向前端的负载均衡器
负载均衡器发来的并发连接数量也有可能是一个很大的负载,尤其在用户访问量教大的情形下,所以在单台服务器之上,反代服务器只反代当前用户请求至一台主机上的tomcat,也是必要的
其实这种组织可以称为nnt,nat
对站点而已,部署在动态站点或称为主站服务器上的应用,有可能不止是动态内容,随着网站要更新,还要一些如css,js,也会在动态服务器之上所构建,所以使用nginx或使用httpd反代,还有一个好处,静态内容还可以由前端的反代服务器,自己来处理,动态内容则由tomcat加载以后,先响应给前端代理服务器,再由代理服务器响应调度器,所以也可以极大减轻动态服务器的压力,对varnish这样的缓存服务器来讲,有一部分内容到后端的nginx有部分内容到主站服务器,
因为有一些css,js内容是由他们来负责处理和响应的,这样以后做灰度发布只需要操作这些主机就行,那些图片内容是无须做任何关心的
加入定义了某些网站静态内容可以缓存三天,刚刚有内容缓存上,网站发布了新版本,缓存当中的内容就需要人工来失效,(在varnish上说,可以使用ban和purge机制)
接入层,缓存层,业务层,向后就是存储层(mysql),web2.0时代并发较高,而对事务数据一致性要求不高的情况下,也会有nosql中的,著名高性能数据库服务器,redis
静态服务器也会有nginx服务器,后图片也是要存储在后端服务器上的,分布式文件系统
用户通过主站上传数据,一般传到后端服务器上,所以动态服务器需要跟各种不同类型的存储打交道,非结构化的,半结构化的,和结构化的,分布式文件系统一般存对象类的数据,或者称为非结构化数据,redis这种基于json格式,如果就可以的话,或者基于Kevin格式存储(半结构化数据)
到了mysql这,强一致,并支持事务功能,这种一般称为半结构化数据,
如果是多台动态服务器,在反代时,就需要做会话保持,(本地有没有反代tomcat且不说,不是特别关键,主要看负载均衡器的调度时,需要不需要去保持用户会话,用户会话的保存方式有三种
1.session sticky会话粘性,(实现方式很多,如lvs能基于源地址hash做粘性,而7层代理,既能基于源地址hash,还能基于cookie追踪用户身份,因此这些可以做更加精细密度的粘性,即便如此,做粘性也有缺点(1.损害负载均衡效果,2.一旦某台服务器宕机了,总有一部分session是要丢失的,此时会遇到一个窘境,此类用户发出请求时是重新调度,还是不重新调度,重新调度会话丢失,不重新调度服务器还没有修复(这种情况并不少见,只要不是互联网一类企业,都会经常出现一些故障)
2.可以将后面的tomcat集群构建成一个会话集群,session replication cluster,session会话集群
,一般2个三个 (多了就不会用这种方式了),为了避免session sticky遇到的问题,没法调度,只能绑定,再比如主机宕机,用户重新调度有问题,不重新调度也有问题,这种情况下,可以把米的三台主机,先不考虑前端的负载均衡器,只需要把这三台主机构建成一个集群,这个集群他们可以通过某多播地址,类似keepalived,基于所谓的多播地址,进行通讯,通讯的时候,能够基于一些判断标准,来判断大家是不是属于同一个cluster,如果同属一个cluster,收到来自前端调度服务器的请求之后,如果更新了用户会话,那么会把此会话通过多播地址同步给整个集群中的其他主机。
任何一个会话通过调度器调度到任何一个主机上的,这个主机会把会话多播,,下一次,这个用户在请求的时候,重新调度,无论调度到哪一台主机上,这个会话都在,
这种就叫session,replication cluster,tomca原生就支持这个clutser,我们可以配置其称为session replication
cluster,这种方式不适用较大应用的情形,因为主机太多的时候,并发访问量很多的时候,每个主机所承载的更新速度都很快,多播信道充斥着各种多播信息,每个主机也会收到与集群相关的各种事务,所以服务器性能会严重消耗,但有个好处,用户的请求不用被粘性了,调度到任何主机上都没有任何问题,任何主机宕机了,用户只要一刷新就调度到其他主机上了,没有任何问题。
(有没有方法既有这样的好处,又不会主机太多性能差的
第三钟)
3.找一个存储设备,把所有的会话信息存储在存储设备上,这个存储设备要求就是高性能,支持的事务能力,每秒支持的tps数量,需要非常高才可以,着就要取决于你的并发数量有多大,(redis,memcached,这样的键值存储,大致上提供的数据存取能力,每秒50-100万次,非常强大,redis是一种存储,memcached也是一种存储,如果放单点,这台服务器宕机会导致所有的会话均不可用,需要做冗余)
**
redis自身是具有冗余能力的,完整意义上的,storage,data store(redis也是在内存中,但是自己会基于两种方式,
任何一种都能实现数据存储在磁盘上,服务器宕机,重启以后,数据依然存在,这是redis的优势)
memcache 就是data cache(只是缓存,不持久数据,所有的数据都只在内存中,服务器宕机或重启,数据都会丢失)**
所以到底使用memcached还是redis,自行选择
相对来讲,memecached比redis支持的数据类型更多,仅仅做会话缓存来讲,memcached也足够用了一台服务有问题,可以存两台,memcached自身不支持集群机制,要想做冗余,需要基于双显模式,自行存储到两个服务器中,而对redis而言,不必如此,只要写到一台服务器中,会自己同步到其他从服务器中,一旦主服务器宕机,还可以让从服务器备用的冗余当主服务器,这个主从跟dns主从很相似
mysql,对于运维来讲,最重要的就是主从复制
第一种 session replication cluster、toncat自带的,可以直接使用,上一节课已经构建出了,nginx或httpd,的反代集群,wrr或者wlc
因此前面使用httpd调度或者nginx调度无关紧要,haproxy和nginx,推荐使用nginx
java程序启动慢一点,先要启动虚拟机,再要导入程序
n1启动nginx,n2,n3照常启动
默认可以rr算法
严格来讲这些事都需要实现的,调度因该调度到本机的nginx,然后再反代给tomcat
已经可以被访问到了
访问到之前的集群状态,轮询状态
轮询的会话,即使两次都是A,会话也会改变,被认为是不同用户,为了不让session发生改变,就需要去配置集群 了
要想让tomcat配置成集群,再官方文档中有说明
tomcat内部有个组建就叫cluster,意味着有个类叫cluster,这个类有子类来定义集群的很多组建
可以放在egine上对engine所有的host都有效
也可以放在某个host当中,针对当前host的所有context都有效,如果要context的中就只对当前context应用时有效的,
一般而言是放到host当中。
作为集群而言,每一个节点都需要配置,所以你的集群时间要也严格同步
1.会基于多播方式,通过228.0.0.4的地址进行通信
2.多播地址所使用的端口是45564,监听再同一个端口上的,就能成为同一个集群的成员,没有任何认证功能(只要是再228.0.0。4的45564端口上就是同一个集群,所以是用端口来判定是否是集群成员的
(keepalived是用认证来判定是否是成员的)
3.使用什么方式来发送广播信息)
4.每一个集群成员都应该接受集群里的任何多播信息,所以自己能够接受就需要监听在一个套接字上,端口有效范围是4000-4100
5.就需要定义侦听器
6.当tcp链接发生错误时如何能判断出来,如果messagedispash发送过来后,在内部如何解析,作为我们简单配置来讲,都无需关心,只需要把整个配置贴进去
开始到结束就也是一个cluster组建
**内部嵌套的还有一些组建
manager,channel,valve,deployer,clusterlistner监听器
**
作为一个应用程序服务器tomcat,是需要维持用户会话的,那么用户会话来了,跳转到哪里,所以tomcat定义了会话该如何保存,默认使用简单的本地会话管理器,而且是一个持久会话管理器,session manager,默认会话都在内存中创建,随后保存在磁盘上,免得tomcat重启以后,会话丢失,所以所有的会话都保存在磁盘上,
这种会话管理器叫持久会话管理器
不使用持久会话管理器,
第二种。所有会话都在内存中
还有第三种会话管理器,delta 每一个会话,本地不仅保存,还有通过多播传给其他主机
第四种,bacup会话管理器(所以tomcat主机节点很多的时候,万一一个节点挂了,所有会话都回丢失的),
假如有4个节点,可以实现两两备用
A把B当备用,B也当A备用,A的会话传给B,B的会话传给A,但是不向CD传
(把4个如果都放在一个集群,就回过大造成性能低,避免这种,22一组使得任何一组宕机,会话信息不至于丢失的)
CD也是一个小会话集群
前端调度服务器也使绑定调度,只不过调度的使绑定的一组主机,依然有损负载均衡效果
这种放式并不常用,了解下即可
其实还有第5种会话管理器,把会话放在web存储上
manager就是指明有哪一个会话管理器的,deltamanager,说白了就是使用session replication cluster信道来传递会话的,
在主机关机以后是否过期,expireSessionsOnShutdown=“false”
notifyListenersOnReplication=“true”,会话传送过去后,要触发,告诉对方保存还是什么
notifyListenersOnReplication=“true”,会话传送过去后,要触发,告诉对方保存还是什么,这两个listener就是做这个事情的,jvm JvmRouteSessionIDBinderListener,能够实现用户调度以后,带有jvmroute信息的,可以基于这种方式绑定,不过做了集群 以后很少绑定了
ClusterSessionListener
cluster内部通告时,要不要接受下来立即处理,主要式监测某个事件发生以后的采取后面动作的
channel
**channel式一个很重要的组建,是用来定义信道的,大家之所以能够成为成员主要靠channel来定义的
定义第一个组件membership (为什么是同一个集群成员,首先要监听同一个地址mcastservice
地址
端口
frequency=“500” 每隔多长时间发送一次心跳探测 ms毫秒,0.5秒
dropTime=“3000” 如果3000ms都没收到心跳,就认为宕机
) **
sender 自己怎么传ReplicationTransmitter 复制传送器
PooledParallelSender 基于轮循机制的,并发发送器
receiver 自己怎么收 transport.nio.NioReceiver
nio可以理解为java内部可以高并发异步处理用户请求的一个逻辑
接收信息,就需要监听在哪个端口,地址
auto 自动会去判断哪个是集群地址(有可能会判断错误,尤其是主机端口过多时,有必要可以手动指定一个地址)
4000接收对应信息端口
autoBind=“100” 每隔多长时间自动绑定一次
selectorTimeout=“5000” 挑选器的超时时间
maxThreads=“6” 最大并发连接数,取决于你的成员节点有多少个,成员节点有7个,那么其他节点就有6个,这六个主机可能随时都在发事务信息,启动6个线程各自处理独立一个主机的信息,节点不多时,6个够了
节点过多是,数值调整大
Interceptor
<Interceptor ,探测这个会话集群中,是不是发生tcp传输错误
deploy
deploy部署,一旦在集群中某单个节点上部署了新版应用程序的时候,要不要自动的通过多播集群,复制给其他节点
内部的部署器来实现内部的自动部署功能
tempDir="/tmp/war-temp/" 临时目录是哪里
deployDir="/tmp/war-deploy/" 临时用来做部署的目录是哪里
watchDir="/tmp/war-listen/" 监听在哪个目录
watchEnabled=“false”/>
一般不依赖于这种方式,一般都是灰度发布
valve过滤器
只需要把这段配置复制到后端集群上的host或者engine当中,并按需修改里面的某些属性,基本上就能达到目的了
并不是放在host中,host所有应用都能使用集群会话了,而是任何一个向使用集群会话的应用程序得再web。xml或者context。xml,添加一个distributable元素才可以
如果要使用 mod_jk模块,还需要为每一个后端tomcat的engine加一个属性,jvmRoute=“node01” >标识
但是一般mod_jk一般每人用了
现在就可以去配置了
到n2 tomcat编辑server.xml
就在原来的host内部定义即可
<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="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
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=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener">
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener">
</Cluster>
复制到host中间
修改下多播地址
其他的就先不修改,保存退出
n3主机也一样
需要把多播地址改成集群中的地址
现在想给test做分布式会话,分布式会话集群
需要给test配置一个web.xml文件,并在找个文件中添加<distributable/ 属性element,意思就是把他们做分布式会话
去复制一个配置文件到它的WEB-INF目录中
找到配置段开始的地方
在其内部找一个位置添加一项 <distributable/即可,自封装的标签,另外一个节点也这么配置即可
也可以把文件复制过去即可
现在重启tomcat,不过很有可能出错,先打开一个窗口监控日志信息
产生语法错误信息了
没有element type
这两个少了斜线
再启动一次
再查看日志
重新监听下
改成restart启动
还有问题
多看几行日志
去尝试绑定172.16.0.7:4099的服务的时候失败
这个就是绑定地址的问题了,本地虽然是192.168.0.1,但是探测出来可能是172.16。0.7
再去打开server.xml,找到address=auto改成自己的地址
继续监控日志
地址没问题,但是没有支持多播机制
其实支持多播,但是地址是临时配置的
nmtui修改下,,手动把地址改成固定格式的配置
重启以后应该是固定地址了
继续监听日志
不报错,成功了,动态地址认为式不支持多播的
另外一个节点可以直接进行配置了
首先nmtui改地址
编辑配置文件
加上斜线,地址先不改,查看是否能识别
先监控一下日志
错误在前面
依然式绑定地址失败
它的地址是由反解得到的,n3 是172。16。0.8
修改hosts文件试试
再去监听日志
就没有问题了,auto可以不用更改,不过会尝试反解地址
已经完成找个集群了,
现在调度器依然式负载均衡调度
刷新一下session是否改变
切换到tomcatB主机了,但是会话没变
Tomcat Session Replication Cluster:
(1) 配置启用集群,将下列配置放置于或中;
<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="228.0.0.4"
port="45564"
frequency="500"
dropTime="3000"/>
<Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto"
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=""/>
<Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/>
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/"
deployDir="/tmp/war-deploy/"
watchDir="/tmp/war-listen/"
watchEnabled="false"/>
<ClusterListener className="org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener"/>
<ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
</Cluster>
确保Engine的jvmRoute属性配置正确。
(2) 配置webapps
编辑WEB-INF/web.xml,添加<distributable/>元素;
注意:CentOS 7上的tomcat自带的文档中的配置示例有语法错误;
<ClusterListener className=“org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener”/
<ClusterListener className=“org.apache.catalina.ha.session.ClusterSessionListener”/
绑定的地址为auto时,会自动解析本地主机名,并解析得出的IP地址作为使用的地址;
既然式负载均衡调度,很显然用哪种调度器,对用户来讲都每什么影响,刚才是用nginx调度,换成httpd调度,应该依然每什么问题,把之前的会话绑定注释掉
刷新一下session是否改变
怎么去使用httpd的第三个模块,mod_jk,只是个示例,了解下即可,要想使用httpd第三方模块,一般只能使用编译安装光有devel包还不够可能还需要gcc,才能安装第三方模块
告诉你如何安装
native下是mod_jk的源码
。/configure --help查看第三方模块如何安装
指明httpd 的apxs文件在哪里即可
这个程序就为了安装第三方模块所用到的一个对接接口,是把第三方模块进来,编译成为httpd的模块的
所以编译时只要–with-apxs这个文件路径在哪里即可,其他的选项要不要做看你的需要
手动把这个修改权限
有了这个模块可以配置mod_jk来方向代理用户请求
这个模块是不会自动被装进来的
使用loadmodule加载模块,模块名很诡异
现在就能装载使用了
如果要基于mod_jk来实现ajp协议反代的话,看下官方文档
、
这就是如何去编译安装httpd第三方模块
将来如何把tomcat 配置成replication cluster,但是这种方式不是很有用
下面配置成web存储,把所有的tomcatsession都存储在存储服务器上,memcached没有冗余能力
tomcat有第三方模块可以解决这个问题(第三类类库的类)