4.3 tomcat负载均衡与memcached

tomcat负载均衡


  • tomcat Connector 组件

tomcat 一般只提供动态资源处理功能,而静态资源的请求则交给独立的 apache/httpd 或 nginx 来处理。但 tomcat 与外界通信的唯一组件是连接器 Connector,因此动态请求要转发给 tomcat 时,需要和 Connector 通信。Connector 与外界通信的协议有两种:http/ajp

    语法:<Connector port="端口号" protocol="协议" [connectionTimeout="超时时间(毫秒)"] [redirectPort="重定向端口"]>

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

client→Proxy→Nginx→tomcat

在这种调度方案中,当客户端访问一个URL时,会将请求通过 DNS 解析发送至发布在公网上的反向代理服务器,反代可以是由 Nginx 也可以由 HAProxy 提供。反代收到请求后根据调度算法将报文分发至后端的 webserver 上,webserver 收到报文由 Nginx 分析报文,当访问静态资源时便由自己响应请求,若请求的是应用程序时则反向代理至本地的 tomcat,由 tomcat 运行后将结果响应给 Nginx 并发送至前段反向代理服务器,由前段代理服务器响应给客户端。

    配置后端 WebServer 服务器

修改 tomcat 主配置文件,和单独提供服务一样,并无二样

  <Service name="Catalina">

    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

    <Engine name="Catalina" defaultHost="web1.test.com">

      <Realm className="org.apache.catalina.realm.LockOutRealm">

        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="web1.test.com"  appBase="/data/test/web1"
            unpackWARs="true" autoDeploy="true">

        <Context path="/context" docBase="/data/context/testapp" reloadable="" />

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs/test/web1"
               prefix="web1_access_log" suffix=".log"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>

修改本地 Nginx 配置文件,当访问以.jsp为后缀的文件时反向代理至本地的8080端口

server {
	listen 80 default_server;
	server_name static.web.com;
	#root /data/static;
	
	location / {
		root /data/static;
	}

	location ~* \.jsp$ {
		proxy_pass http://127.0.0.1:8080;
	}
}

配置前端反向代理服务器

#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend  main
    bind *:80
    bind *:443 ssl crt /etc/haproxy/ssl.pem
    mode http
    default_backend      web_server1

#---------------------------------------------------------------------
# backend server
#---------------------------------------------------------------------
backend web_server1
    balance     roundrobin
    option httpchk GET /index.jsp HTTP/1.0

    server      web1 192.168.30.74:80    check
    server      web2 192.168.30.174:80   check

client→httpd→tomcat

在这种调度方案中,当客户端发起请求时,通过的前端的调度器分析请求报文,将访问应用程序的请求分发给 httpd,由 httpd 充当反向代理服务器,将请求根据调度算法发送至后端的 tomcat 服务器上。

  • 使用 proxy_http_module 模块通过 http 协议代理

创建 httpd 的配置文件,设置反向代理功能

[root@CentOS75 certs]# cat /etc/httpd/conf.d/httpd-tomcat.conf
<proxy balancer://tomcatsvr>   #定义后端服务器组
	BalancerMember http://192.168.30.74:8080 loadfactor=2
	BalancerMember http://192.168.30.174:8080 status=I
	ProxySet lbmethod=byrequests                 #调度算法
</Proxy>

<VirtualHost *:80>                               #定义虚拟主机和监听端口
	ServerName      web.test.com                 #定义虚拟主机名
	ProxyRequests Off                            #关闭正向代理
	ProxyVia        On                           #在响应报文头部添加代理服务器主机名
	ProxyPreserveHost On                         #保留请求报文中的主机名
	<Proxy *>
		Require all granted                      #声明代理权限
	</Proxy>
	ProxyPass / balancer://tomcatsvr/            #声明使用的后端服务器组
	ProxyPassReverse / balancer://tomcatsvr/    
	<Location />
		Require all granted                      #声明访问权限
	</Location>
</VirtualHost>
  • 使用 proxy_ajp_module 模块通过 ajp 协议代理

修改上面 httpd 的配置文件,设置使用 ajp 协议反向代理

<proxy balancer://tomcatsvr>
	BalancerMember ajp://192.168.30.74:8009    #服务器组中的主机应该使用ajp协议,并与后端的8009端口通信
	BalancerMember ajp://192.168.30.174:8009
	ProxySet lbmethod=byrequests
</Proxy>

<VirtualHost *:80>
	ServerName      web.test.com
	ProxyRequests Off
	ProxyVia        On
	ProxyPreserveHost On
	<Proxy *>
		Require all granted
	</Proxy>
	ProxyPass / balancer://tomcatsvr/
	ProxyPassReverse / balancer://tomcatsvr/
	<Location />
		Require all granted
	</Location>
