引言
大概整理掌握了Redis一些初步的概念性知识,这一篇的基本上结束Redis的大部分知识介绍。没看一篇的建议看一下 Redis 初级篇。一篇主要是理论。这一篇稍微深一些。实战性更多一些。
接下来预计出一些Redis深入浅出类文章比如SDS动态字符串。
背景
Redis迭代背景就是从 ①单机时代 ②Mecaded缓存+MySQL+垂直拆分 ③分库分表+水平拆分+MySQL集群 ④多用户访问时代(还能抗住) ⑤用户量剧增增加缓存层保护数据库 ⑥用户量爆发式增长单台无法满足用户要求 ⑦Redis集群(哨兵模式)
NoSQL
了解Redis之前有必要了解一下NoSQL,数据库分关系型数据库,非关系型数据库。NoSQL是比较特殊的它是既包含关系型也包含非关系型所有是非常有必要了解一下的。优点: 数据之前无关系,很好扩展。大数据量情况下高性能优势。数据量是多样型的,不需要事先设计,随取随用实战应用: 实战应用的时候肯定不可能只用一种数据库,一般都是MySQL+NoSQL配合使用。分类: kv键值对,文档型数据库,列存储,图关系数据库
五大常用数据类型
验证服务连接
[root@iZ2zebzs5dnocz7mu3p6wnZ bin]# redis-cli -p 6379 127.0.0.1:6379> ping PONG
String
应用: 关注数,浏览量,点击量等数据临时存储操作
set get 命令操作数据存取
127.0.0.1:6379> get demo (nil) 127.0.0.1:6379> set demo huanshao OK 127.0.0.1:6379> get demo "huanshao" 127.0.0.1:6379> set demo1 nb OK 127.0.0.1:6379> keys* (error) ERR unknown command `keys*`, with args beginning with: 127.0.0.1:6379> keys * 1) "\xac\xed\x00\x05t\x00\x04Demo" 2) "demo" 3) "demo1"
判断key是否存在
127.0.0.1:6379> exists demo (integer) 1 127.0.0.1:6379> exists demo2 (integer) 0 127.0.0.1:6379> type demo string
设置获取key过期时间
127.0.0.1:6379> setex demo2 30 wc OK 127.0.0.1:6379> ttl demo2 (integer) 25 127.0.0.1:6379> ttl demo2 (integer) 21 127.0.0.1:6379> keys * 1) "\xac\xed\x00\x05t\x00\x04Demo" 2) "demo" 3) "demo1" 127.0.0.1:6379> get demo1 "nb"
key-value值追加 类似于Java中的append
127.0.0.1:6379> append demo1 lth (integer) 5 127.0.0.1:6379> get demo1 "nblth"
value值替换
127.0.0.1:6379> get demo1 "nblth" 123.56.240.222:6379> setrange demo1 2 S (integer) 5 123.56.240.222:6379> get demo1 "nbSth"
判断是否存在,如果不存在就创建
123.56.240.222:6379> keys * 1) "\xac\xed\x00\x05t\x00\x04Demo" 2) "demo" 3) "demo1" 123.56.240.222:6379> setnx demo2 LTH (integer) 1 123.56.240.222:6379> keys * 1) "\xac\xed\x00\x05t\x00\x04Demo" 2) "demo" 3) "demo1" 4) "demo2" 123.56.240.222:6379> get demo2 "LTH"
批量操作数据 插入 批量获取 取出
123.56.240.222:6379> mset hs1 5 hs2 6 OK 123.56.240.222:6379> keys * 1) "hs2" 2) "\xac\xed\x00\x05t\x00\x04Demo" 3) "demo" 4) "demo2" 5) "hs1" 6) "demo1" 123.56.240.222:6379> mget hs1 hs2 1) "5" 2) "6"
数值计算
123.56.240.222:6379> incr hs1 (integer) 6 123.56.240.222:6379> get hs1 "6" 123.56.240.222:6379> decr hs2 (integer) 5 123.56.240.222:6379> get hs2 "5" 123.56.240.222:6379> get hs1 "6" 123.56.240.222:6379> get hs2 "5" 123.56.240.222:6379> incrby hs1 4 (integer) 10 123.56.240.222:6379> get hs1 "10" (0.81s) 123.56.240.222:6379> decrby hs2 3 (integer) 2 123.56.240.222:6379> get hs2 "2" 123.56.240.222:6379> keys * 1) "hs2" 2) "\xac\xed\x00\x05t\x00\x04Demo" 3) "demo" 4) "demo2" 5) "hs1" 6) "demo1"
清空数据
123.56.240.222:6379> flushdb OK 123.56.240.222:6379> keys * (empty array)
保证原子性 要么成功 要么失败
123.56.240.222:6379> msetnx k1 v1 k2 v2 (integer) 1 123.56.240.222:6379> keys * 1) "k1" 2) "k2" 123.56.240.222:6379> flushdb OK 123.56.240.222:6379> keys * (empty array)
如果不存在值就返回nill,并创建
123.56.240.222:6379> getset k3 v3 (nil) 123.56.240.222:6379> get k3 "v3"
切换数据库 获取数据库大小
123.56.240.222:6379> dbsize (integer) 1 123.56.240.222:6379> select 2 OK 123.56.240.222:6379[2]> keys * (empty array) 123.56.240.222:6379[2]> select 1 OK 123.56.240.222:6379[1]> select 1 OK 123.56.240.222:6379[1]> keys * (empty array) 123.56.240.222:6379[1]> select 0 OK 123.56.240.222:6379> keys * 1) "k3"
List
应用: 关注列表,热点数据列表,分析数据列表等 数据放入list集合 获取List集合中的数据
123.56.240.222:6379> keys * 1) "k3" 123.56.240.222:6379> flushdb OK 123.56.240.222:6379> keys * (empty array) 123.56.240.222:6379> lpush mylist lth (integer) 1 123.56.240.222:6379> lpush mylist jia (integer) 2 123.56.240.222:6379> lpush mylist you (integer) 3 123.56.240.222:6379> lrange mylist 0-1 (error) ERR wrong number of arguments for 'lrange' command 123.56.240.222:6379> lrange mylist 0 -1 1) "you" 2) "jia" 3) "lth" 123.56.240.222:6379> lrange mylist 0 1 1) "you" 2) "jia" 123.56.240.222:6379> rpush mylist xiaofang (integer) 4 123.56.240.222:6379> lrange mylist 0 1 1) "you" 2) "jia" 123.56.240.222:6379> lrange mylist 0 -1 1) "you" 2) "jia" 3) "lth" 4) "xiaofang"
根据下标获取数据 获取数据长度
123.56.240.222:6379> lindex mylist 1 "lth" 123.56.240.222:6379> llen mylist (integer) 2 123.56.240.222:6379> lrange mylist 0 -1 1) "jia" 2) "lth"
移出list数据
123.56.240.222:6379> lpush mylist xiaofang (integer) 3 123.56.240.222:6379> lpush mylist mao rpop lth (integer) 6 123.56.240.222:6379> lrange mylist 0 -1 1) "lth" 2) "rpop" 3) "mao" 4) "xiaofang" 5) "jia" 6) "lth" 123.56.240.222:6379> lpush mylist sql (integer) 7 123.56.240.222:6379> lrange mylist 0 -1 1) "sql" 2) "lth" 3) "rpop" 4) "mao" 5) "xiaofang" 6) "jia" 7) "lth" 123.56.240.222:6379> rpop mylist 1 1) "lth" 123.56.240.222:6379> flushdb OK 123.56.240.222:6379> lrange mylist 0 -1 (empty array)
模拟 栈与队列
lpush rpop 队列 lpush lpop 栈
Set
应用: 无序,不支持重复存储。主要通过交并差集操作实现一些类似于微博的共同好友,共同粉丝,随机事件,抽奖,选名等功能
差价 set 数据
123.56.240.222:6379> sadd myset lth (integer) 1 123.56.240.222:6379> sadd myset lth (integer) 0 123.56.240.222:6379> sadd myset hs (integer) 1
获取set数据,判读集合是否存在这个key
123.56.240.222:6379> smembers myset 1) "hs" 2) "lth" 123.56.240.222:6379> sismember myset hs (integer) 1 123.56.240.222:6379> sismember myset hss (integer) 0
获取set大小
123.56.240.222:6379> smembers myset 1) "hs" 2) "xiaofang" 3) "lth" 123.56.240.222:6379> scard myset (integer) 3
set 移出元素
123.56.240.222:6379> srem myset lth (integer) 1 123.56.240.222:6379> smembers myset 1) "hs" 2) "xiaofang"
随机取出一个set元素
123.56.240.222:6379> smembers myset 1) "hs" 2) "xiaofang" 123.56.240.222:6379> srandmember myset "xiaofang" 123.56.240.222:6379> srandmember myset "xiaofang" 123.56.240.222:6379> srandmember myset "xiaofang" 123.56.240.222:6379> srandmember myset "hs"
随机删除一个元素
123.56.240.222:6379> spop myset 1 1) "hs" 123.56.240.222:6379> smembers myset "xiaofang"
创建新集合 取集合的交集
123.56.240.222:6379> keys * 1) "youset" 2) "myset" (0.82s) 123.56.240.222:6379> smembers youset 1) "xiaohuan" 123.56.240.222:6379> smembers myset 1) "xiaofang" 123.56.240.222:6379> sadd youset xiaofang (integer) 1 123.56.240.222:6379> smembers youset 1) "xiaofang" 2) "xiaohuan" 123.56.240.222:6379> smembers myset 1) "xiaofang" 123.56.240.222:6379> sdiff youset myset 1) "xiaohuan"
取集合差集
123.56.240.222:6379> smembers youset 1) "xiaofang" 2) "xiaohuan" 123.56.240.222:6379> smembers myset 1) "xiaofang" 123.56.240.222:6379> sinter myset youset 1) "xiaofang"
取集合并集
123.56.240.222:6379> sunion youset myset 1) "xiaohuan" 2) "xiaofang"
Hash
应用: 因为它的映射关系的特性,特别适合存一些存储对象。比如用户详情,商品详情,订单详情等。
set get 哈希数据
123.56.240.222:6379> hset myhash name lth (integer) 1 123.56.240.222:6379> hset myhash age 18 (integer) 1 123.56.240.222:6379> hget myhash name "lth" 123.56.240.222:6379> hget myhash age "18"
获取全部值
123.56.240.222:6379> hgetall myhash 1) "name" 2) "lth" 3) "age" 4) "18"
批量获取多个 filed
123.56.240.222:6379> hmget myhash name age 1) "lth" 2) "18"
删除当前myhash的 name字段
123.56.240.222:6379> hdel myhash name (integer) 1 123.56.240.222:6379> hgetall myhash 1) "age" 2) "18"
获取hash长度
123.56.240.222:6379> hlen myhash (integer) 1 123.56.240.222:6379> hset myhash name lll (integer) 1 123.56.240.222:6379> hlen myhash (integer) 2
判断当前myhash这个key 以及myhash内的name字段是否存在
123.56.240.222:6379> hexists myhash name (integer) 1 123.56.240.222:6379> hexists myhash names (integer) 0
获取所有的key以及获取所有的value数值
123.56.240.222:6379> hkeys myhash 1) "age" 2) "name" 123.56.240.222:6379> hvals myhash 1) "18" 2) "lll"
给myhash这个key的 age字段 加3
123.56.240.222:6379> hincrby myhash age 3 (integer) 21
判断是否存在wight这个字段,如果不存在就创建
123.56.240.222:6379> hsetnx myhash wight 160 (integer) 1 123.56.240.222:6379> hkeys myhash 1) "age" 2) "name" 3) "wight"
ZSet
应用: 主要用于一些直播系统中的实时排名信息。包括在线用户列表,礼物排行列表,弹幕消息列表等功能。
添加数据,遍历数据
127.0.0.1:6379> zadd myzset 1 lth (integer) 1 127.0.0.1:6379> zadd myzset 2 xf (integer) 1 127.0.0.1:6379> zrange myzset (error) ERR wrong number of arguments for 'zrange' command 127.0.0.1:6379> zrange myzset 0 -1 1) "lth" 2) "xf"
批量添加数据
127.0.0.1:6379> zadd myzset 3 zsq 4 zyn (integer) 2 127.0.0.1:6379> zrange myzset 1 -1 1) "xf" 2) "zsq" 3) "zyn" 127.0.0.1:6379> zrange myzset 0 -1 1) "lth" 2) "xf" 3) "zsq" 4) "zyn"
查询zset集合中的区间范围值
127.0.0.1:6379> zrange myzset 0 -1 1) "lth" 2) "xf" 3) "zsq" 4) "zyn" 127.0.0.1:6379> zrangebyscore myzset -inf +inf 1) "lth" 2) "xf" 3) "zsq" 4) "zyn" 127.0.0.1:6379> zrangebyscore myzset -inf +inf withscores 1) "lth" 2) "1" 3) "xf" 4) "2" 5) "zsq" 6) "3" 7) "zyn" 8) "4"
获取zset中范围内的成员数量
127.0.0.1:6379> zcount myzset 1 2 (integer) 2 127.0.0.1:6379> zcount myzset 1 3 (integer) 3
从大到小排序
127.0.0.1:6379> zrevrange myzset 0 -1 1) "zyn" 2) "zsq" 3) "xf" 4) "lth"
获取zset元素中的个数
127.0.0.1:6379> zcard myzset (integer) 4
三大特殊类型
Geospatial
应用: 地理位置查询距离,附近人,外卖派送距离测试网站:经纬度距离测试
添加地理位置
127.0.0.1:6379> geoadd china:city 116.4 39.9 beijing (integer) 1 127.0.0.1:6379> geoadd china:city 119.9 34.7 changzhou (integer) 1 127.0.0.1:6379> geoadd china:city 120.2 31.5 wuxi (integer) 1 127.0.0.1:6379> geoadd china:city 120.1 30.3 hangzhou (integer) 1
获取添加后的北京位置
127.0.0.1:6379> geopos china:city beijing 1) 1) "116.39999896287918091" 2) "39.90000009167092543"
获取两个城市之间的距离
127.0.0.1:6379> geodist china:city changzhou wuxi km "357.0194"
寻找方圆半径 110 30中 1000千米的数据
127.0.0.1:6379> geodist chain:city changzhou wuxi km (nil) 127.0.0.1:6379> geodist china:city changzhou wuxi km "357.0194" 127.0.0.1:6379> georadius china:city 110 30 400 km (empty array) 127.0.0.1:6379> georadius china:city 110 30 500 km (empty array) 127.0.0.1:6379> georadius china:city 110 30 100 km (empty array) 127.0.0.1:6379> georadius china:city 110 30 1000 km 1) "hangzhou" 2) "wuxi"
找出任何指定元素周围的其他元素。这里指令的意思就是以常州为主找出方圆400千米的城市
127.0.0.1:6379> georadiusbymember china:city changzhou 400 km 1) "changzhou" 2) "wuxi"
BitMaps
应用: 打卡,签到,只存在两种状态的都可以使用这个。
设置状态
127.0.0.1:6379> setbit signs 0 0 (integer) 0 127.0.0.1:6379> setbit signs 1 0 (integer) 0 127.0.0.1:6379> setbit signs 2 1 (integer) 0 127.0.0.1:6379> setbit signs 2 1 (integer) 1 127.0.0.1:6379> setbit signs 3 1 (integer) 0 127.0.0.1:6379> setbit signs 4 1 (integer) 0 127.0.0.1:6379> setbit signs 5 1 (integer) 0 127.0.0.1:6379> setbit signs 6 1 (integer) 0
取状态的个数
127.0.0.1:6379> bitcount signs (integer) 5
Hayperloglog
应用: 这个类型占用的内存的特别小的。所以可以考虑一下这个。如果允许容错,非常建议使用
添加元素
127.0.0.1:6379> pfadd haplog hs (integer) 1 127.0.0.1:6379> pfadd haplog lth (integer) 1 127.0.0.1:6379> pfadd haplog xf (integer) 1 127.0.0.1:6379> pfcount haplog (integer) 3
合并两组数据不重复
127.0.0.1:6379> pfadd haplogs xxxlll (integer) 1 127.0.0.1:6379> pfmerge haplog haplogs OK 127.0.0.1:6379> keys * 1) "haplog" 2) "haplogs" 127.0.0.1:6379> pfcount haplog (integer) 4 127.0.0.1:6379> pfcount haplogs (integer) 1
Config文件介绍
Redis的单位大小写是不敏感的,不区分
units are case insensitive so 1GB 1Gb 1gB are all the same.
可以包含多个配置文件,当搭建集群的时候用的这个这个
# include /path/to/local.conf # include /path/to/other.conf
网关的配置,配置IP地址的,保护模式,端口号
# bind 192.168.1.100 10.0.0.1 # listens on two specific IPv4 addresses # bind 123.56.240.222 # listens on loopback IPv4 and IPv6 # protected-mode yes # port 6379
通用配置 以守护线程方式进行,也就是说 后台运行还是前台运行的区别,第二个是管理守护进程的
daemonize yes supervised no
如果以后台运行的话,必须指定一个pid文件。pid文件的作用是防止启动多个进程副本。原理是进程运行后会给.pid文件加一个文件锁,只有获得该锁的进程才有写入权限(F_WRLCK),把自身的pid写入该文件中。其他试图获得该锁的进程会自动退出。日志等级
日志的级别主要分为 notic,debug,verbose,warning Redis默认的设置为verbose,开发测试阶段可以用debug,生产模式一般选用notice
- debug:会打印出很多信息,适用于开发和测试阶段
- verbose(冗长的):包含很多不太有用的信息,但比debug要清爽一些
- notice:适用于生产模式
- warning : 警告信息
日志文件路径
logfile /usr/local/redis/var/redis.log
数据库默认为16个,第二个意思为运行的时候不显示输出logo
databases 16 always-show-logo no
快照配置,3600秒内 如果有一个key修改 就进行持久化
# save 3600 1 # save 300 100 # save 60 10000
RDB文件, 持久化出错后是否继续执行,是否压缩rdb文件,
stop-writes-on-bgsave-error yes rdbcompression yes
保存rdb文件时,进行错误的检查校验
rdbchecksum yes
rdb备份文件保存目录
dir /usr/local/redis/var
集群配置
# replicaof <masterip> <masterport>
事务(内附锁)
事务语法
watch key1 key2 … : 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 ) multi : 标记一个事务块的开始( queued ) exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 ) discard : 取消事务,放弃事务块中的所有命令 unwatch : 取消watch对所有key的监控
事务执行代码(一切正常)
127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set k1 v1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> exec 1) OK 2) OK 127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> get k2 "v2"
事务执行代码(有一条指令有误)
127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set q1 11 QUEUED 127.0.0.1:6379(TX)> set q2 33 QUEUED 127.0.0.1:6379(TX)> set q3 44 op QUEUED 127.0.0.1:6379(TX)> exec 1) OK 2) OK 3) (error) ERR syntax error 127.0.0.1:6379> mget q1 q2 1) "11" 2) "33"
Redis的事务是有点特殊的,与数据库和程序中是有点特殊的。MySQL中的事务是要不全部成功,要不全部失败,程序里的事务也是一样的要么全部成功,要不全部失败。Redis这里的事务就是,正确的全部执行,错误的该报错报错,不影响大概的执行。
Redis不保证原子性且事务没有隔离级别的概念
总结:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令
事务锁分乐观锁,悲观锁。顾名思义悲观锁就是任何操作我都加锁,我谁都不信任。乐观锁刚好与其相反,它主要就是相信任何人,它不会有加锁的操作,只不过在开启的时候要给他一个watch操作,也就是监控这个值的。执行事务时会判断这个值是否与开启事务的值一致,如果不一致不会执行,如果一致且认为正确执行!
执行示例 这里暂时不搞分布式,直接开两个窗口模拟,也就是开两个线程的意思
①:首先在第一个窗体设置一个值为66,然后watch监控这个数值的变动,并且开启事务在事务中添加这个值44 也就是说66+44 最后的值应该是100
②:这个时候不执行事务,操作第二个操作,改变这个数值
③:这个时候的w1 已经是67了,不再是66了,所以第一个窗口的事务应该执行不成功。原因是这个值已经被改动了
这个就是乐观锁,具体乐观锁的实现原理,以后我会论述出自己的想法,这里说的是Redis,就不讲乐观锁的事情了。
AOF,RDB持久化
这个就是rdb备份文件。这个文件的配置是来自config里的 dbfilename决定的
这个就是raof备份文件。这个文件的配置是来自config里的 appendfilename决定的
RDB与AOF的不同就是RDB是采用快照的形式,直接全部复制备份,AOF是采用追加的方式。
Redis在每次启动时都会先判断dump.rdb文件与appendonly文件是否存在需要还原的数据。如果文件被删了,就会自动创建一个文件。
在执行还原数据的时候还涉及到一个工具,这个工具是用来修复备份文件中指令的,在下面的常用工具我会做出一一介绍
集群
集群搭建
说到集群,我想大家都不陌生,也就是常说的高可用,提到高可用就和3v3高扯不开关系。海量,多样,实时。高并发,高性能,高可用。
先介绍一下,因为是集群Redis,所以至少要使用3台以上的电脑,我这里为了简化一些,我就采用一台服务器,3个Redis配置来启动3个Redis了。跟多台电脑是一样的。
三个窗口分别对应三台Redis
这里的操作就是修改三个窗口中 三个配置文件的配置,端口分别是6379,6380,6381。然后分别启动三个Redis实例。
检查一下三台实例的运行状态,确认6379,6380,6381无误。
通过 info replication 指令 查看当前库的状态,role是当前的角色,connected_slaves是子库
搭建集群的话,只需要配置从库就好了,不需要配置主库
通过指令配置 主从库
以上就是指令搭建集群操作了。真正实际中都是用配置搭建。所以步骤都是一样的,只不过方式变了,进入redis.conf 修改replication 那里的配置即可,修改方法在上述已经解答,就是通过 ip+port。如果有密码的话在下面大概5行的位置修改一下 requirepass即可。
哨兵模式
主从切换技术 方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。
哨兵模式 是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
最后一张图片就是哨兵模式的入口,它是一个独立的进程。一旦主库宕机,哨兵进程会自动投票选举新的主机。
常用工具介绍
介绍一下关于Redis的常用工具
压力测试工具: redis-benchmarkAOF文件检查工具: redis-check-aofRDB文件检查工具: redis-check-rdb哨兵模式的监控工具: redis-sentinel(集群那里会介绍的)
可以看一下压力测试工具测出来的数据。参考了解一下即可。
发布订阅
发布订阅必须是两个窗口或者多个Redis才能进行测试。以下案例就是 ①:第一个窗口负责订阅一个频道叫huanshao,订阅之后就处于等待接收的状态了。 ②:第二个窗口是用于发送消息的,往huanshao这个频道发送一个HelloWord然后第一个窗口自动就接收了
这个就是Redis的发布订阅,这个的应用场景类似于微信的公众号发送文章一样,博主上传一个新文章,订阅这个公众号的人将全部可以接收这个文章的数据
缓存穿透,缓存雪崩,缓存预热,缓存降级
详情图解请前往Redis初篇 Redis一篇访问入口
缓存穿透:缓存穿透:一般访问缓存的流程,如果缓存中存在查询的商品数据,那么直接返回。 如果缓存中不存在商品数据,就要访问数据库。由于不恰当的业务功能实现,或者外部恶意攻击不断地请求某些不存在的数据内存,由于缓存中没有保存该数据,导致所有的请求都会落到数据库上,对数据库可能带来一定的压力,甚至崩溃。
缓存雪崩:当缓存重启或者大量的缓存在某一时间段失效,这样就导致大批流量直接访问数据库,对 DB 造成压力, 从而引起 DB 故障,系统崩溃。举例来说, 我们在准备一项抢购的促销运营活动,活动期间将带来大量的商品信息、库存等相关信息的查询。 为了避免商品数据库的压力,将商品数据放入缓存中存储。 不巧的是,抢购活动期间,大量的热门商品缓存同时失效过期了,导致很大的查询流量落到了数据库之上。对于数据库来说造成很大的压力。
缓存预热:缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询事先被预热的缓存数据。如果不进行预热, 那么 Redis 初识状态数据为空,系统上线初期,对于高并发的流量,都会访问到数据库中, 对数据库造成流量的压力缓存降级:降级的情况,就是缓存失效或者缓存服务挂掉的情况下,我们也不去访问数据库。我们直接访问内存部分数据缓存或者直接返回默认数据。举例来说:对于应用的首页,一般是访问量非常大的地方,首页里面往往包含了部分推荐商品的展示信息。这些推荐商品都会放到缓存中进行存储,同时我们为了避免缓存的异常情况,对热点商品数据也存储到了内存中。同时内存中还保留了一些默认的商品信息。
缓存穿透解决方案:针对缓存穿透的情况, 简单的对策就是将不存在的数据访问结果, 也存储到缓存中,避免缓存访问的穿透。最终不存在商品数据的访问结果也缓存下来。有效的避免缓存穿透的风险
缓存雪崩解决方案
- 将商品根据品类热度分类, 购买比较多的类目商品缓存周期长一些, 购买相对冷门的类目
商品,缓存周期短一些; 2. 在设置商品具体的缓存生效时间的时候, 加上一个随机的区间因子, 比如说 5~10 分钟 之间来随意选择失效时间; 3. 提前预估 DB 能力, 如果缓存挂掉,数据库仍可以在一定程度上抗住流量的压力
缓存预热解决方案:
- 数据量不大的时候,工程启动的时候进行加载缓存动作;
- 数据量大的时候,设置一个定时任务脚本,进行缓存的刷新;
- 数据量太大的时候,优先保证热点数据进行提前加载到缓存