實現tomcat及Memcached、redis緩存服務器session共享


NoSQL

NoSQL是對非SQL、非傳統關系型數據庫的統稱。

NoSQL一詞誕生於1998年,2009年這個詞匯被再次提出指非關系型、分布式、不提供ACID的數據庫設計模式。

隨着互聯網時代的到來,數據爆發式增長,數據庫技術發展日新月異,要適應新的業務需求。

隨着移動互聯網、物聯網的到來,大數據的技術中NoSQL也同樣重要。

https://db-engines.com/en/ranking

分類

Key-value Store

redis、memcached

Document Store

mongodb、CouchDB

Column Store列存數據庫,Column-Oriented DB

HBase、Cassandra

Graph DB

Neo4j

Time Series 時序數據庫

InfluxDB

Memcached不支持集群,只支持字符串類型、字節流,不支持持久化,不支持buffer緩存,而Redis支持字符串、源地址hash等類型,支持buffer緩存,且支持主從復制、集群、支持持久化等  

Memcached只支持能序列化的數據類型,不支持持久化,基於Key-Value的內存緩存系統。

內存分配機制

應用程序運行需要使用內存存儲數據,但對於一個緩存系統來說,申請內存、釋放內存將十分頻繁,非常容易導致大量內存碎片,最后導致無連續可用內存可用。

(1)Memcached采用了Slab Allocator機制來分配、管理內存。

(2)Page:分配給Slab的內存空間,默認為1MB,分配后就得到一個Slab。Slab分配之后內存按照固定字節大小等分成chunk。

(3)Chunk:用於緩存記錄kv值的內存空間。Memcached會根據數據大小選擇存到哪一個chunk中,假設chunk有128bytes、64bytes,數據只有100bytes存儲在128bytes中,存在些浪費。

        Chunk最大就是Page的大小,即一個Page中就一個Chunk

(5)Slab Class:Slab按照大小分組,就組成不同的Slab Class

 

如果有100bytes要存,那么Memcached會選擇上圖中Slab Class 2存儲,因為它是120bytes的Chunk。

Slab之間的差異可以使用Growth Factor控制,默認1.25。

懶過期Lazy Expiration

memcached不會監視數據是否過期,而是在取數據時才看是否過期,過期的把數據有效期限標識為0,並不清除該數據。以后可以覆蓋該位置存儲其它數據。

LRU

當內存不足時,memcached會使用LRU(Least Recently Used)機制來查找可用空間,分配給新紀錄使用。

集群

Memcached集群,稱為基於客戶端的分布式集群。

Memcached集群內部並不互相通信,一切都需要客戶端連接到Memcached服務器后自行組織這些節點,並決定數據存儲的節點。

memcached選項:

修改memcached運行參數,可以使用下面的選項修改/etc/sysconfig/memcached文件

-u username memcached運行的用戶身份,必須普通用戶
-p 綁定的端口,默認11211
-m num 最大內存,單位MB,默認64MB
-c num 最大連接數,缺省1024
-d 守護進程方式運行
-f 增長因子Growth Factor,默認1.25
-v 詳細信息,-vv能看到詳細信息
-M 內存耗盡,不許LRU
-U 設置UDP監聽端口,0表示禁用UDP

實戰一:基於session共享存儲實現LAMT的會話保持(sticky模式生產中常用)

msm

msm(memcached session manager)提供將Tomcat的session保持到memcached或redis的程序,可以實現高可用。

目前項目托管在Github:https://github.com/magro/memcached-session-manager

支持Tomcat的6.x、7.x、8.x、9.x。

Tomcat的Session管理類,Tomcat版本不同

memcached-session-manager-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar

Session數據的序列化、反序列化類

官方推薦kyro
在webapp中WEB-INF/lib/下

驅動類

memcached(spymemcached.jar)
Redis(jedis.jar) # redis的jar包

官網下載依賴的jar包:https://github.com/magro/memcached-session-manager/wiki/SetupAndConfiguration

將spymemcached.jar、memcached-session-manage、kyro相關的jar文件都放到Tomcat的lib目錄中去,這個目錄是$CATALINA_HOME/lib/ ,對應本次安裝就是/usr/local/tomcat/lib。

asm-5.2.jar
kryo-3.0.3.jar
kryo-serializers-0.45.jar
memcached-session-manager-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
minlog-1.3.1.jar
msm-kryo-serializer-2.3.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
spymemcached-2.12.3.jar
jedis-3.0.0.jar  # redis相關的jar包

sticky模式  

1、當請求結束時Tomcat的session會送給memcached備份。即Tomcat session為主session,memcached session為備session,使用memcached相當於備份了一份Session。

2、查詢Session時Tomcat會優先使用自己內存的Session,Tomcat通過jvmRoute發現不是自己的Session,便從memcached中找到該Session,更新本機Session,請求完成后更新memcached。

