session方案及配置
用戶訪問服務器資源主要分成兩類,一類是無狀態(tài)訪問,例如請求一張圖片。另一類是有狀態(tài)訪問,這種情況下,服務器需要記錄追蹤用戶狀態(tài),并根據用戶所處狀態(tài)做出不同響應,典型的例子是購物車。Session的作用就是在Web服務器上保持用戶的狀態(tài)信息。
用戶請求連接服務器時,服務器會生成一個唯一的sessionID為標識符至用戶端本地,客戶端使用該sessionID來存/取服務器端的session空間。sessionID是客戶端瀏覽器cookie保存的。
當客戶端訪問Tomcat集群時,所有的請求將被Nginx攔截,由Nginx做負載均衡后轉發(fā)給后臺真實Tomcat。按照這個流程就可能出現一個問題,當用戶進行頁面刷新或跳轉時,每次請求將被轉發(fā)給不同的Tomcat處理,這樣就會造成Session的不同步。舉個簡單的栗子,例如當用戶往購物車添加商品時,興高采烈地準備買單了,當他跳轉到付款頁面卻發(fā)現購物車被清空了,這就是Session丟失的典型栗子。因此,我們需要為集群環(huán)境做Session同步。
單機環(huán)境下,session可有部署在服務器上的web容器如:Tomcat進行保存管理。但在使用負載均衡集群時如架構前端Nginx來負載均衡后端多臺Tomcat,所以可能分發(fā)到任何一臺后端的Tomcat;雖然呢,也有類似于Nginx中的ip_hash算法可以將客戶端和服務器做一個綁定,但是弊端太多,生產環(huán)境慎用。
下面將介紹幾種session的方案
一、session綁定
session綁定就是利用負載均衡服務器的hash源IP地址算法實現,將來源于同一個IP的請求總是分發(fā)到同一臺后端web服務器上,又稱為會話粘滯。 但是如果該服務器死機或故障,那該用戶的session空間也就不復存在了,就如我們網頁瀏覽購物網站時,剛添加到購物車的寶貝,一刷新全沒了,用戶體驗肯定非常差,所以該session綁定方案使用場景非常有限
#編輯nginx主配置文件 upstream tomcats { ip_hash #使用ip_hash算法調度 server 192.168.111.4:8080; server 192.168.111.5:8080; }
二、session復制
適用于小型架構的服務器集群。開啟web服務器的session復制功能,在集群中的幾臺服務器之間同步session對象,這樣每臺服務器都保存了用戶的session信息,但是當集群規(guī)模比較大時,session復制機制會消耗大量系統資源以及網絡資源
操作系統 | IP地址 | 軟件版本 | 主機名 |
---|---|---|---|
CentOS7 | 192.168.111.3 | nginx1.14.2 | Nginx |
centos7 | 192.168.111.4 | JDK1.7;Tomcat7.0.54 | tnode1 |
centos7 | 192.168.111.5 | JDK1.7;Tomcat7.0.54 | tnode2 |
如有防火墻或selinux記得關閉或者修改相應規(guī)則
[root@localhost ~]# nginx -v nginx version: nginx/1.14.2 [root@localhost ~]# vim /etc/hosts 192.168.111.3 nginx 192.168.111.4 tnode1 192.168.111.5 tnode2 [root@localhost ~]# scp /etc/hosts 192.168.111.4:/etc/ [root@localhost ~]# scp /etc/hosts 192.168.111.5:/etc/ #配置hosts文件 #hostname nginx #hostname tnode1 #hostname tnode2 修改主機名 [root@nginx ~]# vim /usr/local/nginx/conf/nginx.conf http { ... upstream tomcatpool { server 192.168.111.4:8080 weight=1 max_fails=1 fail_timeout=10s; server 192.168.111.5:8080 weight=1 max_fails=1 fail_timeout=10s; } #以上為添加 location / { root html; index index.html index.htm; proxy_pass http://tomcatpool; } #以上為修改添加最下面一行調用池 安裝配置Tomcat。 [root@tnode1 ~]# tar zxf jdk-7u65-linux-x64.tar.gz [root@tnode1 ~]# mv jdk1.7.0_65/ /usr/local/java7 [root@tnode1 ~]# echo "PATH=$PATH:/usr/local/java7/bin" >> /etc/profile [root@tnode1 ~]# source /etc/profile [root@tnode1 ~]# rm -rf /usr/bin/java [root@tnode1 ~]# java -version java version "1.7.0_65" Java(TM) SE Runtime Environment (build 1.7.0_65-b17) Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode) [root@tnode1 ~]# tar zxf apache-tomcat-7.0.54.tar.gz [root@tnode1 ~]# mv apache-tomcat-7.0.54 /usr/local/tomcat7 [root@tnode2 ~]# tar zxf jdk-7u65-linux-x64.tar.gz [root@tnode2 ~]# mv jdk1.7.0_65/ /usr/local/java7 [root@tnode2 ~]# echo "PATH=$PATH:/usr/local/java7/bin" >> /etc/profile [root@tnode2 ~]# source /etc/profile [root@tnode2 ~]# rm -rf /usr/bin/java [root@tnode1 ~]# java -version java version "1.7.0_65" Java(TM) SE Runtime Environment (build 1.7.0_65-b17) Java HotSpot(TM) 64-Bit Server VM (build 24.65-b04, mixed mode) [root@tnode2 ~]# tar zxf apache-tomcat-7.0.54.tar.gz [root@tnode2 ~]# mv apache-tomcat-7.0.54 /usr/local/tomcat7 [root@tnode1 ~]# vim /usr/local/tomcat7/webapps/ROOT/session.jsp #測試頁面 Session ID:<%= session.getId() %><BR> SessionPort:<%= request.getServerPort() %> <% out.println("This tomcat server 192.168.111.4");%> [root@tnode2 ~]# vim /usr/local/tomcat7/webapps/ROOT/session.jsp Session ID:<%= session.getId() %><BR> SessionPort:<%= request.getServerPort() %> <% out.println("This tomcat server 192.168.111.5");%> #這是一個獲取當前服務器所擁有的IP和sessionID的腳本頁面 下面開始配置session復制(生產環(huán)境時一般10臺以下使用該session解決方案 [root@tnode1 ~]# vim /usr/local/tomcat7/conf/server.xml 104 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tnode1"> #改行后面添加jvmroute配置項。 109 <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> #去掉注釋 [root@tnode1 ~]# vim /usr/local/tomcat7/webapps/ROOT/WEB-INF/web.xml </description> #添加至倒數第二行 [root@tnode2 ~]# vim /usr/local/tomcat7/conf/server.xml <Engine name="Catalina" defaultHost="localhost" jvmRoute="tnode2"> <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> [root@tnode1 ~]# vim /usr/local/tomcat7/webapps/ROOT/WEB-INF/web.xml </description> #添加至倒數第二行 [root@tnode1 ~]# /usr/local/tomcat7/bin/shutdown.sh [root@tnode1 ~]# /usr/local/tomcat7/bin/startup.sh [root@tnode2 ~]# /usr/local/tomcat7/bin/shutdown.sh [root@tnode2 ~]# /usr/local/tomcat7/bin/startup.sh 客戶端使用火狐瀏覽器輸入:http://192.168.111.3/session.jsp來進行測試,并且刷新(別強制刷新,那樣是新的sessionID)
三、使用memcached解決session問題
memcached是一套分布式的快取系統,相關數據都是在內存里,一旦服務重啟或者死機,則數據必然丟失;memcached是鍵值對存儲形式;在以下試驗中,每個session都會在這兩臺memcached上進行分布式存儲,有了冗余性,即使一臺出問題也不影響工作。同樣只適用于中小型架構。
以下的配置兩臺Tomcat一樣
[root@tnode1 ~]# yum -y install libevent memcached #安裝memcached及其依賴 [root@tnode1 ~]# memcached -u root -m 512M -n 10 -f 2 -d -vvv -c 512 //-u:運行用戶必須是root身份 //-m:指定使用物理機的多少內存 //-n:chunk size的最小空間是多少字節(jié) //-f:chunk size大小增長的倍數默認1.25倍 //-d:在后臺啟動 //-vvv:顯示詳細信息 //-c:memcached服務的最大連接數 Tomcat連接memcached所依賴的庫文件: javolution-5.5.1.jar memcached-session-manager-1.5.1.jar msm-kryo-serializer-1.6.4.jar kryo-1.03.jar memcached-session-manager-tc7-1.5.1.jar reflectasm-0.9.jar kryo-serializers-0.10.jar minlog-1.2.jar spymemcached-2.7.3.jar memcached-2.5.jar msm-javolution-serializer-1.5.1.jar 將這些文件放到/usr/local/tomcat7/lib/目錄下 配置文件連接memcached。 [root@tnode2 ~]# vim /usr/local/tomcat7/conf/context.xml <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager" memcachedNodes="memA:192.168.111.4:11211 memB:192.168.111.5:11211" requestUrilgnorePattern=".*(ico|png|gif|jpg|css|js)$" transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFactory"/> [root@tnode2 ~]# /usr/local/tomcat7/bin/shutdown.sh [root@tnode2 ~]# /usr/local/tomcat7/bin/startup.sh #重啟服務 測試頁仍然使用以上的那個測試頁 瀏覽器訪問http://192.168.111.3/session.jsp測試,可以看到sessionID不變
四、使用redis解決session問題
注意:盡量保持系統環(huán)境的純凈
如果使用如上做完memcached環(huán)境接著做redis 1.rpm -e memcached-1... 2.vim /usr/local/tomcat7/conf/context.xml 3.pkill -9 memcached 4.刪除相關jar包 安裝部署redis [root@tnode1 ~]# tar zxf redis-3.2.5.tar.gz [root@tnode1 ~]# yum -y install tcl #依賴包 [root@tnode1 src]# mkdir /usr/local/redis/{bin,etc,var} -pv [root@tnode1 src]# cp ~/redis-3.2.5/src/redis-benchmark redis-check-aof redis-cli redis-server /usr/local/redis/bin/ //redis-benchmark:讀寫性能測試工具 //redis-cli:redis命令行操作工具 //redis-server:redis服務的daemon啟動程序 [root@tnode1 src]# cp ~/redis-3.2.5/redis.conf /usr/local/redis/etc/ //redis的主配置文件 [root@tnode1 src]# vim /usr/local/redis/etc/redis.conf 128 daemonize yes #表示將redis啟動在后臺 61 bind 0.0.0.0 #監(jiān)聽所有主機 [root@tnode1 src]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf [root@tnode1 src]# netstat -anpt | grep redis tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 69432/redis-server #啟動并且查看端口 Tomcat和redis連接需要用到如下包: commons-logging-1.1.3.jar jedis-2.5.2.jar tomcat-redis-session-manage-tomcat7.jar commons-pool2-2.2.jar tomcat-juli.jar [root@tnode1 ~]# vim /usr/local/tomcat7/conf/context.xml #連接redis配置 <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" /> <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager" host="192.168.111.4" port="6379" database="0" maxInactiveInterval="60" /> #Context字段中添加如上,IP為redis服務器的IP。 #如下可以先把node2上該lib目錄刪掉,直接復制覆蓋 [root@tnode1 ~]# scp -r /usr/local/tomcat7/lib root@192.168.111.5:/usr/local/tomcat7/lib #如下是直接覆蓋node2配置文件 [root@tnode1 ~]# scp /usr/local/tomcat7/conf/context.xml root@192.168.111.5:/usr/local/tomcat7/conf/ #然后node2上重啟Tomcat服務,可多重啟幾遍順便觀察node1上的redis監(jiān)視狀態(tài),并且時刻關注本機catalina.out日志變化是否異常。 #如下是正常情況下redis監(jiān)視的狀態(tài)輸出 [root@tnode1 src]# /usr/local/redis/bin/redis-cli -p 6379 monitor 1556385116.932343 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800" 1556385116.970109 [0 192.168.111.4:37948] "GET" "DCF23D098140E899E20A996990F690D5" 1556385116.972760 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800" 1556385117.582753 [0 192.168.111.4:37948] "GET" "DCF23D098140E899E20A996990F690D5" 1556385117.584391 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800" 1556385117.599639 [0 192.168.111.4:37948] "GET" "DCF23D098140E899E20A996990F690D5" 1556385117.600743 [0 192.168.111.4:37948] "EXPIRE" "DCF23D098140E899E20A996990F690D5" "1800" 1556385125.008432 [0 192.168.111.4:37948] "PING" 1556385155.006175 [0 192.168.111.4:37948] "PING" 1556386097.450914 [0 192.168.111.5:34118] "SETNX" "F7379EF99F21FD0BBF830056FEF162A0" "null" 1556386097.575639 [0 192.168.111.5:34118] "SET" "F7379EF99F21FD0BBF830056FEF162A0" "xacxedx00x05srx00Dcom.orangefunction.tomcat.redissessions.S essionSerializationMetadataBxd9xd9xf7vxa2xdbLx03x00x01[x00x15sessionAttributesHashtx00x02[Bxpwx14x00x00x00x10x1fxa2xa9ox15x7fxe1Wx9cx9cxc6xc2xb0xd5xe2xa8xsrx00x0ejava.lang.Long;x8bxe4x90xccx8f#xdfx02x00x01Jx00x05valuexrx00x10java.lang.Numberx86xacx95x1dx0bx94xe0x8bx02x00x00xpx00x00x01j3x83Fxddsqx00~x00x03x00x00x01j3x83Fxddsrx00x11java.lang.Integerx12xe2xa0xa4xf7x81x878x02x00x01Ix00x05valuexqx00~x00x04x00x00absrx00x11java.lang.Booleanxcd rx80xd5x9cxfaxeex02x00x01Zx00x05valuexpx01qx00~x00nsqx00~x00x03x00x00x01j3x83Fxddtx00 F7379EF99F21FD0BBF830056FEF162A0sqx00~x00ax00x00x00x00wbx00x00x01j3x83Fxdd"1556386097.577377 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800" 1556386097.586858 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800" 1556386099.395455 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0" 1556386099.403983 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800" 1556386099.410867 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0" 1556386099.413166 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800" 1556386099.855877 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0" 1556386099.857305 [0 192.168.111.5:34118] "EXPIRE" "F7379EF99F21FD0BBF830056FEF162A0" "1800" 1556386100.497947 [0 192.168.111.5:34118] "GET" "F7379EF99F21FD0BBF830056FEF162A0" 客戶端訪問http://192.168.111.3/session.jsp,是Nginx的地址來進行測試,正常時是sessionID不會變的
五、memcached和redis對比表
、 | 內存利用率 | 性能 | 數據持久化 | 其它 |
---|---|---|---|---|
redis | 鍵值對村存儲利用率低于memcached,但使用hash結構存儲則超過后者 | 只使用單核CPU,數據大小100K以下快于后者 | 支持數據持久化(保存到硬盤) | Redis 支持數據的備份,即 master-slave 模式的數據備份,支持多種數據結構的存儲 |
memcached | 如上 | 可以使用多核,100K以上快于前者 | 自身不支持持久化,但可以結合其他數據庫做架構如:memcached + bdb | 兩者性能都屬于非常不錯的,而且也都是開源免費。 |