性能:Java开发分布式存储系统都有哪些常用的编码技巧?

PageCache 调优和 Direct IO

有以下三种情况,PageCache 无法起作用。

  1. 使用 FIleChannel 读写时,底层可能走 Direct IO,不走页缓存。
  2. 在内存有限或者不够用的时候,频繁换页,导致缓存命中率低。
  3. 大量随机读的场景,导致页缓存的数据无法命中。

有一种解决思路是:通过使用 Direct IO 来模拟实现 PageCahce 的效果。

新的思路是:可以绕过操作系统,直接使用通过自定义 Cache + Direct IO 来实现更细致、自定义的管理内存、命中和换页等操作,从而针对我们的业务场景来优化缓存策略,从而实现比 PageCache 更好的效果。

Direct IO 可以通过 JNA/JNI 调用 Native 方法实来实现。GitHub 上有封装好了 Java JNA 库,实现了 Java 的 Direct IO,直接就可以使用。有兴趣的话,你可以去研究一下这个 GitHub 项目:github.com/smacke/jayd...

FileChannel 和 mmap

java.nio 包中的 FileChannel 属于 NIO 的一种;mmap 是调用 FileChannel.map() 实例出来的一种特殊读写文件的方式,被称为内存映射。

FileChannel 大多数时候是和 ByteBuffer 打交道的,你可以将 ByteBuffer 理解为一个 byte\[\] 的封装类。ByteBuffer 是在应用内存中的,它和硬盘之间还隔着一层 PageCache。

FileChannel 写的时候经历了应用内存 -> PageCache -> 磁盘三个步骤。

mmap 是一个把文件映射到内存的操作,因此可以像读写内存一样读写文件。它省去了用户空间到内核空间的数据复制过程,从而提高了读写性能。

mmap 在内存充足、数据文件较小且相对固定的场景下,性能比 FileChannel 高。但它有这样几个缺点:

  1. 使用时必须先指定好内存映射的大小,并且一次 Map 的大小限制在 1.5G 左右。
  2. 是由操作系统来刷盘的,手动刷盘时间不好掌握。
  3. 回收非常复杂,需要手动释放,并且代码和实现很复杂。

直接内存(堆外)和堆内内存

堆内内存就是指 JVM 堆内部的内存空间,堆外就是指除了 JVM 堆以外的内存空间。

关于堆内内存和堆外内存的选择,有下面五点建议:

  1. 当需要申请大块的内存时,堆内内存会受到限制,可以尝试分配堆外内存。

  2. 堆外内存适用于生命周期中等或较长的对象。

  3. 堆内内存刷盘的过程中,还需要复制一份到堆外内存,多了一步,会降低性能。

  4. 创建堆外内存的消耗要大于创建堆内内存的消耗,所以当分配了堆外内存之后,要尽可能复用它。

  5. 可以使用池化 + 堆外内存的组合方式。比如代码中如果需要频繁 new byte\[\],就可以研究一下 ThreadLocal<ByteBuffer> 和 ThreadLocal<byte\[\]> 的使用机制。


此文章为11月Day18学习笔记,内容来源于极客时间《深入拆解消息队列 47 讲》

相关推荐
爱勇宝4 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
IT_陈寒8 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码9 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo9 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志10 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..10 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects10 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰10 小时前
一些基础和问题解决
后端
陈随易11 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN11 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp