Redis - 大厂程序员是怎么用的| 青训营笔记

161 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天

Redis基本工作原理

Redis实现数据持久化的原理

数据从内存中读写

将数据保存在硬盘上防止重启数据丢失

  • 增量数据保存在AOF文件
  • 全量数据RDB 文件中
  • Redis单线程处理命令的概念

Redis应用案例

掘金连续签到

Key过期 string 数据结构 sds

len alloc flags buf

可以存储字符串 数字 二进制数据

通常和expire配合使用

场景:存储计数 session

消息队列

利用list实现,数据结构quicklist

quicklist 由双向链表和listpack 实现

listpack

listpack 也叫紧凑列表,它的特点就是用一块连续的内存空间来紧凑地保存数据,同时为了节省内存空间,listpack 列表项使用了多种编码方式,来表示不同长度的数据,这些数据包括整数和字符串

<tot-bytes> <num-elements> <element-1> ... <element-N> <listpack-end-byte>
  • Total Bytes为整个listpack的空间大小,占用4个字节,每个listpack最多占用4294967295Bytes。
  • Num Elem为listpack中的元素个数,即Entry的个数,占用2个字节,值得注意的是,这并不意味着listpack最多只能存放65535个Entry,当Entry个数大于等于65535时,Num Elem被设置为65535,此时如果需要获取元素个数,需要遍历整个listpack。
  • Entry为每个具体的元素。
  • End为listpack结束标志,占用1个字节,内容为0xFF

计数

HASH数据结构 dict

在较大数据进行迁移时会出现阻塞情况

渐进式rehash

我们知道当HashMap中由于Hash冲突(负载因子)超过某个阈值时,出于链表性能的考虑,会进行Resize的操作。Redis也一样。

在redis的具体实现中,使用了一种叫做渐进式哈希(rehashing)的机制来提高字典的缩放效率,避免 rehash 对服务器性能造成影响,渐进式 rehash 的好处在于它采取分而治之的方式, 将 rehash 键值对所需的计算工作均摊到对字典的每个添加、删除、查找和更新操作上, 从而避免了集中式 rehash 而带来的庞大计算量。

扩展和收缩需要将ht[0]上的所有键值对rehash到ht[1]哈希表中。但是redis的rehash动作并不是一次性完成的,而是分多次、渐进式的完成的。

渐进式rehash步骤:

  1. 为ht[1]分配空间
  2. 将字典中的rehashidx设置为0,表示rehash正式开始,rehash期间,不会阻塞CRUD等操作
  3. 当ht[0]所有的键值对都rehash到ht[1]时,将rehashidx属性设置成-1,表示rehash完成

排行榜

zset数据结构 跳表

结合dict实现排行榜功能

跳表

跳表是可以实现二分查找的有序链表

跳表插入、删除、查找元素的时间复杂度跟红黑树都是一样量级的,时间复杂度都是O(logn),

我们可以通过较少索引数来减少空间复杂度,但是相应的肯定会造成查找效率有一定下降,我们可以根据我们的应用场景来控制这个阈值,看我们更注重时间还是空间。

按照区间查找数据时,跳表可以做到 O(logn) 的时间复杂度定位区间的起点,然后在原始链表中顺序往后遍历就可以了,非常高效。

在字节跳动,使用Redis有哪些注意事项

  • 大Key:Value大于10KB就是大Key,使用大Key将导致Redis系统不稳定

  • 热Key:一个Key的QPS特别高,将导致Redis实例出现负载突增,负责均衡流量不均的情况。导致单实例故障

  • 慢查询:大Key、热Kye的读写;一次操作过多的Key(mset/hmset/sadd/zadd)

  • 导致缓存穿透、缓存雪崩的场景及避免方案