</VirtualHost>

loadfactor  调整主机调度时的权重
status:
    D  禁用
    S  暂时禁用
    I  忽略健康状态监测,始终为存活
    H  备用服务器
    E  将其置为错误状态
    N  排干该服务器
ProxySet  设置调度选项
    lbmethod  指定调度算法
        bytraffic  根据服务器当前承载的流量进行调度
        bybusyness  根据服务器当前连接的会话数量调度
        byrequests  根据设置的权重轮询调度
    stickysession  声明cookie变量名

Header add Set-Cookie "CookieFlag=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED   #添加报文头部

<proxy balancer://tomcatsvr>
	BalancerMember ajp://192.168.30.74:8009 route=tomcatB
	BalancerMember ajp://192.168.30.174:8009 route=tomcatA   #定义cookie中的变量值
	ProxySet lbmethod=byrequests
	ProxySet stickysession=CookieFlag   #定义添加在cookie中的变量名
</Proxy>

<VirtualHost *:80>
	ServerName      web.test.com
	ProxyRequests Off
	ProxyVia        On
	ProxyPreserveHost On
	<Proxy *>
		Require all granted
	</Proxy>
	ProxyPass / balancer://tomcatsvr/
	ProxyPassReverse / balancer://tomcatsvr/
	<Location />
		Require all granted
	</Location>
</VirtualHost>
    <Engine name="Catalina" defaultHost="web1.test.com" jvmRoute="tomcatA">  #使用jvmRoute属性定义当前服务器的route标识

通过 chrome 访问,并查看响应报文头部,发现多次访问都调度至同一主机

会话粘性


  • tomcat cluster

由于tomcat 处理的事动态内容,当多个 tomcat 服务器构成集群时,必然要面临一个问题:会话绑定。在此之前,我们先了解 tomcat 是如何配置集群的。

tomcat 构成集群需要依靠 Cluster 组件的支持,该组件能够定义当前 tomcat 的“会话管理、多波通信、部署”等功能。需要配置在<Engine>或<Host>组建中。

        <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
                 channelSendOptions="8">   #发送消息的信道选项

          <Manager className="org.apache.catalina.ha.session.DeltaManager"  #使用Delta会话管理器
                   expireSessionsOnShutdown="false"  #当前节点关闭时,是否通知其他节点摧毁本节点上的所有会话
                   notifyListenersOnReplication="true"/>  #当会话属性变动时,是否通知会话管理器

          <Channel className="org.apache.catalina.tribes.group.GroupChannel">
            <Membership className="org.apache.catalina.tribes.membership.McastService"  #搜索集群中的成员变化
                        address="228.0.0.30"   #定义组播地址
                        port="45564"           #监听端口号
                        frequency="500"        #定义探测间隔,毫秒
                        dropTime="3000"/>      #失效判定时间
            <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver"  #监听其他节点传来的消息
                      address="192.169.30.74"  #监听的地址
                      port="4000"              #监听的端口,范围在4000-4100
                      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.ClusterSessionListener"/>
        </Cluster>

注意:在集群中请务必确保各节点之间的时间同步
           绑定的地址为auto时,会自动解析本地主机名,并解析得出的IP地址作为使用的地址
           同时当集群规模较大,请保证前端的负载均衡服务器已经配置粘性会话

配置应用程序的 web.xml,在其中添加 <distributable/> 元素

    <distributable/>

注意:应用程序的 web.xml 文件权限

通过前端调度器访问后端 tomcat 服务器上的应用程序,发现无论访问后端任何主机,当前会话并不会丢失

  • memcached

memcached原理

许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示。但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据库响应恶化、网站显示延迟等重大影响。

memcached是高性能的分布式内存缓存服务器。一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web用的速度、提高可扩展性。

memcached作为高速运行的分布式缓存服务器,具有以下的特点:

    协议简单
    基于libevent的事件处理
    内置内存存储方式 
    memcached不互相通信的分布式

为了提高性能,memcached 中保存的数据都存储在 memcached 内置的内存存储空间中。由于数据仅存在于内存中,因此重启 memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于 LRU(Least Recently Used) 算法自动删除不使用的缓存。

各个memcached不会互相通信以共享信息,而是通过使用智能客户端来选择本次访问的缓存存放在某一个节点上。

memcached安装与配置

memcached 程序因为过于简单,所以并没有常规的配置文件,而是存放在 /etc/sysconfig/memcached 中

