本地缓存和分布式缓存有何区别?

缓存是提高服务性能的一把利剑,尤其在高并发、高请求量的服务中性能提升明显。如果后端服务只靠关系型数据库提供支撑,系统会很快达到处理瓶颈。缓存设计无处不在,通常来说可以分为本地缓存与分布式缓存。本地缓存框架主要有Guava cache、Caffeine等,它们利用本地服务器内存来存储接口的返回数据。本地缓存有一定的局限性,多个进程间不能共享缓存,且缓存都是单机保存不容易扩展,本地机器宕机后缓存不能持久化。相对于本地缓存,分布式缓存可以解决本地缓存存在的问题,缓存数据集中存储并可以被后端服务共享访问,对于缓存数据还可以进行副本存储,做到持久化存储。不过引入分布式缓存也会带来一些运维成本,还有数据不一致等问题。总体来说,分布式缓存可以提高服务性能,减少后端服务的压力,收益大于成本。通常分布式缓存组件有Redis、Couchbase等本节主要以Redis组件介绍为主。

本地缓存

本地缓存是指将数据缓存在应用程序所在的服务器或客户端的内存中。本地缓存通常是以键值对的形式存储数据,其中键用于唯一标识数据,值则是实际的缓存数据。下面是一些常见的本地缓存的特点:

  • 快速访问速度:本地缓存位于应用程序所在的内存中,访问速度非常快,可以显著减少对后端数据源的访问。

  • 单节点存储:本地缓存通常只存储在一个节点中,多个应用实例之间无法共享缓存数据。

  • 有限容量:本地缓存的容量受到内存大小的限制,一旦超过容量限制,可能会导致性能下降或者数据丢失。

本地缓存适用于以下场景:

  • 热点数据缓存:将常用的、对应用程序性能影响较大的数据缓存在本地,提高访问速度,减少对后端数据源的压力。

  • 临时数据存储:将临时生成的数据缓存在本地,避免频繁访问后端系统。

分布式缓存

分布式缓存是指将缓存数据分散存储在多个节点上,这些节点可以分布在不同的服务器或者网络中。分布式缓存通过将数据分片存储在多个节点上,提高了缓存的容量和可扩展性。下面是一些常见的分布式缓存的特点:

  • 数据共享与复制:分布式缓存部分数据会被复制到多个节点上,以提高数据的可靠性和可用性。

  • 高扩展性:分布式缓存可以根据需求动态添加和删除节点,以适应数据量的变化和访问负载的增加。

  • 网络开销:由于分布式缓存需要在网络上进行数据传输,可能会增加额外的网络开销,导致访问速度略低于本地缓存。

分布式缓存适用于以下场景:

  • 海量数据缓存:当应用程序需要缓存大量数据时,本地缓存的容量可能无法满足需求,这时可以使用分布式缓存来扩展缓存容量。

  • 高并发访问:当应用程序需要处理大量并发请求时,本地缓存的性能可能受到限制,这时可以使用分布式缓存来分担访问负载。

本地缓存 JDK Map

JDK Map 经常用于缓存实现:

  • HashMap

    HashMap 是一种基于哈希表的集合类,它提供了快速的插入、查找和删除操作。可以将键值对作为缓存项的存储方式,将键作为缓存项的唯一标识符,值作为缓存项的内容。

  • ConcurrentHashMap

    ConcurrentHashMap 是线程安全的 HashMap,它在多线程环境下可以保证高效的并发读写操作。

  • LinkedHashMap

    LinkedHashMap 是一种有序的 HashMap ,它保留了元素插入的顺序,可以按照插入顺序或者访问顺序进行遍历。

  • TreeMap

    TreeMap 是一种基于红黑树的有序 Map,它可以按照键的顺序进行遍历。

应用场景: 红包活动存储在 ConcurrentHashMap 中 ,通过定时任务刷新缓存 。

核心流程:

1、红包系统启动后,初始化一个 ConcurrentHashMap 作为红包活动缓存 ;

2、数据库查询所有的红包活动 , 并将活动信息存储在 Map 中 ;

3、定时任务每隔 30 秒 ,执行缓存加载方法,刷新缓存。

为什么红包系统会将红包活动信息存储在本地内存 ConcurrentHashMap 呢 ?

  • 红包系统是高并发应用,快速将请求结果响应给前端,大大提升用户体验;

  • 红包活动数量并不多,就算全部放入到 Map 里也不会产生内存溢出的问题;

  • 定时任务刷新缓存并不会影响红包系统的业务。

笔者见过很多单体应用都使用这种方案,该方案的特点是简洁易用,工程实现也容易 。

本地缓存框架 

虽然使用 JDK Map 能快捷构建缓存,但缓存的功能还是比较孱弱的。

因为现实场景里,我们可能需要给缓存添加缓存统计过期失效淘汰策略等功能。

于是,本地缓存框架应运而生。

流行的 Java 缓存框架包括:Ehcache , Google Guava ,  Caffeine Cache 。

虽然本地缓存框架的功能很强大,但是本地缓存的缺陷依然明显。

1、高并发的场景,应用重启之后,本地缓存就失效了,系统的负载就比较大,需要花较长的时间才能恢复;

