Redis常识

文章目录

    • 缓存的三个风险
    • 数据结构
    • 淘汰策略 和 过期删除策略
        • 过期删除
        • 淘汰
    • 如何理解单线程
    • redis特性
    • 复制
    • gossip协议
    • 事务(和mysql不同,是不严格的事务 )
    • 集群(高可用)
    • 管道
    • 持久化

缓存的三个风险

  • 缓存雪崩(缓存引起的数据库,乃至整个系统的雪崩)(大量Key同时过期 或者redis挂)
    • 过期时间加扰动值
    • 后台更新缓存值(缓存永不过期,消息队列)
    • key过期,只允许一个请求(线程) 回源 (锁机制,甚至不用分布式锁也可以)
  • 击穿(热点数据过期)
    • key分片,key= key1 + key2… ,各个分片分担流量
    • 雪崩的处理方式都可以用到击穿的场景
  • 穿透(用户访问的数据,既不在缓存中,也不在数据库中)
    • 对被穿透key的访问限流
    • 缓存空值/默认值
    • 布隆过滤器(redis也自带了布隆过滤器的实现)
      • 如果bloomfilter说有,那可能没有
      • 如果bloomfilter说没有,那一定就没有

see also

数据结构

  • str
    • 存session
    • 分布式锁(setnx)
    • 简单计数器
  • list
    • mq
  • hash
    • 存储对象
  • set
    • 集合特性:不重复、可交集、差集、并集计算
    • 点赞场景:一个用户只能对一个key(文章) 点赞一次
    • 共同好友、共同关注的公众号场景
    • 抽奖:一个用户只能抽一次
  • zset
    • 排行榜(根据分数去排序)
    • 相同分数下获取满足前缀的元素,比如获取131 开头的电话号码
  • bitmaps
    • value只能为0或1,用于大数据集的 0、1 值统计,比如签到,要么签到了要么没签到
  • hyperloglog
    • 统计大数据集的不同元素数量。内存占用小,不过只能取近似精确的结果
    • 百万级网页 UV 计数
  • 地理空间(geospatial)
    • 存储和计算经纬度
  • Stream 数据类型
    • 实现消息队列的绝佳数据结构:支持持久化、自动生成全局唯一ID、ack模式、消费者组机制

see also

淘汰策略 和 过期删除策略

Redis的淘汰和过期删除策略是两个不同的概念。

  • 过期删除:key 带ttl
  • 淘汰: 内存不够用了,删除符合条件的key
过期删除

1、如何判断key 已经过期?
redis的【过期字典】数据结构中存储了 ,get key的时候先从【过期字典】中get ,并将ttl 和当前时间做比较,可以判断出key是否过时。

2、过期删除策略

  • 定时删除: set key ttl的时候,注册一个定时事件,到点就删除。
    这种方式对内存友好(到点就删),但当ttl key多时,对CPU不好,因为需要额外线程干活。
  • 惰性删除(lazy free): get key 时,发现key过期了就删。
    这对内存不够好(删得不及时),但对CPU好
  • 定期随机检查删除: 每隔一段时间【随机】从过期字典中选出一批key检查是否过期,如是则删除。
    这是定时删除和惰性删除的折中。

redis真正的做法是 【惰性删除】 + 【定期随机检查删除】共存。

淘汰

分两大类
一类【不进行淘汰-noevinction】,当内存不够用,返回错误;
二类【进行淘汰】。

【进行淘汰】的策略可再分:
1、设置了ttl key淘汰

  • volatile-random : 随机淘汰设置了ttl 的key
  • volatile-ttl : 优先淘汰更早过期的key
  • volatile -lru :least-recently-used
  • volatile -lfu: least-frequently-used

2、所有范围的key 淘汰

  • allkeys-random : 随机淘汰任意key
  • allkeys-lru
  • allkeys-lfu

值得一提是:3.0+的redis,使用 【noeviction】作为默认策略,这对用户使用redis的容量评估提供了更高的要求。

如何理解单线程

  • before6.0,网络IO+KV读写是 单线程;
  • after6.0,网络IO是多线程,KV操作是单线程。即使多线程并非彻底的多线程,I/O线程只能同时执行读或者同时执行写操作

