NutzCN Logo
问答 Shiro使用redis共享Session但是redis连接不释放
发布于 2424天前 作者 yueming158 3671 次浏览 复制 上一个帖子 下一个帖子
标签:

Shiro使用redis共享Session但是redis连接不释放

30 回复

你自己写的?

不是我用的你github上面的配置文件
[main]

Session管理器,关闭定时校验机制,持久化环境下会非常耗内存

sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionValidationSchedulerEnabled = false

带缓存的SessionDAO

sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager

use R.UU32(), 原生的是UUID,比较长

sessionIdGenerator = org.nutz.integration.shiro.UU32SessionIdGenerator
securityManager.sessionManager.sessionDAO.sessionIdGenerator = $sessionIdGenerator

2层缓存配置

jedisAgent = org.nutz.integration.jedis.JedisAgent
cacheManager_ehcache = org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager_ehcache.cacheManagerConfigFile=classpath:ehcache.xml
cacheManager_redis = org.nutz.plugins.cache.impl.redis.RedisCacheManager
cacheManager_redis.mode=kv
cacheManager_redis.debug=true
cacheManager = org.nutz.plugins.cache.impl.lcache.LCacheManager
cacheManager.level1 = $cacheManager_ehcache
cacheManager.level2 = $cacheManager_redis
cacheManager.jedisAgent = $jedisAgent
securityManager.cacheManager = $cacheManager

cookie, nutzcn使用超长时间的cookie,所以下面的timeout都很长

sessionIdCookie=org.apache.shiro.web.servlet.SimpleCookie
sessionIdCookie.name=sid

sessionIdCookie.maxAge=1800000

sessionIdCookie.maxAge=60000
sessionIdCookie.httpOnly=true
sessionManager.sessionIdCookie=$sessionIdCookie
sessionManager.sessionIdCookieEnabled=true

sessionManager.globalSessionTimeout=1800000

sessionManager.globalSessionTimeout=6000

realm声明

nutzdao_realm = com.kaisa.kams.components.security.SimpleAuthorizingRealm
authc = org.nutz.integration.shiro.SimpleAuthenticationFilter

authc.loginUrl = /user/toLogin
logout.redirectUrl= /user/toLogin

roles.unauthorizedUrl=/authority/unauthorized
perms.unauthorizedUrl=/authority/unauthorized

[urls]
/user/logout = logout
/user/error = anon
/user/login = anon

用"插入代码"按钮重新发一次

而且我设置超时时间如果直接关掉浏览器那个缓存会一直存redis中

[main]

#Session管理器,关闭定时校验机制,持久化环境下会非常耗内存
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionValidationSchedulerEnabled = false

#带缓存的SessionDAO
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager = $sessionManager

# use R.UU32(), 原生的是UUID,比较长
sessionIdGenerator = org.nutz.integration.shiro.UU32SessionIdGenerator
securityManager.sessionManager.sessionDAO.sessionIdGenerator = $sessionIdGenerator

# 2层缓存配置
jedisAgent = org.nutz.integration.jedis.JedisAgent
cacheManager_ehcache = org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager_ehcache.cacheManagerConfigFile=classpath:ehcache.xml
cacheManager_redis = org.nutz.plugins.cache.impl.redis.RedisCacheManager
cacheManager_redis.mode=kv
cacheManager_redis.debug=true
cacheManager = org.nutz.plugins.cache.impl.lcache.LCacheManager
cacheManager.level1 = $cacheManager_ehcache
cacheManager.level2 = $cacheManager_redis
cacheManager.jedisAgent = $jedisAgent
securityManager.cacheManager = $cacheManager

# cookie, nutzcn使用超长时间的cookie,所以下面的timeout都很长
sessionIdCookie=org.apache.shiro.web.servlet.SimpleCookie
sessionIdCookie.name=sid
#sessionIdCookie.maxAge=1800000
sessionIdCookie.maxAge=60000
sessionIdCookie.httpOnly=true
sessionManager.sessionIdCookie=$sessionIdCookie
sessionManager.sessionIdCookieEnabled=true
#sessionManager.globalSessionTimeout=1800000
sessionManager.globalSessionTimeout=6000

# realm声明
nutzdao_realm = com.kaisa.kams.components.security.SimpleAuthorizingRealm
authc = org.nutz.integration.shiro.SimpleAuthenticationFilter


authc.loginUrl  = /user/toLogin
logout.redirectUrl= /user/toLogin

roles.unauthorizedUrl=/authority/unauthorized
perms.unauthorizedUrl=/authority/unauthorized


[urls]
/user/logout = logout
/user/error  = anon
/user/login  = anon

#redis配置
redis.host=192.168.42.31
redis.port=6379
redis.timeout=2000
redis.password=***
redis.database=5

只有调用shiro的subject.logout();缓存才会清除

那你指的redis连接不释放是哪里看出来?

我这边生产环境连接数一直涨而且到200以后有一台机器获取不到redis连接,我redis服务最大连接数有1万

那你怎么知道是这里的问题?

我其它地方暂时没有使用redis,这个是最近加的

我再监控一下这一块吧

那就是猜测而已

既然你怀疑是这里的问题,注释掉cacheManager_redis和level2嘛,测试一下,把问题缩小

想了想,把

securityManager.cacheManager = $cacheManager

改成

securityManager.cacheManager = $cacheManager_ehcache

就屏蔽掉redis层

看了看nutzcn的状态