2、每个应用节点都会维护自己的单独缓存,缓存同步比较头疼

分布式缓存之Redis

    Redis是一个开源的、基于内存的Key-Value缓存数据库。Redis因其丰富的数据类型、高性能I/O、串行执行命令、数据持久化等特性而流行开来,Redis非常适合做分布式缓存数据库。Redis有5种基本数据类型:

lString:字符串类型,是Redis中最常用的数据类型。Key与Value都有一定的大小限制,如果太大会影响性能。字符串类型通常可以保存sessionId等信息,在计算器、分布式锁、全局ID等这类场景中使用。

lHash:哈希类型,类似JAVA中的HashMap这种数据结构。哈希类型的底层数据结构有ziplist和hashtable,当哈希类型元素个数小于配置限制以及值小于配置的限制时采用ziplist结构,否则使用hashtable结构。哈希类型通常可以保存一些配置信息,例如某个活动ID下的配置信息等。

lList:列表类型,底层包括两种实现:ziplist与linkedlist。列表类型通常用作消息队列来使用。

lSet:集合类型,底层实现是intset或hashtable。集合中元素不能重复,通常用作一类数据的集合来存储,例如社交媒体关注的“大V”集合等。

lSorted set:有序集合,底层实现包括ziplist或skiplist。有序集合常用场景主要是在有排序需求的地方,例如按销量排序的商品、热搜榜等。

其他数据类型包括:

lBitmap:位图类型,主要按位存储,可以按位进行计算。位图非常类似BloomFilter,可以判断某个值是否存在这种使用场景。

lHyperloglog:HyperLogLog主要的应用场景就是进行基数统计。

lGeo:主要存储地理位置信息数据。

  了解了Redis的一些数据结构类型,针对具体的场景选用不同的数据类型来使用。Redis虽然基于内存存储数据,但是也有持久化机制,将缓存数据持久化到磁盘上。Redis有两种持久化机制:RDB(Redis DataBase)和AOF(Append Only File)。RDB是每隔一定时间对Redis进行快照然后存储下来。AOF是将Redis的执行命令存储下来。相对来说RDB恢复数据更快,但是会丢失一定时间内的数据。AOF只会丢失最后执行的几条执行命令,所以恢复的数据更全一些。当然新的版本已经有RDB和AOF两种混合的持久化方式。

     Redis的在生产环境部署通常有几种模式:主从模式、哨兵模式以及集群模式。主从模式可以是一主多从,写缓存通过主库来操作,从库同步主库的数据并用来读取数据。哨兵模式是为了高可用,监控主库,当主库挂掉的时候,在从库中选择一个节点变为主库,这样避免了主库宕机不用使用的情况。Redis为了更好的扩展,提供了分片模式,设置了16384个槽,对缓存key进行hash计算,根据hash值分配到不同的槽与分片节点上。

    Spring Boot提供了对Redis的集成,提供了RedisTemplate类,完成Redis命令的执行,自动配置RedisTemplate代码如下:


public class RedisCacheConfiguration {

    /**
     * 配置Redis连接工厂
     */
    @Bean
    public JedisConnectionFactory getJedisConnectionFactory(RedisConfigProperties redisConfigProperties) {
        JedisConnectionFactory jedisConnectionFactory = null;
        try {
            RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(redisConfigProperties.getHost(),
                    redisConfigProperties.getPort());
            redisStandaloneConfiguration.setPassword(redisConfigProperties.getPassword());
            redisStandaloneConfiguration.setDatabase(redisConfigProperties.getDatabase());
            jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
            jedisConnectionFactory.getPoolConfig().setMaxTotal(50);
            jedisConnectionFactory.getPoolConfig().setMaxIdle(50);
            jedisConnectionFactory.getPoolConfig().setMaxWaitMillis(redisConfigProperties.getTimeout());
        } catch (RedisConnectionFailureException e) {
            e.getMessage();
        }
        return jedisConnectionFactory;
    }

    @Bean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
          return redisTemplate;
    }
}
 本地缓存与分布式缓存的比较

本地缓存和分布式缓存各有优缺点,根据具体的应用场景和需求选择合适的缓存方式。下面是它们在一些关键方面的比较:

  • 数据一致性:本地缓存通常可以提供更高的数据一致性,因为数据存储在一个节点中。而分布式缓存由于数据复制和网络传输等原因,可能会导致一定的数据不一致性。

  • 容量和可扩展性:本地缓存的容量受限于内存大小,无法动态扩展。而分布式缓存可以通过添加或删除节点来动态调整容量,以适应数据量和访问负载的变化。

  • 访问速度:本地缓存由于位于内存中,访问速度非常快。而分布式缓存需要通过网络进行数据传输,可能略慢于本地缓存。

  • 可用性和容错性:本地缓存通常只存储在一个节点上,一旦节点故障,可能会导致缓存不可用。而分布式缓存利用数据复制和冗余机制,提高了系统的可用性和容错性。

  • 管理和维护成本:本地缓存相对简单,无需关注多个节点之间的数据同步和一致性。而分布式缓存需要进行节点管理和数据复制等操作,增加了管理和维护的成本。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值