每天学习一点点之 Tomcat 是如何清除过期 Session 的

今天使用一种很临时的方案解决 Session 泄漏的问题:缩短 Session 的过期时间。这种方法虽然简单,但却非常有效。然而,这引发了一个问题:我们应该将过期时间设置为多短呢?在 Spring Boot 中,最短的过期时间是 60 秒。如果你配置的值小于 60 秒,系统会将其默认设置为 60 秒。这是由 org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory#getSessionTimeoutInMinutes 方法决定的:

	private long getSessionTimeoutInMinutes() {
		Duration sessionTimeout = getSession().getTimeout();
		if (isZeroOrLess(sessionTimeout)) {
			return 0;
		}
		return Math.max(sessionTimeout.toMinutes(), 1);
	}

这时候组内有同学说,过短的过期时间是否会影响服务的性能,例如,是否需要更频繁地删除 Session

为了解答这个问题,我们需要理解 “Tomcat 是如何清除 Session 的”,以及 “Tomcat 中 Session 的更新机制是否会受到 Session 过期时间设置的长短的影响”。

其实根据经验,结合 Redis 删除过期 Key,以及 ThreadLocal 清除过期 entry 等存在类似场景的框架,过期清除机制无非就是两种策略,以及一些细微的处理差异:

  • 惰性删除:只在数据被访问时才检查和删除过期的数据
    • 每次只检查当前数据
    • 顺带检查周边数据
  • 定期删除:后台定时进行扫描
    • 全量扫描
    • 随机扫描

我相信 Tomcat 的处理方式也不会脱离这两种策略。带着这个思考,那么接下来就源码分析一下 Tomcat 到底是如何清除过期 Session 的。

关于 Session,Tomcat 提供了一个常用的函数 org.apache.catalina.session.StandardSession#isValid,用于判断 Session 是否有效。如果 Session 已经无效,该函数会调用 org.apache.catalina.session.StandardSession#expire(boolean) 使 Session 过期(移除)。这表明 Tomcat 对 Session 的处理采用了惰性删除机制。

Tomcat 提供了几种不同的 Session 持久化策略,主要通过实现不同的 ManagerStore 来实现:

  1. 内存持久化:这是 Tomcat 的默认策略,由 StandardManager 实现。所有的 Session 都保存在内存中。当 Tomcat 重启或者出现故障时,所有的 Session 信息都会丢失。
  2. 文件持久化:由 PersistentManagerFileStore 实现。不活跃的 Session 会被保存到文件系统中,从而释放内存。当 Session 再次变得活跃时,可以从文件系统中恢复。
  3. 数据库持久化:由 PersistentManagerJDBCStore 实现。不活跃的 Session 会被保存到数据库中。这种策略适合于需要在多个 Tomcat 实例之间共享 Session 的情况。
  4. 分布式 Session:在一个 Tomcat 集群中,可以通过实现 ClusterableSessionDeltaManagerBackupManager 来实现 Session 的复制或者备份,从而实现 Session 的分布式管理。

本文关注的是内存持久化策略,即 StandardManager。它有一个函数 org.apache.catalina.session.ManagerBase#processExpires,该函数遍历所有的 Session,对每个 Session 判断是否过期。如果发现 Session 已失效,就会让 Session 过期:

    public void processExpires() {

        long timeNow = System.currentTimeMillis();
        Session sessions[] = findSessions();
        int expireHere = 0;

        if (log.isDebugEnabled()) {
            log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length);
        }
        for (Session session : sessions) {
            if (session != null && !session.isValid()) {
                expireHere++;
            }
        }
        long timeEnd = System.currentTimeMillis();
        if (log.isDebugEnabled()) {
            log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) +
                    " expired sessions: " + expireHere);
        }
        processingTime += (timeEnd - timeNow);

    }

既然怀疑这个函数可能存在定时调度,其实有一个小技巧,在这个函数上打一个断点,看是否可能触发,果然没一会就触发了:

在这里插入图片描述

根据 stack trace,这个函数是由 ContainerBackgroundProcessor 执行的。

在这里插入图片描述

Tomcat 启动时会执行 threadStart 方法,该方法基于 java.util.concurrent.ScheduledExecutorService 启动一个定时任务,backgroundProcessorDelay 参数可以控制启动后多久开始执行,backgroundProcessorDelay 控制多久执行一次。

    /**
     * Start the background thread that will periodically check for session timeouts.
     */
    protected void threadStart() {
        if (backgroundProcessorDelay > 0 &&
                (getState().isAvailable() || LifecycleState.STARTING_PREP.equals(getState())) &&
                (backgroundProcessorFuture == null || backgroundProcessorFuture.isDone())) {
            if (backgroundProcessorFuture != null && backgroundProcessorFuture.isDone()) {
                // There was an error executing the scheduled task, get it and log it
                try {
                    backgroundProcessorFuture.get();
                } catch (InterruptedException | ExecutionException e) {
                    log.error(sm.getString("containerBase.backgroundProcess.error"), e);
                }
            }
            backgroundProcessorFuture = Container.getService(this).getServer().getUtilityExecutor()
                    .scheduleWithFixedDelay(new ContainerBackgroundProcessor(), c,
                            backgroundProcessorDelay, TimeUnit.SECONDS);
        }
    }

