Redis Rehash

Rehash rehash执行条件 关键说明 负载因子::load_factor = ht[0].used / ht[0].size BGSAVE::fork一个子进程来创建RDB文件,父进程可以继续处理命令请求 BGREWRITEAOF:AOF重写缓冲区,由于redis是单进程的,为了不在进行重写时阻塞服务,redis使用了子进程的方式进行AOF重写 redis中每次开始执行aof文件重写或者开始生成新的RDB文件或者执行aof重写/生成RDB的子进程结束时,都会调用updateDictResizePolicy->dictDisableResize函数,所以从该函数中,也可以看出来,如果当前没有子进程在执行aof文件重写或者生成RDB文件,则运行进行字典扩容;否则禁止字典扩容。 扩容 以下条件中的任意一个被满足时执行扩容 服务器目前没有在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 1 服务器目前正在执行 BGSAVE 命令或者 BGREWRITEAOF 命令, 并且哈希表的负载因子大于等于 5 缩容 databasesCron->tryResizeHashTables函数检查用于保存键值对的redis数据库字典是否需要缩容 最小size是4 服务器目前没有在执行 BGSAVE 命令或者 BGREWRITEAOF 命令,并且哈希表的负载因子小于 0.1 时, 程序自动开始对哈希表执行收缩操作 rehash执行过程 为字典的 ht[1] 哈希表分配空间=ht[0].used= ht[0] 当前包含的键值对数量 如果执行的是扩展操作, 那么 ht[1] 的大小为 为第一个大于等于ht[0].used * 2 的 2^n 如果执行的是收缩操作, 那么 ht[1] 的大小为为第一个大于等于 ht[0].used的 2^n 将保存在 ht[0] 中的所有键值对 rehash 到 ht[1] 上面: rehash 指的是重新计算键的哈希值和索引值, 然后将键值对放置到 ht[1] 哈希表的指定位置上。 当 ht[0] 包含的所有键值对都迁移到了 ht[1] 之后 (ht[0] 变为空表), 释放 ht[0] , 将 ht[1] 设置为 ht[0] , 并在 ht[1] 新创建一个空白哈希表, 为下一次 rehash 做准备。 渐进式Rehash rehash执行条件等同于Rehash 在渐进式 rehash 执行期间, 新添加到字典的键值对一律会被保存到 ht[1] 里面, 而 ht[0] 则不再进行任何添加操作: 这一措施保证了 ht[0] 包含的键值对数量会只减不增, 并随着 rehash 操作的执行而最终变成空表。 rehash执行过程 为 ht[1] 分配空间, 让字典同时持有 ht[0] 和 ht[1] 两个哈希表。 在字典中维护一个索引计数器变量rehashidx,并将它设置为0,表示rehash工作正式开始 在rehash进行期间,每次对字段执行添加、删除、查找、更新操作的时候,程序除了执行指定的操作意外,还会顺带将 ht[0] 哈希表在 rehashidx 索引上的所有键值对 rehash 到 ht[1] , 当 rehash 工作完成之后, 程序将 rehashidx 属性的值++ 随着字典操作的不断执行, 最终在某个时间点上, ht[0] 的所有键值对都会被 rehash 至 ht[1] , 这时程序将 rehashidx 属性的值设为 -1 , 表示 rehash 操作已完成。 定时辅助rehash 虽然redis实现了在读写操作时,辅助服务器进行渐进式rehash操作,但是如果服务器比较空闲,redis数据库将很长时间内都一直使用两个哈希表。所以在redis周期函数中,如果发现有字典正在进行渐进式rehash操作,则会花费1毫秒的时间,帮助一起进行渐进式rehash操作。...

July 22, 2021 · 1 min · quicksandzn

Redis 持久化方式

