1、redis支持数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
2、redis持久化的两种方式:RDB和AOF
-
RDB持久化是在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork(叉)一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
优点:(1)文件备份只有一个文件,容易查找恢复;(2)灾难恢复效率高;
缺点:(1)如果在定时持久化前出现宕机,数据将丢失;(2)RDB是通过fork子进程来协助完成持久化,如果数据集较大会导致服务器短时间内停止服务
-
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
优点:数据安全性更高,可以配置同步持久化
缺点:灾难恢复效率低
3、缓存穿透、缓存击穿、缓存雪崩及解决方案
-
缓存穿透
访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。
解决方案
- 采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
- 访问key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间。
-
缓存击穿
一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。
解决方案
- 在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。
-
缓存雪崩
大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
解决方案
- 可以给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时刻失效。
4、redis 适合的场景
-
会话缓存(Session Cache)
最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?
幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。
-
全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。
再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。
此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
-
队列
Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。
生产者消费者模式简单实现过程:
1、插入数据:
127.0.0.1:6379> lpush list 1
(integer) 1
127.0.0.1:6379> lpush list 2
(integer) 2
127.0.0.1:6379> lpush list 3
(integer) 3
127.0.0.1:6379> lpush list 4
(integer) 4
2、显示数据:
127.0.0.1:6379> lrange list 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
3、取出数据:
127.0.0.1:6379> lpop list
"4"
127.0.0.1:6379> lpop list
"3"
127.0.0.1:6379> lpop list
"2"
127.0.0.1:6379> lpop list
"1"
127.0.0.1:6379> lpop list
(nil)
-
排行榜/计数器
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。
排行榜简单实现过程:
1、设置了4个玩家的分数,如果玩家分数已经存在,则会覆盖之前的分数。
127.0.0.1:6379> zadd ph 90 user
(integer) 1
127.0.0.1:6379> zadd ph 80 user1
(integer) 1
127.0.0.1:6379> zadd ph 70 user2
(integer) 1
127.0.0.1:6379> zadd ph 60 user3
(integer) 1
2、zscore——查看user2玩家分数
127.0.0.1:6379> zscore ph user2
"70"
3、zrevrange——按名次查看排行榜
127.0.0.1:6379> zrevrange ph 0 -1 withscores
1) "user"
2) "90"
3) "user1"
4) "80"
5) "user2"
6) "70"
7) "user3"
8) "60"
4、查询前三名玩家分数。
127.0.0.1:6379> zrevrange ph 0 2 withscores
1) "user"
2) "90"
3) "user1"
4) "80"
5) "user2"
6) "70"
5、zrevrank——查看玩家的排名,zrevrank是以分数由高到低的排序返回玩家排名(实际返回的是以0开始的索引),对应的zrank则是以分数由低到高的排序返回排名。
127.0.0.1:6379> zrevrank ph user2
(integer) 2
127.0.0.1:6379> zrank ph user2
(integer) 1
6、zrem——移除某个玩家
127.0.0.1:6379> zrem ph user1
(integer) 1
127.0.0.1:6379> zrevrange ph 0 -1 withscores
1) "user"
2) "90"
3) "user2"
4) "70"
5) "user3"
6) "60"
7、del——删除排行榜
127.0.0.1:6379> del ph
(integer) 1
127.0.0.1:6379> get ph
(nil)
127.0.0.1:6379> zrevrange ph 0 -1 withscores
(empty list or set)
-
发布/订阅
最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统。
"发布/订阅"模式包含两种角色,分别是发布者和订阅者。订阅者可以订阅一个或者多个频道(channel),而发布者可以向指定的频道(channel)发送消息,所有订阅此频道的订阅者都会收到此消息。
发布/订阅模式简单实现过程:
1、订阅频道
127.0.0.1:6379> subscribe channel:1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel:1"
3) (integer) 1
执行上面命令客户端会进入订阅状态,处于此状态下客户端不能使用除subscribe、unsubscribe、psubscribe和punsubscribe这四个属于"发布/订阅"之外的命令,否则会报错。
进入订阅状态后客户端可能收到3种类型的回复。每种类型的回复都包含3个值,第一个值是消息的类型,根据消类型的不同,第二个和第三个参数的含义可能不同。
消息类型的取值可能是以下3个:
(1)subscribe。表示订阅成功的反馈信息。第二个值是订阅成功的频道名称,第三个是当前客户端订阅的频道数量。
(2)message。表示接收到的消息,第二个值表示产生消息的频道名称,第三个值是消息的内容。
(3)unsubscribe。表示成功取消订阅某个频道。第二个值是对应的频道名称,第三个值是当前客户端订阅的频道数量,当此值为0时客户端会退出订阅状态,之后就可以执行其他非"发布/订阅"模式的命令了。
2、发布消息
127.0.0.1:6379> publish channel:1 hi
(integer) 1
127.0.0.1:6379> publish channel:1 nihao
(integer) 1
返回值表示订阅此频道的数量
3、订阅者接收消息
127.0.0.1:6379> subscribe channel:1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel:1"
3) (integer) 1
1) "message"
2) "channel:1"
3) "hi"
1) "message"
2) "channel:1"
3) "nihao"