redis特性

Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)

复制

主从复制是个比较复杂的过程,详见 see also

gossip协议

事务(和mysql不同,是不严格的事务 )

假如现开启了事务,包括了一组命令,拿传统DB的ACID“套”一下:

  • 原子性A

    • exec前,如果命令入队失败,事务不会执行,原子性可以保证
    • exec后,多个命令中其一执行异常,不会回滚这组命令,所以不能保证原子性
  • 能保证隔离性 A 【客户端A执行事务(注意只是exec期间),客户端B的请求会阻塞住】

  • 一致性 C

    • 理解1:一致性的核心是约束 (唯一性约束” 和 “完整性约束”),redis能满足
    • 理解2:原子性,隔离性和持久性是数据库的属性,而一致性(在 ACID 意义上)是应用程序的属性。应用可能依赖数据库的原子性和隔离属性来实现一致性,但这并不仅取决于数据库。
      因此,字母 C 严格来说不属于 ACID 。这就没有“redis的一致性”说法了
  • 持久性 D

    • 开启了rdb/aof
    • rdb可能没有生成快照
    • aof:no/everysec有丢失数据风险,always性能差一般不使用,所以实践角度看,持久性没有保证
  • 隔离性I

    • 并发操作在 EXEC 执行前,隔离性需要通过 WATCH 机制来保证
    • 并发操作在 EXEC 命令之后,隔离性可以保证:Redis 是单线程执行命令,EXEC 命令执行后,Redis 会保证先把事务队列中的所有命令执行完之后再执行之后的命令。
  • see also

集群(高可用)

  • 主从 【主可读写,从只读;主挂了,不可写,要手动切换主】
  • 哨兵 【基于主从,主可读写,主挂了,哨兵会重新选主。哨兵集群要高可靠,算是独立的服务。一个哨兵集群可以检测多个redis主从】
    see also
  • cluster集群 【官方推荐的高可用方案】
    • 【主从和哨兵数据都是没有分片的,容量有上限;cluster会分片,分片后mget mset等不可用】
    • 【实际上是多组主从 “组团”成了一个集群,只由主读写,从不提供服务】
    • 【客户端查询路由- 客户端连任意节点可能被 重定向 (注意不是转发)到其他节点】
    • 【无中心节点、redis 虚拟槽slot分布到多个节点、扩缩容方便、高可用+可failover】
    • 【但无监控、依赖客户端做路由、failover节点检测慢、gossip协议本身有开销】
    • 【slot是数据管理和迁移的基本单位,类比kafak分区;槽的迁移不影响节点服务】
    • 【数据 – slot --节点】
    • 【三主三从】
    • see also

P.S. redis 是根据crc(key)%16384 来决定存储这个kv对的slot的位置,也即是说,sharding 是在key维度的。这解决不了热点key的问题。

管道

一组命令发给服务端 ,不仅减少了网络传输的开销,更重要是极大减少服务端IO,增大吞吐

持久化

  • RDB (redis database):fork子进程出来dump内存快照二进制文件到磁盘,文件小,恢复快,但可能丢数。大数据集场景下fork子进程也可能比较耗时,redis可能有抖动
  • AOF (Append-on-file)
    • 写命令落盘到文件,恢复时回放
    • append本质是写文件系统buffer,OS会【delayed write】
    • 文件重写:aof不能持续追加,毕竟磁盘有限,且过大的文件,回放极其费时,因此redis会压缩文件(合并命令,有点像kafka的Compaction)。
      redis内数据对象的最新状态生成新的AOF文件,体积较小
  • Redis支持混合持久化,对AOF文件重写有什么影响
    • 纯AOF方式
    • RDB+AOF方式:先按照RDB格式写入数据状态,然后把重写期间AOF缓冲区的内容以AOF格式写入,文件前半部分为RDB格式,后半部分为AOF格式
  • 开启混合持久化:文件是【RDB头+AOF尾】,Redis发现AOF文件为RDB头,会使用RDB数据加载的方法读取并恢复前半部分;然后再使用AOF方式读取并恢复后半部分
    (这特别像mysql的备份数据恢复,备库+binlog)

你可能感兴趣的:(redis,数据库,缓存)