1 Redis 简介

Redis是一个 基于内存亦可持久化的Key-Value数据库,

Redis为什么这么快?

  1. redis是基于内存的,内存的读写速度非常快
  2. 采用单线程(网络请求模块使用了一个线程),避免了不必要的上下文切换和竞争条件
  3. Reactor的事件驱动模型,非阻塞IO - IO多路复用1

基本的数据结构,

  • String: 字符串
  • Hash: 散列
  • List: 列表
  • Set: 集合
  • Sorted Set: 有序集合

2 Redis 常见使用场景

Hash
hash 是一个 string 类型的 field 和 value 的映射表 ,适合用于存储对象
比如说登录成功后存一些用户的token 以及个人信息

key=User293847
value={
  "id": 1,
  "name": "SnailClimb",
  "age": 22,
  "location": “Wuhan, Hubei”
  "token": “PaZzZtT15ijfHcxqPaZzZtT15ijfHcxq”
}

Sorted Set
实时排行榜功能

# 添加分数
 zadd top_buy 89 user1
 zadd top_buy 95 user2
 zadd top_buy 95 user3
 zadd top_buy 90 user4
# 查询分数
 zrevrange top_buy  0 2 withscores

List
基于List的 LPUSH+BRPOP 的实现的简单 入门级 消息列队

lpush和rpop左进右出
rpush和lpop右进左出
blpush和brpop堵塞式,可以指定超时时间

//发送消息
$redis->lPush($list, $value);

//消费消息
while (true) {
    try {
        $msg = $redis->rPop($list);
        if (!$msg) {
            sleep(1);
        }
        //业务处理
     
    } catch (Exception $e) {
        echo $e->getMessage();
    }
}
不阻塞 lpop和rpop会一直空轮训,消耗资源 ,阻塞 空闲连接的会主动断开连接,减少闲置资源占用,就会抛出异常 所以还要捕获到异常,和重试,

Psubscribe
基于psubscribe 实现简单的 订单超时 ,关闭订单功能

1 修改redis.conf  开启keyspace notifications
SETEX order_info 60 redis
psubscribe 'keyevent@15:expired'

**Stream **
基于Stream 实现消息队列

// ,消息ID 方案,消息内容,其中消息内容为 key-value 型数据。ID,最常使用*,表示由 Redis 生成消息ID,这也是强烈建议的方案。field string [field string], 就是当前消息内容,由1个或多个 key-value 构成
XADD key ID field string [field string ...]
//从 Stream 中读取消息 
XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
//消息 ID 的序列化生成
//消息遍历
//消息的阻塞和非阻塞读取
//消息的分组消费
//未完成消息的处理
//消息队列监控

单点的 redis分布式锁(非严格意义上的分布式锁)

1、加锁
加锁实际上就是在redis中,给Key键设置一个值,为避免死锁,并给定一个过期时间。

SET lock_key random_value NX PX 2000

值得注意的是:
random_value 是客户端生成的唯一的随机字符串。
NX 代表只在键不存在时,才对键进行设置操作。
PX 2000设置键的过期时间为2000毫秒。

2 释放锁

// random_value 为:ARGV[1],而 lock_key 为KEYS[1]。
if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end
为什么不用 SETNX获取锁 主要原因是SETNX不支持超时时间的设置。
为什么random_value 要设置成随机值? 保证了一个客户端释放的锁是自己持有的那个锁

3 Redis 常见一些问题

1 Redis 持久化机制

RDB

fork一个进程,遍历hash table,利用copy on write,把整个db dump保存下来,粒度比较大,如果save, shutdown, slave 之前crash了,则中间的操作没办法恢复。

AOF

把写操作指令,持续的写到一个类似日志文件里,粒度较小,crash之后,只有crash之前没有来得及做日志的操作没办法恢复。
2 Redis 缓存穿透/缓存雪崩如何处理

缓存雪崩

  • 失效时间分散开
  • 增加互斥锁,控制数据库请求 防止集体落在db上
  • 永远不过期 过期时间放value ,发现过期 异步线程重新构建换成
  • 本地ehcache缓存+熔断设计

缓存雪崩

  • 缓存空值 ,
  • 布隆过滤器 (类似于一个hbase set 用来判断某个元素(key)是否存在于某个集合中
    我们把有数据的key都放到BloomFilter中,每次查询的时候都先去BloomFilter判断,如果没有就直接返回null)
3 如何保证缓存与数据库 数据一致性?

读的顺序是先读缓存,后读数据库
写的顺序是先写数据库,然后写缓存
每次更新了相关的数据,都要把该缓存清理掉
为了避免极端条件下造成的缓存与数据库之间的数据不一致,缓存需要设置一个失效时间。时间到了,缓存自动被清理,达到缓存和数据库数据的“最终一致性”

Redis 高可用

Redis Sentinel 哨兵 一主二从三哨兵 哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。

Redis Cluster 三 主 三 从 用虚拟槽分区,所有的键根据哈希函数映射到 0~16383 个整数槽内,每个节点负责维护一部分槽以及槽所映射的键值数据。

redis中的异步复制情况下的数据丢失以及脑裂问题

# 第一个参数表示连接到master的最少slave数量
# 第二个参数表示slave连接到master的最大延迟时间
min-replicas-to-write 3
min-replicas-max-lag 10

4 Redis 知识点

  • Redis 之 Reactor ,I/O多路复用
  • 缓存淘汰算法之LRU
  • redis中哈希一致性



  1. 多路 I/O 复用模型是利用select、poll、epoll可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求 ↩︎