SSL Session默认设置导致线程阻塞了几十秒的案例分析

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
可观测可视化 Grafana 版,10个用户账号 1个月
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: SSL Session默认设置导致线程阻塞了几十秒的案例分析

问题描述

几年前在做某学习APP的时候,评论服务(comment)访问评论后端服务(comment-server)正常RT在【几毫秒 ~ 几十毫秒】,偶尔(每隔几天)RT达到几十秒甚至几分钟,造成用户看不到评论列表,发表评论失败等不好的体验。

分析过程

系统交互关系

  • 网关与comment之间通讯协议是LWP(LaiWang Protocol)
  • comment与SLB之间通讯协议是https

comment调用comment-server超时?

在应用调用依赖服务的时候,会记录下【时间戳,依赖类别,调用的接口,响应时间,状态码】等指标信息。

通过监控及日志信息,出现问题的时候与SLB交互的RT是【452秒】,初步定位是【SLB】或【comment-server】处理慢导致的,所以联系了运维同学、负责【comment-server】的同学一起排查。

与SLB交互耗时

其中request_time:0.004秒,upstream_response_time:0.004秒

comment-server处理耗时

处理耗时【4毫秒】,看来锅是自己的😳。

Review代码

应用访问SLB使用的是Apache HttpClient,代码抽象表达如下:

这个代码哪里似乎有问题?

GC导致的阻塞?

通过查看GC Log,发现CMS GC耗时较长,与超时的时间点是能够对应上的,终于发现了线索。

发生CMS GC的时候,线程都在忙些什么呢?这时候LWP框架的线程dump起到了关键作用,下面对LWP简单做下介绍。

线程模型

LWP是一个RPC框架,网络通讯框架使用的是netty。

业务线程池

线程池初始化

拒绝策略

在线程blocked的时候,LWP框架打印出了当时的线程栈信息,发现所有业务线程都阻塞在了SSL交互过程中。

问题根因

SSLSessionContext’s ssl session缓存(which is a SoftReference cache) 超时时间默认是86400s (24小时),ssl session缓存大小默认是没有限制的,导致CMS GC处理SoftReference的时候耗时较长导致的。

算是JDK的一个Bug,如下:

解决办法

设置SSLContext实例的sessionCacheSize、sessionTimeout,示例:

sslContext.getClientSessionContext().setSessionCacheSize(1024);
sslContext.getClientSessionContext().setSessionTimeout(60);

不仅https,对于使用SSL通讯的应用同样需要注意上面的问题。

参考资料

相关实践学习
SLB负载均衡实践
本场景通过使用阿里云负载均衡 SLB 以及对负载均衡 SLB 后端服务器 ECS 的权重进行修改,快速解决服务器响应速度慢的问题
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
目录
相关文章
|
27天前
|
存储 NoSQL Redis
Redis 新版本引入多线程的利弊分析
【10月更文挑战第16天】Redis 新版本引入多线程是一个具有挑战性和机遇的改变。虽然多线程带来了一些潜在的问题和挑战,但也为 Redis 提供了进一步提升性能和扩展能力的可能性。在实际应用中,我们需要根据具体的需求和场景,综合评估多线程的利弊,谨慎地选择和使用 Redis 的新版本。同时,Redis 开发者也需要不断努力,优化和完善多线程机制,以提供更加稳定、高效和可靠的 Redis 服务。
31 1
|
1月前
线程CPU异常定位分析
【10月更文挑战第3天】 开发过程中会出现一些CPU异常升高的问题,想要定位到具体的位置就需要一系列的分析,记录一些分析手段。
61 0
|
23天前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
15 1
|
2月前
|
安全 Java 调度
python3多线程实战(python3经典编程案例)
该文章提供了Python3中多线程的应用实例,展示了如何利用Python的threading模块来创建和管理线程,以实现并发执行任务。
39 0
|
2月前
|
并行计算 API 调度
探索Python中的并发编程:线程与进程的对比分析
【9月更文挑战第21天】本文深入探讨了Python中并发编程的核心概念,通过直观的代码示例和清晰的逻辑推理,引导读者理解线程与进程在解决并发问题时的不同应用场景。我们将从基础理论出发,逐步过渡到实际案例分析,旨在揭示Python并发模型的内在机制,并比较它们在执行效率、资源占用和适用场景方面的差异。文章不仅适合初学者构建并发编程的基础认识,同时也为有经验的开发者提供深度思考的视角。
|
3月前
|
存储 监控 Java
|
3月前
|
安全 Java 开发者
Swing 的线程安全分析
【8月更文挑战第22天】
61 4
|
3月前
|
Java 数据库连接 数据库
当线程中发生异常时的情况分析
【8月更文挑战第22天】
100 4
|
3月前
|
安全 Java 程序员
线程安全与 Vector 类的分析
【8月更文挑战第22天】
50 4
|
2月前
|
安全 Java API
Java线程池原理与锁机制分析
综上所述,Java线程池和锁机制是并发编程中极其重要的两个部分。线程池主要用于管理线程的生命周期和执行并发任务,而锁机制则用于保障线程安全和防止数据的并发错误。它们深入地结合在一起,成为Java高效并发编程实践中的关键要素。
30 0