这表明 Tomcat 对 Session 的处理也有定期删除机制。

总结

在 Tomcat 中,Session 的管理采用了惰性删除和定期删除两种策略:

  • 惰性删除是通过 org.apache.catalina.session.StandardSession#isValid 方法实现的,每次在判断 Session 是否有效的时候,如果 Session 已经无效,就会让 Session 过期(移除)
  • 在内存持久化策略中在内存持久化策略中,定期删除是通过 org.apache.catalina.session.ManagerBase#processExpires 方法实现的,该方法会定期遍历所有的 Session,对每个 Session 判断是否过期,如果发现 Session 已失效,就会让 Session 过期

在 Tomcat 中,Session 的更新机制并不会直接受到 Session 过期时间设置的长短的影响,但是,如果 Session 的数量过多,可能导致 Session 清理操作的效率降低。因为在每次 Session 清理操作时,都需要遍历所有的 Session,检查每个 Session 是否过期,如果过期就将其移除。如果 Session 的数量过多,那么这个过程就会消耗更多的时间和资源。

因此,虽然 Session 的过期时间设置不会直接影响 Session 的更新机制,但是 Session 的数量过多确实会对 Session 的更新效率和系统性能产生影响。为了保持系统的高效运行,应该尽量控制 Session 的数量,避免 Session 的数量过多。

欢迎关注公众号:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/181474.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

修改Docker默认镜像和容器存储位置(超详细!!!)

Ubuntu20.04 修改Docker默认镜像和容器存储位置 Docker 默认安装的情况下,会使用 /var/lib/docker/ 目录作为存储目录,用以存放拉取的镜像和创建的容器等。不过由于此目录一般都位于系统盘,遇到系统盘比较小,而镜像和容器多了后就…

母婴团队半年破亿秘诀揭秘,合规经营成就辉煌

这支母婴产品销售团队在短短半年内实现了过亿的销售额,这是一个令人瞩目的成就。他们既不依赖线下门店,也不是传统的电商平台,那么他们是如何做到这一点的呢? 这个团队从16年10月开始经营母婴产品,如今已经过去了6年时…

【JavaEE】Spring小练习——存储和获取对象

一、题目: 在 Spring 项目中,通过 main 方法获取到 Controller 类,调用 Controller 里面通过注入的方式调用Service 类,Service 再通过注入的方式获取到 Repository 类,Repository 类里面有一个方法构建⼀个 User 对象…

unordered_map 与 unordered_set 的使用

unordered_map unordered_map 的介绍文档 unordered_map 的介绍文档&#xff1a;来自cpluscplus.com 的中文翻译 unordered_map是存储<key, value>键值对的关联式容器&#xff0c;其允许通过keys快速的索引到与 其对应的value。在unordered_map中&#xff0c;键值通常用…

国内企业出海首选的免费开源订单管理系统(OMS)解决方案

用开源智造Odoo订单管理系统 (OMS) 解决方案实现"订单到收款"流程自动化 开源智造Odoo 订单管理软件功能消除了手动操作瓶颈&#xff0c;可防止出错&#xff0c;还建立了从销售报价到订单履行的顺畅工作流来确保及时开票和付款&#xff0c;从而帮助您理顺订单处理过程…

大数据量条件SQL查询内存处理方案以及数据过滤算法优化

MySQL是一个广泛使用的关系型数据库管理系统。通过SQL语言进行数据操作和查询&#xff0c;还支持多用户、多线程和分布式操作等功能。 在实际使用中&#xff0c;我们会遇到各种查询条件&#xff0c;如字段名、表名、逻辑运算符、比较运算符、函数等。其中&#xff0c;有些查询…

【SpringCloud】从单体架构到微服务架构

今天来看看架构的演变过程 一、单体架构 从图中可以看到&#xff0c;所有服务耦合在一起&#xff0c;数据库存在单点&#xff0c;一旦其中一个服务出现问题时&#xff0c;整个工程都需要重新发布&#xff0c;从而导致整个业务不能提供响应 这种架构对于小项目而言是没有什么…

人人吐槽互联网行情不好?但这个岗位的需求猛增、疯狂招人!

