Java高性能系统缓存的最佳实践(上)

简介: Java高性能系统缓存的最佳实践

1 屈服于现实的磁盘



MQ都使用磁盘来存储消息。这样服务器下电也不会丢数据。绝大多数用于生产系统的服务器,都会使用多块磁盘组成磁盘阵列,这样即使其中的一块异常,也可把数据从其他磁盘中恢复。


另外磁盘也便宜,就可用较低成本,存储海量消息。所以,不仅仅是MQ,几乎所有存储系统的数据,都需保存到磁盘。


但磁盘读写很慢。SSD可读写几千次/s,若程序在处理业务请求时直接读写磁盘,假设处理每次请求需要读写3~5次,即使每次请求数据量不大,程序最多也就能处理1000次/s左右请求。


而内存随机读写速度是磁盘10万倍!内存作为缓存来加速程序访问速度,是所有高性能系统都会采用的方案。


缓存思想简单,就是把低速存储的数据,复制一份放到高速存储,加速数据访问。使用也简单



在做业务系统时,在一些执行较慢方法上加个@Cacheable

image.png



2 缓存最佳实践

采用@Cacheable注解缓存的命中率如何?

怎样才能提高缓存命中率?

缓存是否总能返回最新的数据?

如果缓存返回了过期的数据该怎么办?



只读缓存 VS 读写缓存


唯一区别:更新数据时,是否经过缓存。


Kafka使用的PageCache,是个典型的读写缓存。os会利用系统空闲物理内存给文件读写做缓存,这缓存叫做PageCache。应用程序在写文件时,os会先把数据写入PageCache,成功写进后,对于用户代码,写入就结束了。


然后,os再异步更新数据到磁盘。应用程序在读文件时,os是先尝试从PageCache查数据,找到就直接返回,找不到会触发一个缺页中断,然后os把数据从文件读取到PageCache,再返回给应用程序。

数据写到PageCache后,并不是同时写到磁盘,期间有个延迟。

os可保证即使程序异常退出,os也会把这部分数据同步到磁盘。但若服务器都突然掉下电,这部分数据就丢了。


读写缓存的设计,本身就不可靠,牺牲数据一致性换取性能。当然,程序可以调用sync等系统调用,强制操作系统立即把缓存数据同步到磁盘文件中去,但是该同步过程很慢,也失去了缓存的意义。


写缓存实现非常复杂。应用程序不停更新PageCache数据,os需记录哪些数据变化,同时还要在另外一个线程,把缓存中变化的数据更新到磁盘。

在提供并发读写同时异步更新数据,这过程要保证数据一致性,且有非常好性能,可为强人锁男。

所以不推荐使用读写缓存。


那为什Kafka可使用PageCache提升性能?

这由MQ特点决定。


MQ读写比例大致1:1,因大部分MQ都是一收一发。这种读写比例,只读缓存既无法给写加速,读加速也有限,并不能提升多少性能。

Kafka并不是只靠磁盘保证数据可靠性,它更依赖在不同节点上的多副本保证数据可靠性,这样即使某服务器掉电丢失一部分文件内容,也可从其他节点找到正确数据,不会丢消息。


而且PageCache读写缓存是os实现,Kafka只要按照正确姿势使用即可,不涉及实现复杂度问题。所以,Kafka其实在设计上,充分利用PageCache读写缓存的优势,且规避了PageCache一些劣势,达到很好效果。


和Kafka一样,大部分其他MQ,也会采用读写缓存加速消息写入,只是实现方式不同。


不同于MQ,大部分业务类程序,读写比都是严重不均衡,一般读频率远高于写数,一般都几倍到几十倍。使用只读缓存来加速系统才是明智选择。


设计只读缓存又该考虑哪些问题呢?


维护缓存数据时效性        


对只读缓存,缓存中数据源只有一个途径:磁盘。当数据需更新时,磁盘数据和缓存副本都需更新。在分布式系统中,除非是使用事务(性能差)或者一些分布式一致性算法(复杂)保证数据一致性。否则,由于节点宕机、网络传输故障等,是无法保证缓存中数据和磁盘中的数据完全一致的。


若出现数据不一致,数据一定是以磁盘上那份拷贝为准的。

需解决问题:尽量让缓存数据与磁盘数据保持同步。


何时更新缓存数据

在更新磁盘数据同时,更新下缓存数据不就行?想法没任何问题,缓存中数据会一直保持最新。但在并发环境,实现起来不太容易

目录
相关文章
|
2月前
|
Java 测试技术 API
Java Stream API:被低估的性能陷阱与优化技巧
Java Stream API:被低估的性能陷阱与优化技巧
368 114
|
4月前
|
机器学习/深度学习 Java 编译器
解锁硬件潜能:Java向量化计算,性能飙升W倍!
编译优化中的机器相关优化主要包括指令选择、寄存器分配、窥孔优化等,发生在编译后端,需考虑目标平台的指令集、寄存器、SIMD支持等硬件特性。向量化计算利用SIMD技术,实现数据级并行,大幅提升性能,尤其适用于图像处理、机器学习等领域。Java通过自动向量化和显式向量API(JDK 22标准)支持该技术。
229 4
|
4月前
|
Cloud Native 前端开发 Java
WebAssembly 与 Java 结合的跨语言协作方案及性能提升策略研究
本文深入探讨了WebAssembly与Java的结合方式,介绍了编译Java为Wasm模块、在Java中运行Wasm、云原生集成等技术方案,并通过金融分析系统的应用实例展示了其高性能、低延迟、跨平台等优势。结合TeaVM、JWebAssembly、GraalVM、Wasmer Java等工具,帮助开发者提升应用性能与开发效率,适用于Web前端、服务器端及边缘计算等场景。
191 0
|
7月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
2月前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。
|
2月前
|
存储 缓存 Java
Java 12相比Java 11有哪些性能上的提升?
Java 12相比Java 11有哪些性能上的提升?
91 3
|
2月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
157 8
|
3月前
|
Java Spring
如何优化Java异步任务的性能?
本文介绍了Java中四种异步任务实现方式:基础Thread、线程池、CompletableFuture及虚拟线程。涵盖多场景代码示例,展示从简单异步到复杂流程编排的演进,适用于不同版本与业务需求,助你掌握高效并发编程实践。(239字)
257 6
|
3月前
|
缓存 Java 开发者
Java 开发者必看!ArrayList 和 LinkedList 的性能厮杀:选错一次,代码慢成蜗牛
本文深入解析了 Java 中 ArrayList 和 LinkedList 的性能差异,揭示了它们在不同操作下的表现。通过对比随机访问、插入、删除等操作的效率,指出 ArrayList 在多数场景下更高效,而 LinkedList 仅在特定情况下表现优异。文章强调选择合适容器对程序性能的重要性,并提供了实用的选择法则。
241 3
|
4月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
1667 10