對于分布式使用nginx+tomcat實現負載均衡,最常用的均衡算法有ip_hash、輪訓、根據權重、隨機等。不管對于哪一種負載均衡算法,由于nginx對不同的請求分發到某一個tomcat,tomcat在運行的時候分別是不同的容器里,因此會出現session不同步或者丟失的問題。
實際上實現session共享的方案很多,其中一種常用的就是使用tomcat、jetty等服務器提供的session共享功能,將session的內容統一存儲在一個數據庫(如mysql)或緩存(如redis)中。
本文旨在解決分布式系統的session如何共享問題,大致思路:session放入redis。其他解決方案:持久化、放cache等都可以,但是自從有了redis,這完全可以變的簡簡單單。
本文大致分兩步:
1.springboot中如何使用redis。
2.redis如何解決session共享
pom依賴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
<!--redis配置開始--> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-redis</artifactid> </dependency> <dependency> <groupid>org.springframework.data</groupid> <artifactid>spring-data-redis</artifactid> <version>${spring-data-redis.version}</version> </dependency> <dependency> <groupid>redis.clients</groupid> <artifactid>jedis</artifactid> <version>${jedis.version}</version> </dependency> <dependency> <groupid>org.springframework.session</groupid> <artifactid>spring-session-data-redis</artifactid> </dependency> <!--redis配置結束--> |
添加redis配置類
該配置類同樣可以配置緩存失效時間等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package com.mos.quote.config; import com.fasterxml.jackson.annotation.jsonautodetect; import com.fasterxml.jackson.annotation.propertyaccessor; import com.fasterxml.jackson.databind.objectmapper; import org.springframework.cache.cachemanager; import org.springframework.cache.annotation.cachingconfigurersupport; import org.springframework.cache.annotation.enablecaching; import org.springframework.cache.interceptor.keygenerator; import org.springframework.context.annotation.bean; import org.springframework.context.annotation.configuration; import org.springframework.data.redis.cache.rediscachemanager; import org.springframework.data.redis.connection.redisconnectionfactory; import org.springframework.data.redis.core.redistemplate; import org.springframework.data.redis.core.stringredistemplate; import org.springframework.data.redis.serializer.jackson2jsonredisserializer; /** * @author administrator */ @configuration @enablecaching public class redisconfig extends cachingconfigurersupport { @bean public keygenerator keygenerator(){ return (target, method, params) -> { stringbuilder sb = new stringbuilder(); sb.append(target.getclass().getname()); sb.append(method.getname()); for (object obj : params) { sb.append(obj.tostring()); } return sb.tostring(); }; } @bean public redistemplate<string, string> redistemplate(redisconnectionfactory factory) { stringredistemplate template = new stringredistemplate(factory); jackson2jsonredisserializer jackson2jsonredisserializer = new jackson2jsonredisserializer(object. class ); objectmapper om = new objectmapper(); om.setvisibility(propertyaccessor.all, jsonautodetect.visibility.any); om.enabledefaulttyping(objectmapper.defaulttyping.non_final); jackson2jsonredisserializer.setobjectmapper(om); template.setvalueserializer(jackson2jsonredisserializer); template.afterpropertiesset(); return template; } @bean public cachemanager cachemanager(redistemplate<string,string> redistemplate) { rediscachemanager rcm = new rediscachemanager(redistemplate); //設置緩存過期時間 rcm.setdefaultexpiration( 600000 ); return rcm; } } |
配置redis服務
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# redis數據庫索引(默認為 0 ) spring.redis.database= 0 # redis服務器地址 spring.redis.host= 192.168 . 1.118 # redis服務器連接端口 spring.redis.port= 6381 # redis服務器連接密碼(默認為空) spring.redis.password= # 連接池最大連接數(使用負值表示沒有限制) spring.redis.pool.max-active= 8 # 連接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.pool.max-wait=- 1 # 連接池中的最大空閑連接 spring.redis.pool.max-idle= 8 # 連接池中的最小空閑連接 spring.redis.pool.min-idle= 0 # 連接超時時間(毫秒) spring.redis.timeout= 0 |
單元測試
1、set值(字符串)
1
2
3
4
5
|
@test public void put(){ stringredistemplate.opsforvalue().set( "test001" , "test001" ); assert .assertequals( "test001" , stringredistemplate.opsforvalue().get( "test001" )); } |
往redis放一個key為test001、value為test001的值,然后查看redis
key=test001
2、set值(object)
1
2
3
4
5
6
7
8
9
10
11
|
@test public void testobj() throws exception { sysuser user= new sysuser(); user.setid( "123456" ); user.setname( "張三" ); valueoperations<string, sysuser> operations=redistemplate.opsforvalue(); operations.set( "user1" , user); operations.set( "user2" , user, 5 , timeunit.seconds); thread.sleep( 6000 ); assert .assertfalse(redistemplate.haskey( "user2" )); } |
往redis分別放key為user1和user2的對象,user2設置5秒失效,線程等待6秒再完成,期望結果:redis中有user1,沒有user2,bingo!!!
objtest
解決session共享
使用spring-session-data-redis實現session共享,pom中引入該依賴(上文已添加),添加sessionconfig配置類。
對,沒看錯,只需要這個就夠了。最長有效時間根據自己情況隨意配置即可。
1
2
3
4
5
6
7
8
9
10
11
12
|
package com.mos.quote.config; import org.springframework.context.annotation.configuration; import org.springframework.session.data.redis.config.annotation.web.http.enableredishttpsession; /** * @author administrator */ @configuration @enableredishttpsession (maxinactiveintervalinseconds = 3000 ) public class sessionconfig { } |
測試
寫一個簡單controller,如下
1
2
3
4
5
6
7
8
|
@requestmapping ( "testsessiontimeout" ) public string testsessiontimeout(string id,httpsession session,model model){ area area = areaservice.getbyid(id); system.out.println( "sessionid-------->" +session.getid()); model.addattribute( "area" ,json.tojsonstring(area)); session.setattribute( "area" ,json.tojsonstring(area)); return "demo/test1" ; } |
這里可以看到sessionid:
sessionid
看redis中,可以看到失效時間,sessionid等
sessionid
共享session
另外找一個機器,照著這個配置再來一遍,自動啟用session共享,因為sessionid都存在了同一個redis中。奏是這么簡單。挽起袖子開始干吧。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://www.jianshu.com/p/b5a96142fdd9