Redis查漏补缺-1

Redis查漏补缺-1

1. 牛客网面经1

Reference:https://www.nowcoder.com/discuss/424298860043907072

1.1 Redis切片集群,数据和实例之间如何进行映射?

1.1.1 redis基础篇8,数据分片——场景

http://t.zoukankan.com/liang24-p-14189712.html

现在有一个场景:要用Redis保存5000万个键值对,每个键值对大约是512B,要怎么部署Redis服务呢?

第一个方案,也是最容易想到的,需要保存5000万个键值对,每个键值对约为512B,一共需要25GB空间,选择一台32GB内存的服务器来部署Redis,还剩余7GB空间,可以采用RDB对数据做持久

但是redis服务使用不久后redis的响应有时候会非常慢,原因是采用了RDB持久化,在前面介绍RDB原理的时候,我们知道fork子进程会瞬间阻塞主进程,而且内存越大,阻塞时间越长(save和bgsave,save会阻塞主线程)

上述的方案不太好,一个比较好的方案是,<redis提供切片集群机制>,多个redis实例组成一个集群,按照一定的规则,把收到数据划分成多份,每一份用一个实例来保存,这样一来,在生成RDB时,数据量就小了,fork就不会阻塞主线程太长时间

1.1.2 如何保存更多数据

通常有两种方案,分别是纵向扩展和横向扩展

纵向扩展,指通过增加硬件配置来扩展,采用更大的内存,更多的CPU。好处是实现简单,缺点是受到硬件和成本限制,不可能无限扩展

横向扩展,指通过增加机器来组成更大的集群,这也是分布式方案常用的方式。好处是扩展性好,缺点是管理复杂

在面向百万、千万级别用户的时候,横向扩展的Redis切片集群会是一个非常好的选择

在使用单个实例时,数据保存在哪里,客户端访问哪里,都是非常明确的。但是切片集群不可避免的要解决多个实例分布式管理的问题,需要解决两大问题:

  • 数据切片后,在多个实例之间如何分布?
  • 客户端怎么确定想要访问的数据在哪个实例上?

1.1.3 数据切片和实例的对应分布关系(数据-哈希槽,哈希槽-实例,基于哈希槽来处理)

在redis3.0之前,官方没有提供切片集群的方案,从3.0开始,官方提供了一个名为Redis Cluster的方案,用于实现切片集群

Redis Cluster方案采用哈希槽来处理数据和实例之间的映射关系。这里有两个映射关系:键值对与哈希槽的映射关系哈希槽与实例的映射关系,下面来介绍一下这两个映射关系的映射过程

  • 键值对与哈希槽的映射过程

根据键值对的key,按照CRC16算法计算一个16bit的值,再用这个16bit的值对16384取模,得到0-16383范围内的模数,每个模数打表一个相应编号的哈希槽

说明:Redis切片集群最多提供16384个哈希槽

  • 哈希槽与实例的映射过程

分为自动和手动

自动映射:使用redis create命令创建集群,Redis会自动把这些槽平均分布在集群实例上

手动映射:使用cluster meet命令搬运建立实例间的连接,形成集群,再用redis addslots命令,指定每个集群上的哈希槽个数

说明:在手动分配哈希槽的时候,需要把16384个槽都分配完,否则Redis集群无法正常工作

1.1.4 客户端如何定位数据

客户端和集群的实例建立链接后,实例就会把哈希槽的分配信息发送给客户端

集群刚创建的时候,实例如何互相知道哈希槽信息?Redis实例会扩展哈希槽信息,每个Redis实例都拥有完整的哈希槽信息

另外,客户端在收到哈希槽信息后,会缓存在本地,以便客户端后续请求直接访问实例

但在集群中,实例和哈希槽对应的关系不是一成不变的,最常见的变化

  • 在集群中,实例有新增或者删除,Redis需要重新分配哈希槽;

  • 为了复杂均衡,Redis需要把哈希槽在所有实例上重新分布以便

Redis Cluster提供一种重定向机制,类似于HTTP协议的重定向

客户端把一个键值对操作请求发给一个实例,如果这个实例没有这个键值对对应的哈希槽,这个实例就会返回给客户端MOVED命令相应的结果,包含新实例的访问地址

1
2
GET hello:key (error) 
MOVED 13320 172.16.19.5:6379

其中,MOVED命令表示客户端请求的键值对所在的哈希槽13320,实际是在172.16.19.5这个实例上

如果哈希槽没有完成迁移,客户端的请求的键值对所在的哈希槽是13320,实际是在172.16.19.5这个实例上

如果哈希槽没有完成迁移,客户端请求的数据并不在哈希槽时,客户端就会收到一条ASK报错信息,如下所示:

1
2
GET hello:key (error) 
ASK 13320 172.16.19.5:6379

这个结果中的ASK命令就表示,客户端请求的键值对所在的哈希槽13320,在172.16.19.5这个实例上,但是这个哈希槽正在迁移。

和MOVED命令不同,ASK命令并不会更新客户端缓存的哈希槽分配信息

1.1.5 Redis Cluster为什么不采用把key直接映射到实例的方式

整个集群存储的key的数量是无法预估的,key的数量非常多的时候,直接记录每个key对应的实例映射空间这个会非常庞大

在中间添加一层哈希槽,可以把数据和结点解耦,key通过hash计算只需要关心映射到哪个哈希槽,然后再通过哈希槽和节点的映射表找到节点,相当于消耗了很少的CPU资源,不但让数据分布更均匀,还可以让这个映射表变得很小,利于客户端和服务端保存,节点之间交换信息时也变得轻量。

1.2 Redis如何实现分布式锁?

先记录在这里,未来TODO:https://www.zhihu.com/question/300767410/answer/1931519430

1.3 什么是缓存预热?如何解决?

系统上线后,提前将相关的缓存数据直接加载到缓存系统。避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题。用户直接查询事先被预热的缓存数据

解决方案:

  1. 手动操作
  2. 数据量不大,可以在项目启动的时候自动加载
  3. 定时刷新缓存

Redis查漏补缺-1
http://example.com/2022/12/20/develop/redis/Redis查漏补缺-1/
作者
Curious;
发布于
2022年12月20日
许可协议