[root@CentOS74 ~]# cat /etc/sysconfig/memcached 
PORT="11211"        #监听的端口号,UDP与TCP同时监听
USER="memcached"    #进程以谁的身份运行
MAXCONN="1024"      #最大的chunk大小
CACHESIZE="256"     #缓存容量
OPTIONS="-f 1.25"   #步进因子大小

也可以通过命令配置 memcached

    -m <num>:最大缓存容量,默认64M
    -c <num>:最大并发连接数量,默认1024
    -u <username>:以指定的用户身份来运行进程
    -l <ip_addr>:监听的IP地址,默认为本机所有地址
    -p <num>:监听的TCP端口,默认端口为11211
    -U <num>:监听的UDP端口,默认端口为11211
    -M:内存耗尽时,不执行LRU清理缓存,而是拒绝存入新的缓存项,直到有多余的空间可用时为止
    -f <factor>:增长因子;默认是1.25
    -t <threads>:启动的用于响应用户请求的线程数

启动 memcached 服务,观察服务监听的端口

[root@CentOS74 ~]# ss -nutl | grep 11211
udp    UNCONN     0      0         *:11211                 *:*                  
udp    UNCONN     0      0        :::11211                :::*                  
tcp    LISTEN     0      128       *:11211                 *:*                  
tcp    LISTEN     0      128      :::11211                :::*                  

此时便可以在主机上访问 memcached,并修改数据库中的数据了

执行增删改查操作

    语法:add | delete | replace | get 键名 [标识] [有效时间] [变量长度]

add first_key 1 0 17  #定义键属性,有效时间为0代表永不失效
this is memcached     #输入值
STORED                #成功添加

get first_key
VALUE first_key 1 17  #输出键的信息
this is memcached     #输出键的值
END

replace first_key 1 0 11  
hello world
STORED

get first_key
VALUE first_key 1 11
hello world
END

delete first_key    
DELETED
get first_key
END

flush all  清空数据库(危险!!!)

incr | decr 键名 [数值]  计数操作
需要定义初始值

incr count 1  #增加1
1             #键值为1
incr count 4  #增加4
5             #键值为5
incr count 8
13            #当键值增加到比原始键长度定义大时
get count
VALUE count 3 2  #键的长度自动增加
13
END

使用MSM对memcached进行会话管理

MSM 全称为 memcached session manager(memcached 会话管理器),是一个由 Java 语言编写的 tomcat 会话管理器,能够将会话保存在 memcached 或 Redis 中,用于高可用性,可伸缩和容错的Web应用程序。

MSW 为我们提供了4种序列化程序,详细可以查看 MSM 的 github 站点 MSM github站点

同时还需要下载必要的 .jar 库文件,以支持 MSM 的工作,并将它们存放在 tomcat 的库文件路径下

[root@CentOS74 ~]# tree MSM/
MSM/
├── classes   #MSM必须的库文件
│   ├── memcached-session-manager-2.3.0.jar
│   ├── memcached-session-manager-tc7-2.3.0.jar
│   └── spymemcached-2.12.3.jar
└── kryo      #自定义序列化程序的库文件
    ├── asm-6.2.jar
    ├── kryo-4.0.2.jar
    ├── kryo-serializers-0.42.jar
    ├── minlog-1.3.0.jar
    ├── msm-kryo-serializer-2.3.0.jar
    ├── objenesis-2.6.jar
    └── reflectasm-1.11.7.jar

2 directories, 10 files

修改 tomcat 的主配置文件 server.xml,添加新的 Context 组件

        <Context path="/" docBase="ROOT" reloadable"">

          <Manager  className = "de.javakaffee.web.msm.MemcachedBackupSessionManager"
                    memcachedNodes = "n1:192.168.30.74:11211,n2:192.168.30.174:11211"  #用节点标识:主机地址:监听端口来识别一个节点
                    failoverNodes = "n2"  #定义备份节点
                    requestUriIgnorePattern = ".* \. (ico|png|gif|jpg|css|js)$"  #不予会话管理的文件格式
                    transcoderFactoryClass = "de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory" 
          />
        </Context>

通过 chrome 访问前段调度器,查看访问结果发现提供页面的服务器虽然变化,但是会话与 memcached 节点却不会改变

停止 n1 上的 memcached 服务,模拟故障,并通过新的浏览器模拟新的客户端访问前端调度器,此时 n2 的 memcached 开始提供服务

注意:当 n1 节点宕机,访问时发现还是会显示 n1 节点的标识,是因为在 memcached 中的键名也同步给了 n2 节点,实际上此时已经是由 n2 节点的 memcached 提供服务了。 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值