前言
工作中对于一些常用配置文件,或者静态数据一般都会使用缓存来保存以便读取,比如java程序中一般会使用Map来做为缓存,或者其他第三方的缓存库,比如Ehcache等,而对于分布式工程而言,一般会使用redis这种缓存容器,访问的时候通过远程通信的手段来获取数据。下面来分析并比对以下这些缓存的优缺点。
本地缓存
本地缓存顾名思义就是在JVM进程中的缓存,一般使用LinkedHashMap来实现,因为LinkedHashMap提供了一个removeEldestEntry方法,重写该方法可以实现自己的缓存清除策略,这也就保证了缓存占用内存空间的可控性,不至于因为多缓存了东西而导致内存溢出。
优点:使用JVM本地内存,不需要开发者关注内存的管理,内存的开辟和回收都是JVM自动管理。
缺点:缓存内容只能单个进程访问。对于集群部署,可能同一个主机要部署多个相同的实例来提供服务,这需要每个实例冗余一份缓存数据,很占用内存,比如缓存一张表数据,三个进程就要缓存三份,相对应的主机内存中会有三份同样的数据。
分布式缓存
分布式缓存一般使用在分布式系统中,一般多个系统或者服务共享同一份缓存数据。常用的分布式缓存组件有:Redis,Memchched,Ehcache等。
优点:多个进程或者主机可以共享同一份缓存数据,对于宝贵的内存而言,节约了内存。
缺点:由于分布式缓存组件一般都是单独部署,访问的时候依赖网络传输,效率相对低下,不可靠(网络不可用时会导致缓存响应超时或断开)。
思考:
由于目前市场上主流的部署方案都是使用docker部署,一般多个docker容器会共享同一个主机的内存和磁盘,因此我有个大胆的想法,可不可以把JAVA程序要缓存的内容放到共享内存中,这样部署到同一个主机上的应用访问缓存时就可以直接读取共享缓存,这样对比上述的第一种本地缓存而言既节省了内存空间,又提高了访问效率(因为查看了资料,java程序访问堆外内存理论上来讲要比访问堆内存要快,原因是堆内存受GC影响,同时也受其他jvm内存管理策略的影响),对比第二种分布式缓存呢,虽然在内存使用上而言要冗余一部分(需要每个物理机缓存一份),但是同样的在访问速度上要快了一大截,并且不受网络质量和带宽的影响。
思路
1、java提供了Unsafe类可以直接操作主机内存。
2、开源程序JNA也提供了直接操作堆外内存的方式
3、共享内存通过c/c++实现,java程序通过JNI的方式去访问。
实现
目前还在假想阶段,但是我相信以上的思路肯定是没有问题,可能社区上或者公司内部已经有了很好的实现方案,希望读者有了解这方面的可以提供一些线索或资料。