Redis

这里写目录标题

  • Redis
    • 1、Redis 为什么这么快
    • 2、Redis 是单线程的吗
      • 为什么用单线程?
      • 为什么单线程能这么快?
    • 3、Redis 全局哈希
    • 4、Redis 数据类型
      • 4.1、String(sds来实现)
      • 4.2、hash(dict来实现)
      • redisObject
      • 嵌入式字符串
      • 压缩列表(ziplist)
      • 整数集合(intset)
    • 5、Redis 持久化
      • 5.1、AOF
        • 写后日志带来了两个好处:
        • 写后日志存在的问题:
        • AOF 三种写回策略:
        • AOF 本身的性能问题:
      • 5.2、RDB
        • 快照时数据能修改吗?
        • 多久做一次快照?
      • 5.3、混合使用 AOF 日志和内存快照
    • 6、Redis 缓存
      • 6.1、Redis 缓存工作原理
        • Redis 缓存的两种类型
      • 6.2、Redis 缓存淘汰策略
        • noeviction 策略 不进行数据淘汰
        • volatile-* 策略 根据过期时间进行淘汰
        • allkeys-* 所有数据范围内进行淘汰
        • LRU
        • 淘汰数据具体操作
      • 6.3、Redis 缓存一致
        • 数据一致性
        • 缓存和数据库不一致的原因及解决方案
      • 6.4、缓存雪崩
        • 出现原因
      • 6.5、缓存击穿
      • 6.6、缓存穿透
        • 布隆过滤器
      • 6.7、缓存污染
    • 7、主从模式
      • 7.1、主从数据一致
      • 7.2、主从同步
      • 7.3、主从库间网络断了怎么办
      • 7.4、主从全量同步使用RDB而不使用AOF的原因
      • 7.5、哨兵机制
      • 7.6、主从切换中,客户端能否正常地进行请求操作?
      • 7.7、哨兵 发布/订阅 消息 和 INFO 命令
      • 7.8、Leader 选举
      • 7.9、Raft 协议
      • 7.10、其它
    • 8、Redis 切片集群
      • 8.1、数据分区
      • 8.2、哈希操作如何映射到对应的实例上
      • 8.3、客户端如何定位数据
        • Redis Cluster 重定向机制
      • 8.4、数据倾斜
        • bigkey 处理方案
      • 8.5、通信开销
        • Gossip 协议
        • Gossip 消息大小
        • 实例间通信频率

Redis

1、Redis 为什么这么快

  1. 因为它是内存数据库,所有操作都在内存上完成,内存的访问速度本身就很快。
  2. Redis 键值对是按一定的数据结构来组织的,操作键值对最终就是对数据结构进行增删改查操作,所以说 Redis 能快速处理数据
  3. Redis 使用异步机制来执行一些并不关键的操作,不关键的操作一般就是不许要 Redis 返回数据结果的操作;像我们的删除操作;还有一些阻塞式的操作,比如:bigkey 删除,清空数据库都可以异步来执行

Redis 主线程在启动后,会创建三个子线程来负责执行删除操作、写AOF日志、文件的关闭;他会把接收到的操作封装成任务,然后放到一个任务队列里;拿着这个任务队列和子线程交互;比如说,我发出了一个删除操作,然后Redis会把这个操作封装成一个任务放到任务队列中,然后返回一个完成信息,但其实这个时候删除操作并没有完成,等到后台的子进程从任务队列中把这个任务取出来,才会开始执行删除操作;

补充(别读):

有两个阻塞是没有办法异步的:集合全量查询和聚合操作、从库加载 RDB 文件,有各自的技巧

  • 集合全量查询和聚合操作:可以使用 SCAN 命令,分批读取数据,再在客户端进行聚合计算;
  • 从库加载 RDB 文件:把主库的数据量大小控制在 2~4GB 左右,以保证 RDB 文件能以较快的速度加载。

2、Redis 是单线程的吗

Redis 的网络 IO 和键值对读写是由一个线程来完成的;

但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。

为什么用单线程?

一方面单线程的程序可以避免线程上下文切换带来的性能损耗;另一方面,单线程程序不存在临界资源,不会出现锁以及并发竞争的情况

为什么单线程能这么快?

  1. 基于内存操作;
  2. 定制化的数据结构,大部分命令的时间复杂度是O(1);
  3. 一方面单线程的程序可以避免线程上下文切换带来的性能损耗;另一方面,单线程程序不存在临界资源,不会出现锁以及并发竞争的情况;
  4. 采用了IO多路复用技术,可以高效的处理多个客户端的请求。

3、Redis 全局哈希

Redis 使用一个哈希表来保存所有键值对;每一个哈希桶位都保存了指向具体值的指针,不管值是 String,还是集合类型,哈希桶中的元素都是指向它们的指针;这样做的好处就是可以用 O(1) 的时间复杂度来快速查找到键值对

存在两个问题就是哈希表的冲突问题和 rehash 可能带来的操作阻塞

全局哈希表使用拉链法来解决哈希冲突;但是当哈希冲突剧烈的时候,哈希冲突链会过长,会影响我们查找效率,这个时候会有 rehash 操作,来增加数组的桶位,减少单个桶位的哈希冲突

Redis 的 rehash 操作是渐进式的,并且使用了两个全局哈希表来完成;当我们添加数据的时候,是往第一个哈希表添加,第二个哈希表只有当我们 rehash 的时候才会创建;rehash分为三步:

  1. 给第二个哈希表分配一个更大的空间

  2. 把哈希表 1 中的数据重新映射并拷贝到哈希表 2 中;

    第二步涉及大量的数据拷贝,如果一次性把哈希表 1 中的数据都迁移完,会造成 Redis 线程阻塞,无法服务其他请求;Redis的策略就是把一次性大量拷贝的开销,分摊到了多次处理请求的过程中

    第二步拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位

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