<t1> <t2>
 . \ / .
  . X .
 . / \ .
<m1> <m2>

t1和m1部署在一台主機上,t2和m2部署在同一台。

開始部署session共享會話保持

1、在t0和t1安裝memcached服務

 #yum install memcached  -y

2、修改t0和t1的配置文件,需要監聽其他地址的IP地址,否則只會監聽本地的IP地址,內存可以設置為1024,最大連接設置為2048

[root@centos-7 yum.repos.d]# cat /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="2048"  #修改最大連接數
CACHESIZE="1024"  # 修改內存大小
OPTIONS=""

3、啟動memcached服務,監聽的是11211端口

# systemctl start memcached

4、將依賴的包在官網下載下來並導入到/usr/local/tomcat/lib目錄下:

asm-5.2.jar
kryo-3.0.3.jar
kryo-serializers-0.45.jar
memcached-session-manager-2.3.2.jar
memcached-session-manager-tc8-2.3.2.jar
minlog-1.3.1.jar
msm-kryo-serializer-2.3.2.jar
objenesis-2.6.jar
reflectasm-1.11.9.jar
spymemcached-2.12.3.jar
jedis-3.0.0.jar

5、修改tomcat服務的配置文件

特別注意,t0配置中為failoverNodes="n1(memcached1)", t1(tomcat1)配置為failoverNodes="n2(memcached2)"  

failoverNodes故障轉移節點,n1是備用節點,n2是主存儲節點。另一台Tomcat將n1改為n2,其主節點是n1,備用節點是n2。

修改t0的配置文件

[root@mysql1 lib]# vim /usr/local/tomcat/conf/context.xml 

    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
        memcachedNodes="n1:192.168.7.100:11211,n2:192.168.7.101:11211"
        failoverNodes="n1"  #改為n1時,n1為備用節點,優先使用n2的主機節點
        requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
        transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
        />

修改t1的配置文件

[root@openstack-2 lib]# vim /usr/local/tomcat/conf/context.xml 

    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
        memcachedNodes="n1:192.168.7.100:11211,n2:192.168.7.101:11211"
        failoverNodes="n2" #改為n2時,優先使用n1的主節點,n2為備用節點。 
        requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
        transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
        />

6、修改tomcat(0和1)的主配置文件

#vim  /usr/local/tomcat/conf/server.xml
 <Engine name="Catalina" defaultHost="t0.baidu.com" jvmRoute="Tomcat1">  #加上后面的名稱,方便辨認是哪個主機
<Engine name="Catalina" defaultHost="t1.baidu.com" jvmRoute="Tomcat2">

7、修改兩個tomcat的server.xml配置文件

# vim /usr/local/tomcat/conf/server.xml 

<Engine name="Catalina" defaultHost="t1.baidu.com">
 </Host>
        <Host name="t1.baidu.com" appBase="/data/webapps" autoDeploy="true" >
 
      </Host>
    </Engine>

8、創建t0和t1的測試頁面

# vim  /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>lbjsptest</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>

9、啟動tomcat服務:

# startup.sh

修改httpd服務的配置文件

修改httpd主配置文件

 # vim  /etc/httpd/conf/httpd.conf

注釋 #DocumentRoot "/var/www/html"

修改httpd的反向代理配置

[root@computer-2 ~]# cat /etc/httpd/conf.d/vhosts.conf 
<VirtualHost *:80>
	ServerName node1.baidu.com
	ProxyRequests Off
	ProxyVia On
	ProxyPreserveHost On
	ProxyPass / balancer://lbtomcats/
	ProxyPassReverse / balancer://lbtomcats/
</VirtualHost>
<Proxy balancer://lbtomcats>
BalancerMember ajp://t0.baidu.com:8009 loadfactor=1 route=Tomcat1
BalancerMember ajp://t1.baidu.com:8009 loadfactor=2 route=Tomcat2
#ProxySet stickysession=ROUTEID
</Proxy>

啟動httpd服務

# systemctl start httpd

測試效果:

 第一次測試:

 

 第二次測試:

 

 下來模擬memcached的n2宕機,此時t0和t1都轉移到memcached的n1上:

 宕機n2:systemctl stop memcached

 

  

 再次重啟n2的memcached服務,此時Tomcat1就會又去優先到n2進行寫入緩存:

 重啟n2的memcached服務:systemctl  restart memcached

 

實戰二:基於session共享存儲實現LNMT的會話保持(sticky模式生產中常用)

1、修改nginx服務器的主配置文件 

upstream tomcats {    #在http 段配置
server t0.baidu.com:8080 weight=1;
server t1.baidu.com:8080 weight=2;
}
 
location / {    #在server 段配置
        proxy_pass http://tomcats;
}
location ~* \.(jsp|do)$ {
        proxy_pass http://tomcats;
}

