终篇 支持JDK19虚拟线程的web框架,之五:兴风作浪的ThreadLocal( 二 )


终篇 支持JDK19虚拟线程的web框架,之五:兴风作浪的ThreadLocal

文章插图
  • 搞清楚以上问题后 , 自己的八卦之心就控制不住了:既然虚拟线程上的ThreadLocal问题这么严重 , 放眼Java世界的生态这么繁荣 , 那么多框架和库 , 那么...你们说
  1. 有没有哪个倒霉蛋掉进这个坑里去?
  2. 惨不惨?
  3. 从坑里爬出来没有?
  • 你别说 , 还真有...

终篇 支持JDK19虚拟线程的web框架,之五:兴风作浪的ThreadLocal

文章插图
踩坑勇士quarkus
  • 这位踩坑勇士 , 就是贯穿整个《支持JDK19虚拟线程的web框架》系列的quarkus , 来吧 , 一起围观quarkus踩坑 , 顺便学点知识
  • 先看quarkus官方文档《virtual-threads.adoc》 , 如下图

终篇 支持JDK19虚拟线程的web框架,之五:兴风作浪的ThreadLocal

文章插图
  • 我对上述内容的理解:
  1. quarkus的人发现:传统线程池模式改用虚拟线程后 , 性能提升明显 , 但是反应式框架改用虚拟线程后的提升并不明显 , 而且还会带来内存消耗过大的问题(看过前面ThreadLocal分析的您 , 此刻应该猜到原因了了 , 嘿嘿 , 您猜的没错)
  2. 如果您的应用对内存有较严要求 , quarkus官方建议您继续坚持(stick)使用反应式框架(这话中透露出浓浓的无可奈何 , 别催了 , 搞不定...)
  • 接下来官方就要甩锅了 , 有趣的是 , 这次接锅的并非JDK , 而是大名鼎鼎的...Netty
Netty的问题
  • 为什么是Netty接锅呢?
  • 首先 , Netty使用了Reactor线程模型 , 而Netty Reactor的核心是Event Loop , 下图来自《Netty in Action》,是处理web请求的内部架构图 , 

终篇 支持JDK19虚拟线程的web框架,之五:兴风作浪的ThreadLocal

文章插图
  • 那么 , 应该有多少个EventLoop线程呢?下图是Netty源码 , 默认值是CPU核数的2倍 , 看得出这是个很保守的数字

终篇 支持JDK19虚拟线程的web框架,之五:兴风作浪的ThreadLocal

文章插图
  • 从上面的架构图和代码可以看出 , Netty的反应式框架的核心是使用少量线程来分发web请求 , 这样的结果仅使用了少量线程资源就能高效处理事件
  • 也正式因为有了线程数不多这个前提 , 在对JSON做序列化处理时 , Netty放心的使用了ThreadLocal , 毕竟线程少 , 一个4核的CPU也才8个ThreadLocal , 毫无压力
  • 而且 , 为了更加高效 , Netty还对ThreadLoacal进行过改造 , 也就是他们自研的FastThreadLocal
  • 然后 , 时间一天天过去 , 终于等来了JDK19发布 , 
  • quarkus的反应式web服务模块底层就是Netty , 为了用上虚拟线程 , 他们动手了...咱们脑补一下吧 , 铺天盖地的虚拟线程线程 , 铺天盖地的FastThreadLocal对象 , 炸了吧您...Are U OK ?
  • 快乐之后 , 咱们还是要正视这个问题 , 表面上看是个坑 , 实际上是两种设计思路的冲突:
  1. 虚拟线程的特性类似golang的协程 , 很适合直接拿来处理高并发web请求 , 为每个请求分配一个虚拟线程 , 逻辑清晰直白 , 资源消耗又不高 , 典型的简单高效
  2. Netty的反应式模型 , 核心思路就是用少量线程高效分发大量请求 , 本身就很高效 , 而且就算优化 , 线程数也不是瓶颈

    经验总结扩展阅读