缓存是介入应用程序和物理数据之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高应用的运行性能。
缓存内的数据对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻会同步缓存数据和物理数据源的数据。
比如我们通常是直接查询MySQL数据库,那么在高并发情况下,大量查询MySQL数据库会导致数据库性能变慢。
因此我们在应用层与MySQL之间搭建一个Cache层,让请求先访问Cache,这样能大大的降低数据库的压力,提高性能
。
简单来说,缓存系统能跨进程我们就称为分布式缓存
在分布式系统开发中,系统与系统之间都是属于进程级别,缓存系统也能跨进程叫分布式缓存,市面上分布式技术有Memcached
和Redis
这两种,二者区别大致如下:
使用Redis做缓存的话,数据的存储结构有两种,一种采用String
存储,另外使用Hashes
存储。
那使用哪种更好呢?得具体情况具体分析:
Hashes
会更好,而且存储的时候没有序列化开销。Hashes
如果缓存(异常)清空了,或者时间失效设计的不合理导致缓存删除,一下子突然千万用户访问进来导致数据库崩溃(应用宕机)
缓存常见的三大经典问题:缓存击穿、缓存穿透、缓存雪崩
存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。
当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。
就是明知道这个Key不在缓存,也不在数据库里,请求大量的这种导致数据库压力剧增。
当大量缓存数据在同一时间过期(失效) 或者 Redis 故障宕机 时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增
,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。
其实最致命的是Redis节点故障,如果那个节点出问题访问不了缓存,那么数据的请求全怼在数据库里,造成数据库崩溃。
解决方法:
我们的redis数据库最大缓存、主键失效、淘汰机制等参数都是可以通过配置文件来配置的。
这个文件是我们的redis.conf
文件。
maxmemory : 设置最大内存
#比如 maxmemory 500mb
超过最大的内存,就会采用内存淘汰策略,执行淘汰,如下。
截止目前redis一共为我们提供了八个不同的内存置换策略,很早之前提供了6种。
# volatile-lru -> Evict using approximated LRU, only keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU, only keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key having an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
#
# LRU means Least Recently Used
# LFU means Least Frequently Used
#
# Both LRU, LFU and volatile-ttl are implemented using approximated
# randomized algorithms.
#
# Note: with any of the above policies, Redis will return an error on write
# operations, when there are no suitable keys for eviction.
#
# At the date of writing these commands are: set setnx setex append
# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
# getset mset msetnx exec sort
#
# The default is:
#
# maxmemory-policy noeviction
默认不淘汰 , 开发中经常使用的是volatile-lru
注意这里的6种机制,volatile和allkeys规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略
使用策略规则:
如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用 allkeys-lru
如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用 allkeys-random
既然是淘汰,那就需要把这些数据给删除,然后保存新的
Redis删除策略主要有以下几种: