传统的关系型数据库(如Mysql)不能适用于高并发的业务场景(典型的如秒杀场景),因为很容易造成数据库的被流量冲崩溃,随着缓存技术的出现可以很好的解决这个问题,如下图所示的缓存工作图:
将热点数据从数据库中预热加载到缓存中,当用户再次访问热点数据时是从内存中加载,减少了对数据库的访问量,解决了高并发场景下容易造成数据库宕机的问题。
缓存一方面是辅助应用系统应对高并发的场景,另一方面提高应用系统的性能,常见的缓存有分布式缓存(如Redis),还有本地缓存。
1、分布式缓存之Redis
(1)支持分布式
Redis是一个单独的中间件部署,在我们现在的分布式集群架构下如果要实现多个服务同时使用一个缓存服务的话,Redis可以很好的支持,如下图所示:
这种分布下,如果使用本地缓存是无法实现的,因为本地缓存是和单个JVM节点绑定的,通常会在分布式架构下下使用Redis。
(2)持久化功能
Redis是一个基于内存的key-value结构的数据库,如果在出现了异常重启或者断电之后,那么Redis里面数据会全部丢失,但是Redis提供了持久化的机制,如下所示:
Redis会根据我们设置好的持久化规则(AOF或RDB)将内存里面的数据持久化到磁盘里面,这样即使Redis出现了异常情况,通过磁盘中的备份数据可以恢复Redis中的数据。要保证缓存里面数据不会丢失的话,Redis就是一个很好的选择。
(3)Redis丰富的功能
Redis提供了丰富的数据结构以及相应的功能,常见的五个基本数据结构,像String、List、hash、set和Zset等,此外它还提供了一些高级实用的数据结构,如HyperLogLog、Bitmap、Geospatial等等。除了丰富的数据结构之外Redis支持主从复制、哨兵模式、集群模式。
2、本地缓存
(1)单节点
本地缓存是在单个服务里面的,多个服务之间的数据是不互通的,如下图所示:
如果只是想缓存一些变动不大的数据来提升系统的性能,那这个时候可以优先考虑使用本地缓存。
(2)高性能
本地缓存比Redis的性能还要高,Redis虽然是基于内存的数据库,但是数据的传输还是需要通过网络连接。如果只需要简单的数据缓存并要求性能还要高,那优先使用本地缓存更好。
(3)存储数据量有限
本地缓存是直接将数据缓存在本地应用里面的,那如果需要缓存的数据非常的多,此时就可能会导致应用系统OOM,所以本地缓存通常是缓存数量量较少的场景下使用。
3、Redis和本地缓存构建多级缓存
Redis的性能很高,但是单分片的Redis写入瓶颈在2w左右,读瓶颈在10w左右,为了支撑超高的并发,我们需要引入本地缓存来构建一个多级缓存系统,如下图所示:
如果数据库的数据发生变动,可以借助消息中间件来通知本地缓存变更数据,这样可以保证数据的最终一致性,如下图所示:
总结:
(1)本地缓存具有速度快(使用本地内存,访问速度非常快)、减少网络开销和降低服务器压力(分担服务器的数据访问压力,提高系统的整体稳定性)等特点。常见的本地缓存式实现有Ehcache、Caffeine和Guava Cache等。
(2)本地缓存可以和Redis一起构建一套多级缓存的系统,大大的提升了系统的并发能力。
(3)本地缓存可以应对Redis故障。如果Redis服务器发生故障,依赖Redis缓存的应用可能会受到影响,使用本地缓存可以在Redis故障时提供一层额外的数据保护来确保应用系统的稳定运行。
(4)本地缓存和Redis缓存的使用场景不同,如下整理的:
频繁读写并需要多个应用实例之间共享的数据,通常选择Redis或其他分布式缓存(如MemCache)是更好的选择。
对于不经常变更的数据推荐使用本地缓存,因为本地换粗可以提供更高的性能和更低的延迟,如用户会话信息、配置数据、元数据、不经常变更的热门数据等等。
对于关键数据或需要持久化保护的数据,选择Redis能够提供更好的数据保护和持久化支持。