在目前的大环境下&#xff0c;外部力量对国内国高科技领域的打压和封锁&#xff0c;国内的IT大厂纷纷进行了裁员&#xff0c;IT行业的龙头大厂裁员举措引发行业震动…… 可真的是这样吗&#xff1f;中国IT没前途了?在IT行业找不到工作了&#xff1f;非也非也&#xff0c;这只…

IoU计算方式

文章目录 一.IoU的简介及原理解析二.yolov系列中的IOU 一.IoU的简介及原理解析 IoU的全称为交并比&#xff08;Intersection over Union&#xff09;&#xff0c;通过这个名称我们大概可以猜到IoU的计算方法。IoU计算的是 “预测的边框”和“真实的边框”的交集和并集的比值。…

2023年“福建省工业互联网+智能制造创新大赛”开启报名

11月22日&#xff0c;由福建省总工会、福建省大数据集团有限公司共同举办的2023年“福建省工业互联网智能制造创新大赛”启动报名。 大赛积极响应《福建省总工会等八部门关于广泛深入开展劳动和技能竞赛为新发展阶段新福建建设建工立业的意见》&#xff08;闽工〔2022〕70号&am…

新手小白想做跨境电商,应该选第三方平台还是独立站?

近几年在疫情的影响下&#xff0c;电商特有的“免接触”模式迅速切中消费者的心理痛点&#xff0c;加上国内电商发展已经趋于平缓&#xff0c;很多线下店铺被迫关闭&#xff0c;这也使得越来越多的大卖和平台也不约而同布局跨境电商。而说到跨境电商&#xff0c;或许大家普遍想…

线程的认识

线程的引入 上一篇中,我们主要讲到了进程,多任务操作系统,希望系统能同时运行多个程序.如果是单任务的操作系统,完全不涉及进程,也不需要管理,更不需要调度.因此,本质上来说,进程是用来解决"并发编程"这样的问题的.但在一些特定的情况下,进程的表现,往往不尽如人意.比…

VTK物体表面画贴合线条

1、自由画线 2、曲线拟合画线 3、三点闭合曲线

软件流程设计之事件风暴EventStorming

最近新开了一个公众号&#xff0c;有兴趣可以关注一下。时不时就复活去更新一下。 最近在带几个新员工&#xff0c;新员工是学校刚毕业的&#xff0c;习惯于做一些导师或者师兄师姐们拆解好的任务&#xff0c;有很明确的功能描述&#xff0c;甚至喂饭喂到什么地步呢&#xff0…

跨境电商的微商业务:个人品牌的成功之路

随着互联网的发展&#xff0c;跨境电商行业迅猛崛起&#xff0c;微商业务作为其中的一种新型销售模式也逐渐崭露头角。微商业务以低成本、高灵活性的特点&#xff0c;为个人品牌的成功之路开辟了新的可能性。 本文将深入研究跨境电商微商业务&#xff0c;探讨在这个领域中个人…

竞赛YOLOv7 目标检测网络解读

文章目录 0 前言1 yolov7的整体结构2 关键点 - backbone关键点 - head3 训练4 使用效果5 最后 0 前言 世界变化太快&#xff0c;YOLOv6还没用熟YOLOv7就来了&#xff0c;如果有同学的毕设项目想用上最新的技术&#xff0c;不妨看看学长的这篇文章&#xff0c;学长带大家简单的…

GitHub上8个强烈推荐的 Python 项目

文章目录 前言1. Manim2. DeepFaceLab3. Airflow4. GPT-25. XSStrike6. 谷歌图片下载7. Gensim8. SocialMapper总结关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③…

Vue3-provide和inject

作用和场景&#xff1a;顶层组件向任意的底层组件传递数据和方法&#xff0c;实现跨层组件通信 跨层传递普通数据&#xff1a; 1.顶层组件通过provide函数提供数据 2.底层组件通过inject函数获取数据 既可以传递普通数据&#xff0c;也可以使用ref传递响应式数据&#xff08…

WorkPlus即时通讯,打通上下游产业链,构建企业生态圈

如今&#xff0c;随着信息技术的迅速发展&#xff0c;智慧水务、智慧医疗、智慧城市、智慧教育、智慧政务等领域正蓬勃发展。在这个智慧时代&#xff0c;企业需要一个具备开放性和扩展性的平台级产品&#xff0c;以满足多样化的业务需求。WorkPlus作为一款全新的移动底座产品&a…

Linux应用开发基础知识——I2C应用编程(十二)

前言&#xff1a; I2C&#xff08;Inter-Integrated Circuit BUS&#xff09;是集成电路总线&#xff0c;是目前应用最广泛的总线之一&#xff0c;最初由PHILIPS&#xff08;现为NXP&#xff09;设计。它使用多主从架构&#xff0c;主要用于连接低速周边设备。I2C总线在硬件物理…