# Server
redis_version:3.9.103
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:2543c881151a8cd6
redis_mode:standalone
os:Linux 3.13.0-101-generic x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.4
process_id:23555
run_id:5fe4e42cdc7a3a0aa69fb4b2eb7d6d716d5418a6
tcp_port:6379
uptime_in_seconds:3323813
uptime_in_days:38
hz:10
lru_clock:11010916
executable:/opt/redis/redis-server
config_file:/opt/redis.conf

# Clients
connected_clients:15
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

最近一次启动已经是1个月前, redis连接并无泄漏.

addr=127.0.0.1:53810 fd=120 idle=89 flags=N db=8 sub=0 psub=1 qbuf=0 obl=0 oll=0 events=r cmd=psubscribe
addr=127.0.0.1:54184 fd=148 idle=4457 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=set
addr=127.0.0.1:54218 fd=116 idle=4457 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:54436 fd=144 idle=4339 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:54932 fd=124 idle=4035 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55366 fd=132 idle=3772 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55579 fd=152 idle=3663 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55969 fd=160 idle=3427 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:56351 fd=140 idle=3251 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:56590 fd=168 idle=3085 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=192.168.42.31:52988 fd=164 idle=0 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=client
addr=127.0.0.1:61752 fd=156 idle=89 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=publish

addr=127.0.0.1:53810 fd=120 idle=2 flags=N db=8 sub=0 psub=1 qbuf=0 obl=0 oll=0 events=r cmd=psubscribe
addr=127.0.0.1:54184 fd=148 idle=4496 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=set
addr=127.0.0.1:54218 fd=116 idle=4496 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:54436 fd=144 idle=4378 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:54932 fd=124 idle=4074 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55366 fd=132 idle=3811 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55579 fd=152 idle=3702 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55969 fd=160 idle=3466 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:56351 fd=140 idle=3290 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:56590 fd=168 idle=3124 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=192.168.42.31:52988 fd=164 idle=0 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=client
addr=127.0.0.1:61965 fd=156 idle=5 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:61967 fd=136 idle=2 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=publish
addr=127.0.0.1:61973 fd=128 idle=3 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=publish
addr=127.0.0.1:61974 fd=172 idle=3 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=publish



addr=127.0.0.1:61752 fd=156 idle=89 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=publish
addr=127.0.0.1:61965 fd=156 idle=5 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
同一个fd由publish变为get后这个连接不释放

LCacheManager中:
    public void run() {
        byte count = 1;

        while(this.running && (this.jedisAgent == null || !this.jedisAgent.isReady())) {
            Lang.quiteSleep(100L);
        }

        log.info("JedisAgent is Ready ...");

        while(this.running) {
            try {
                log.debug("psubscribe " + PREFIX + "*");
                this.jedis().psubscribe(this.pubSub, new String[]{PREFIX + "*"});
            } catch (Exception var3) {
                if(!this.running) {
                    break;
                }

                log.debug("psubscribe fail, retry after 3 seconds", var3);
                Lang.quiteSleep((long)(count * 1000));
            }
        }

    }

请教:这里面的连接是如何释放的

psubscribe并不会也不能释放连接,那是是阻塞的方法, 只有当链接中断了,才可能重新执行

日志里面, 看我截取的这一段, 第一条和最后一条是共用连接的, 说明他们都是从JedisPool取出,并不存在泄漏

addr=127.0.0.1:56351 fd=140 idle=3251 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:56590 fd=168 idle=3085 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=192.168.42.31:52988 fd=164 idle=0 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=client
addr=127.0.0.1:61752 fd=156 idle=89 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=publish

addr=127.0.0.1:53810 fd=120 idle=2 flags=N db=8 sub=0 psub=1 qbuf=0 obl=0 oll=0 events=r cmd=psubscribe
addr=127.0.0.1:54184 fd=148 idle=4496 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=set
addr=127.0.0.1:54218 fd=116 idle=4496 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:54436 fd=144 idle=4378 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:54932 fd=124 idle=4074 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55366 fd=132 idle=3811 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55579 fd=152 idle=3702 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:55969 fd=160 idle=3466 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get
addr=127.0.0.1:56351 fd=140 idle=3290 flags=N db=8 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=get

你说的那部分代码, 的确不够严谨,已经提交修改 https://gitee.com/nutz/nutzmore/commit/3730ec0ee7b6725daf44890c3be59595dd533c2e

但我觉得这跟泄漏没有关系

你已经通过注释shiro.ini里面的配置验证过泄漏的来源吗??

这个不是日志,是两次client list 出来的,第一条和第最后一条是同一个连接,它的空闲时间都3290秒了一直不释放,现在就是这个问题。

为啥要释放, 这些都在JedisPool里面

这跟数据库连接池一个道理

我本地可以重现,就是我一个方法里面有调用getSession拿session里面的东西使用处理完成,然后返回回去,页面再ajax请求后台请求(一次发了四个不同的请求)这时候shiro也会验证,然后就出现多了一个get的连接,这个连接一直不释放。不断请求连接数就不断增多,超过jedis.js的那个100的限制然后就拿不到了!

不释放没有关系,可是一直空闲在哪里没有被重新使用。

那就是要看看哪里调用的Jedis.get了

jedis.get有2个方法, 一个byte[]一个String, 分别打断点看看

org.nutz.plugins.cache.impl.redis.RedisCache2里面有调用get,但包裹了finally块,肯定会回收

查查项目里面哪里还用到了吧

不好意思,我自己傻X了,有一个地方用了,没有关闭!麻烦你了!

添加回复
请先登陆
回到顶部