作者个人研发在高并发场景下提供了一个简单、稳定、可扩展的延迟消息队列框架,具有精准的定时任务和延迟队列处理功能。开源半年多以来,已成功为十几家中小企业提供精准定时调度解决方案,经受住了生产环境的考验。为了造福更多的童鞋,这里给出开源框架的地址:https://github.com/sunshinelyz/mykit-delay写在前面,在启动项目的时候,并没有过多考虑性能问题,所以以快速迭代函数为主。随着业务的快速发展,系统的性能越来越慢。这时候就需要对系统进行相应的优化,最显着的效果就是给系统加了一个缓存。那么,问题来了,你在给系统添加缓存的时候,有没有考虑过在使用缓存的时候需要注意什么?缓存命中率缓存命中率是从缓存中读取数据的次数占总读取次数的比值。命中率越高越好。缓存命中率=从缓存读取/(总读取(从缓存读取+从慢速设备读取))。这是一个非常重要的监测指标。如果你做缓存,你应该监控这个指标,看看缓存是否正常工作。缓存类型一般来说,缓存类型可以分为:堆缓存、堆外缓存、磁盘缓存、分布式缓存。堆内存使用Java堆内存来存储对象。使用堆缓存的好处是没有序列化/反序列化,是最快的缓存。劣势也很明显。当缓存数据量很大时,GC(garbagecollection)暂停时间会变长,存储容量受堆空间大小限制。缓存对象一般都是通过软引用/弱引用来存储的。即当堆内存不足时,可以强制回收这部分内存,释放堆内存空间。一般使用堆缓存来存储热点数据。它可以使用GuavaCache、Ehcache3.x和MapDB来实现。堆外内存,即缓存的数据存放在堆外内存中,可以减少GC停顿时间(堆对象从堆中转出,GC扫描移动的对象更少),可以支持更多的缓存空间(只受机器内存大小限制),不受堆空间影响)。但是读取数据时需要序列化/反序列化。因此,它会比堆缓存慢很多。它可以用Ehcache3.x和MapDB来实现。磁盘缓存是指缓存的数据存储在磁盘上,JVM重启时数据仍然存在,而堆/堆外缓存数据会丢失,需要重新加载。它可以用Ehcache3.x和MapDB来实现。分布式缓存分布式缓存可以使用ehcache-clustered(搭配Terracottaserver)实现Java进程间分布式缓存。也可以使用Memcached和Redis来实现。使用分布式缓存时,有如下两种模式:单机模式:将最热的数据存储到堆缓存中,比较热的数据存储到堆外缓存中,非热数据存储到磁盘缓存中。集群模式:最热的数据存储到堆缓存,比较热的数据存储到外部缓存,所有数据存储到分布式缓存。缓存回收策略缓存的回收策略一般包括:基于空间的回收策略、基于容量(空间)的回收策略、基于时间的回收策略和基于对象引用的回收策略。Space-basedSpace-based是指为缓存设置存储空间。例如设置为10MB,当达到存储空间上限时,会按照一定的策略清除数据。基于容量意味着缓存设置了最大大小。当缓存的条目超过最大大小时,旧数据将根据一定的策略被删除。基于时间的TTL(TimeToLive):生存期,即缓存数据从创建到过期的一段时间(缓存数据无论在这段时间内是否被访问都会过期)。TTI(TimeToIdle):空闲期,即缓存的数据长时间没有被访问后移除缓存的时间。基于对象引用的软引用:如果一个对象是软引用,当JVM堆内存不足时,垃圾回收器可以回收这些对象。软引用适合缓存,这样当JVM堆内存不足时,可以回收这些对象,为强引用对象腾出一些空间,从而避免OOM。弱引用:垃圾回收器回收内存时,如果发现弱引用,会立即回收。弱引用的生命周期比软引用短。注意:只有在没有其他强引用对象引用弱/软引用对象的情况下,该引用才会在垃圾回收期间被回收。也就是说,如果一个对象(不是弱引用/软引用对象)引用了一个弱引用/软引用对象,那么这个弱引用/软引用对象在垃圾回收时是不会被回收的。回收算法使用基于空间和基于容量的缓存,通过一定的策略去除旧数据,通常包括:FIFO算法、LRU算法和LFU算法。FIFO(FirstInFirstOut):先进先出算法,即先放入缓存的先取出。LRU(LeastRecentlyUsed):最近最少使用的算法,从现在开始时间最久的被去掉。LFU(LeastFrequentlyUsed):最不常用的算法,将一定时间内使用次数(频率)最少的算法去掉。在实际应用中,大多数使用基于LRU的缓存。本文转载自微信公众号“冰河科技”,可通过以下二维码关注。转载本文请联系冰川科技公众号。