只需要將httpd的配置改為nginx配置,upstream轉發到后端服務器,其他的tomcat配置不變、memcached服務配置文件都在上面:

2、測試效果:  

 此時tomcat1對應的n2和tomcat2對應的n1都是一個session ID,實驗成功:

 

 

實戰三:基於session共享存儲(memcached)實現LNMT的會話保持(non-sticky模式)

實現原理

從msm 1.4.0之后開始支持non-sticky模式。

Tomcat session為中轉Session,n1為主session,n2為備session。產生的新的Session會發送給主、備memcached,並清除本地Session。

n1下線,n2轉正。n1再次上線,n2依然是主Session存儲節點。

注意:其他測試頁面在上面已經存在,下面就不在寫入。

1、開始部署,在t0和t1的/usr/local/tomcat/conf/context.xml配置文件中修改

    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
        memcachedNodes="n1:192.168.7.100:11211,n2:192.168.7.101:11211"
        sticky="false"
        sessionBackupAsync="false"
        lockingMode="uriPattern:/path1|/path2"
        requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
        transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
        />

2、修改nginx服務器的主配置文件 

upstream tomcats {    #在http 段配置
server t0.baidu.com:8080 weight=1;
server t1.baidu.com:8080 weight=2;
}
 
location / {    #在server 段配置
        proxy_pass http://tomcats;
}
location ~* \.(jsp|do)$ {
        proxy_pass http://tomcats;
}

 3、啟動nginx服務和tomcat服務

# nginx  
# shutdown.sh
# startup.sh

 測試效果

此時可以看到,訪問tomcat時,占用的是memcached的n1

模擬此時的n1(memcached)宕機,此時n2就會占用上來,由於n1和n2是同優先級的服務器,此時就算n1啟動起來,也不會再占用到n1的緩存服務器上。

實戰四:基於session共享存儲(redis)實現LNMT的會話保持(non-sticky模式)

 1、安裝並配置redis服務

#  yum install redis  -y

#  vim /etc/redis.conf    #修改redis配置
 bind 0.0.0.0   #監聽本地的所有IP地址

# systemctl start  redis    #啟動redis服務

2、配置tomcat服務

修改tomcat文件時,目前沒有做redis主從復制及集群模式,生產中必須做,此時將IP地址都指向了一個redis的IP地址上

[root@centos-7 ~]# vim /usr/local/tomcat/conf/context.xml

    <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
        memcachedNodes="redis://192.168.7.100:6379"
        sticky="false"
        sessionBackupAsync="false"
        lockingMode="uriPattern:/path1|/path2"
        requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
        transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"
        />

創建t0和t1的測試頁面

# vim  /data/webapps/ROOT/index.jsp
<%@ page import="java.util.*" %>
<!DOCTYPE html>
<html lang="en">
<head>
        <meta charset="UTF-8">
        <title>lbjsptest</title>
</head>
<body>
<div>On <%=request.getServerName() %></div>
<div><%=request.getLocalAddr() + ":" + request.getLocalPort() %></div>
<div>SessionID = <span style="color:blue"><%=session.getId() %></span></div>
<%=new Date()%>
</body>
</html>

3、修改nginx服務器的主配置文件 

upstream tomcats {    #在http 段配置
server t0.baidu.com:8080 weight=1;
server t1.baidu.com:8080 weight=2;
}
 
location / {    #在server 段配置
        proxy_pass http://tomcats;
}
location ~* \.(jsp|do)$ {
        proxy_pass http://tomcats;
}

啟動nginx和tomcat服務

#  nginx  
# shutdown.sh
# startup.sh

測試效果:

兩個主機的session ID都一致,實驗成功:

 

總結  

通過多組實驗,使用不同技術實現了session持久機制  

1. session綁定,基於IP或session cookie的。其部署簡單,尤其基於session黏性的方式,粒度小,對負載均衡影響小。但一旦后端服務器有故障,其上的session丟失。

2. session復制集群,基於tomcat實現多個服務器內共享同步所有session。此方法可以保證任意一台后端服務器故障,其余各服務器上還都存有全部session,對業務無影響。但是它基於多播實現心跳,TCP單播實現復

制,當設備節點過多,這種復制機制不是很好的解決方案。且並發連接多的時候,單機上的所有session占據的內存空間非常巨大,甚至耗盡內存。

3. session服務器,將所有的session存儲到一個共享的內存空間中,使用多個冗余節點保存session,這樣做到session存儲服務器的高可用,且占據業務服務器內存較小。是一種比較好的解決session持久的解決方案。

以上的方法都有其適用性。生產環境中,應根據實際需要合理選擇。

不過以上這些方法都是在內存中實現了session的保持,可以使用數據庫或者文件系統,把session數據存儲起來,實現持久化。

這樣服務器重啟后,也可以重新恢復session數據。不過session數據是有時效性的,是否需要這樣做,視情況而定。

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM