性能: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 讲》

相关推荐
独泪了无痕3 小时前
Spring Data Redis 快速上手
spring boot·redis·后端
m0_639906947 小时前
Linux 操作系统入门:目录结构、服务排查常用命令、Shell 脚本基础
linux·运维·后端
holly就是我8 小时前
AI 编程助手为什么跑偏?用开源 ccglass 看清 Prompt、工具调用和 Token 消耗
人工智能·后端
鸿蒙开发8 小时前
共享 Schema 与 SchemaFactory
前端·后端·harmonyos
用户788477316348 小时前
小程序后端三选一:云开发、.NET WebAPI、Node,我按客户现状分了三种答案
后端
aiopencode8 小时前
局域网设备抓包怎么做?用 TraceEagle 抓电视、游戏机和 IoT 流量
后端·ios
智驭未来掌门人8 小时前
CLion 开发 Qt 项目的优势
后端
EnCi Zheng8 小时前
后端怎么把AI接口稳定安全低成本接进业务:超时重试、密钥隔离与成本熔断清单
人工智能·后端·安全·架构·api
Bazingga8 小时前
从一家酒店讲懂Docker
后端
南归北隐8 小时前
Spring AI Alibaba Graph框架实现MCP数据库查询实战
java·后端·spring ai·mcp·spring ai mcp