Redis 的两种持久化方式(RDB与AOF) RDB RDB (Redis DataBase) 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。 RDB触发机制分为手动触发和自动触发 手动触发 SAVE命令:阻塞当前Redis服务器,知道RDB过程完成为止 BGSAVE:Redis 进程执行fork()操作创建出一个子进程,在后台完成RDB持久化的过程 自动触发 配置(redis.conf) == BGSAVE save 900 1 //服务器在900秒之内,对数据库执行了至少1次修改 save 300 10 //服务器在300秒之内,对数据库执行了至少10修改 save 60 1000 //服务器在60秒之内,对数据库执行了至少1000修改 优势 整个 Redis 数据库将只包含一个文件,十分易于备份 性能最大化,对于 Redis 的服务进程而言,在开始持久化时,它唯一需要做的只是 fork 出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大地避免服务进程执行 IO 操作 相对于 AOF,基于 RDB 数据文件来重启和恢复 Redis 会更快 劣势 无法最大限度地避免数据丢失,系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失 由于 RDB 是通过 fork 子进程来协助完成数据持久化工作的,因此,如果当数据较大时,可能会导致整个服务器停止服务数毫秒,甚至数秒 AOF AOF (Append Only File) 持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,只许追加文件但不可以改写文件,可以打开文件看到详细的操作记录 同步策略 appendsync always #每次有数据修改发生时都会写入AOF文件 appendsync everysec #每秒同步一次,该策略为AOF的缺省策略 appendsync no #从不同步。高效但是数据不会被持久化 优势 最大限度地避免数据丢失,默认的 everysec 策略可以记录下每秒的修改操作,但如果一秒内宕机,有数据丢失 AOF 对日志文件的写入操作采用的是 append 模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。 劣势 对于同一份数据来说,AOF 文件通常要大于 RDB 文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。 根据同步策略的不同,AOF 在运行效率上往往会慢于 RDB。但是每秒同步策略的效率还是比较高的。 总结 二者选择的标准,就是愿意牺牲一些性能,换取最少的数据丢失(AOF),还是牺牲一些数据来换取更高的性能(RDB)。实际中应该综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择; 用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复...

July 21, 2021 · 1 min · quicksandzn

Redis 数据类型

数据类型及使用场景 String:缓存、计数器、分布式锁等 List:链表、队列、微博关注人时间轴列表等 Hash: 用户信息、Hash 表等 Set: 去重、赞、踩、共同好友等 Sorted Set: 访问量排行榜、点击量排行榜等 Redis Object typedef struct redisObject { unsigned type:4; // 类型 unsigned encoding:4; // 一个对象可能包含多个encoding unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */ int refcount; // 引用计数 实现内存回收机制 void *ptr; // 存储的值 } robj; /* Object types */ #define OBJ_STRING 0 #define OBJ_LIST 1 #define OBJ_SET 2 #define OBJ_ZSET 3 #define OBJ_HASH 4 /* Objects encoding. Some kind of objects like Strings and Hashes can be * internally represented in multiple ways....

July 21, 2021 · 2 min · quicksandzn

缓存的场景问题及解决方案

缓存雪崩 描述 大量的 key 设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时 DB 请求量大、压力骤增,引起雪崩。 解决方案 分级缓存 给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时刻失效。 缓存穿透 描述 访问一个不存在的 key 时,缓存不起作用,请求会穿透到 DB ,流量大时 DB 自然就会瘫痪。 解决方案 利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。 即使查询到的数据为空,仍把该空值缓存,还需要设置过期时间。 布隆过滤器,内部维护一系列合法有效的 key 就可以迅速判断出请求所携带的key是否合法有效。如果不合法,则直接返回。 缓存击穿 描述 一个存在的 key,在缓存过期的一刻,恰好在这个时间点对这个 key 有大量的并发请求过来,这个时候大量的请求可能会瞬间瘫痪掉 DB 。 解决方案 分级缓存 互斥锁 缓存预热 描述 系统上线后,提前将数据刷到缓存。避免用户在访问的时候,先去查询数据库。 解决方案 数据量不大的时候,工程启动的时候进行加载缓存 数据量大的时候,设置一个定时任务脚本,进行缓存的刷新 数据量太大的时候,优先保证热点数据进行提前加载到缓存 缓存降级 缓存降级是指缓存失效或缓存服务器挂掉的情况下,不去访问数据库,直接返回默认数据或访问服务的内存数据

July 21, 2021 · 1 min · quicksandzn