乐趣区

关于redis:Redis-哈希槽及Redis为什么这么快

Redis 哈希槽的概念

Redis 集群中内置了 16384 个哈希槽,当须要在 Redis 集群中搁置一个 key-value 时,redis 先对 key 应用 crc16 算法算出一个后果,而后把后果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会依据节点数量大抵均等的将哈希槽映射到不同的节点。

Redis 集群没有应用一致性 hash, 而是引入了哈希槽的概念

Redis 集群有 16384 个哈希槽, 每个 key 通过 CRC16 校验后对 16384 取模来决定搁置哪个槽. 集群的每个节点负责一部分 hash 槽。这种构造很容易增加或者删除节点,并且无论是增加删除或者批改某一个节点,都不会造成集群不可用的状态。

应用哈希槽的益处就在于能够不便的增加或移除节点:

当须要减少节点时,只须要把其余节点的某些哈希槽挪到新节点就能够了;
当须要移除节点时,只须要把移除节点上的哈希槽挪到其余节点就行了;

在这一点上,咱们当前新增或移除节点的时候不必先停掉所有的 redis 服务。

用了哈希槽的概念,而没有用一致性哈希算法,不都是哈希么?这样做的起因是为什么呢?

Redis Cluster 是本人做的 crc16 的简略 hash 算法,没有用一致性 hash。Redis 的作者认为它的 crc16(key) mod 16384 的成果曾经不错了,尽管没有一致性 hash 灵便,但实现很简略,节点增删时解决起来也很不便。

为了动静增删节点的时候,不至于失落数据么?

节点增删时不失落数据和 hash 算法没什么关系,不失落数据要求的是一份数据有多个正本。

还有集群总共有 2 的 14 次方 -16384 个哈希槽,那么每一个哈希槽中存的 key 和 value 是什么?

当你往 Redis Cluster 中退出一个 Key 时,会依据 crc16(key) mod 16384 计算这个 key 应该散布到哪个 hash slot 中,一个 hash slot 中会有很多 key 和 value。你能够了解成表的分区,应用单节点时的 redis 时只有一个表,所有的 key 都放在这个表里;改用 Redis Cluster 当前会主动为你生成 16384 个分区表,你 insert 数据时会依据下面的简略算法来决定你的 key 应该存在哪个分区,每个分区里有很多 key。

Redis 到底有多快

Redis 采纳的是基于内存的采纳的是单过程单线程模型的 KV 数据库,由 C 语言编写,官网提供的数据是能够达到 100000+ 的 QPS(每秒内查问次数)。这个数据不比采纳单过程多线程的同样基于内存的 KV 数据库 Memcached 差!有趣味的能够参考官网的基准程序测试《How fast is Redis?》(https://redis.io/topics/bench…)

 横轴是连接数,纵轴是 QPS。

Redis 为什么这么快

1、齐全 基于内存,绝大部分申请是纯正的内存操作,十分疾速。数据存在内存中,相似于 HashMap,HashMap 的劣势就是查找和操作的工夫复杂度都是 O(1);

2、数据结构简略,对数据操作也简略,Redis 中的数据结构是专门进行设计的;

3、采纳 单线程,防止了不必要的上下文切换和竞争条件,也不存在多过程或者多线程导致的切换而耗费 CPU,不必去思考各种锁的问题,不存在加锁开释锁操作,没有因为可能呈现死锁而导致的性能耗费;

4、应用 多路非阻塞 I / O 复用模型

5、应用底层模型不同,它们之间底层实现形式以及与客户端之间通信的利用协定不一样,Redis 间接本人构建了 VM 机制,因为个别的零碎调用零碎函数的话,会节约肯定的工夫去挪动和申请;

以上几点都比拟好了解,下边咱们针对多路 I/O 复用模型进行简略的探讨:

(1)多路 I/O 复用模型

多路 I / O 复用模型是利用 select、poll、epoll 能够同时监察多个流的 I/O 事件的能力,在闲暇的时候,会把以后线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正收回了事件的流),并且只顺次程序的解决就绪的流,这种做法就防止了大量的无用操作。

这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采纳多路 I/O 复用技术能够让单个线程高效的解决多个连贯申请(尽量减少网络 IO 的工夫耗费),且 Redis 在内存中操作数据的速度十分快,也就是说内存内的操作不会成为影响 Redis 性能的瓶颈,次要由以上几点造就了 Redis 具备很高的吞吐量。

为什么 Redis 是单线程的

官网 FAQ 示意,因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就牵强附会地采纳单线程的计划了(毕竟采纳多线程会有很多麻烦!)。

正是因为在单线程模式的状况下曾经很快了,就没有必要在应用多线程了!

然而,咱们应用单线程的形式是无奈施展多核 CPU 性能,不过咱们能够通过在单机开多个 Redis 实例来欠缺!

正告 1:这里咱们始终在强调的单线程,只是在解决咱们的网络申请的时候只有一个线程来解决,一个正式的 Redis Server 运行的时候必定是不止一个线程的,这里须要大家明确的留神一下!例如 Redis 进行长久化的时候会以子过程或者子线程的形式执行(具体是子线程还是子过程待读者深入研究);例如我在测试服务器上查看 Redis 过程,而后找到该过程下的线程:

ps 命令的“-T”参数示意显示线程(Show threads, possibly with SPID column.)“SID”栏示意线程 ID,而“CMD”栏则显示了线程名称。

正告 2 :在上图中 FAQ 中的最初一段,表述了从 Redis 4.0 版本开始会反对多线程的形式,然而,只是在某一些操作上进行多线程的操作!所以该篇文章在当前的版本中是否还是单线程的形式须要读者考据!

留神点

1、咱们晓得 Redis 是用”单线程 - 多路复用 IO 模型”来实现高性能的内存数据服务的,这种机制防止了应用锁,然而同时这种机制在进行 sunion 之类的比拟耗时的命令时会使 redis 的并发降落。因为是繁多线程,所以同一时刻只有一个操作在进行,所以,耗时的命令会导致并发的降落,不只是读并发,写并发也会降落。而繁多线程也只能用到一个 CPU 外围,所以能够在同一个多核的服务器中,能够启动多个实例,组成 master-master 或者 master-slave 的模式,耗时的读命令能够齐全在 slave 进行。

须要改的 redis.conf 项:

pidfile /var/run/redis/redis_6377.pid  #pidfile 要加上端口号
port 6377  #这个是必须改的
logfile /var/log/redis/redis_6377.log #logfile 的名称也加上端口号 dbfilename dump_6377.rdb  #rdbfile 也加上端口号 12342、

2、“咱们不能任由操作系统负载平衡,因为咱们本人更理解本人的程序,所以,咱们能够手动地为其调配 CPU 核,而不会过多地占用 CPU,或是让咱们要害过程和一堆别的过程挤在一起。”。CPU 是一个重要的影响因素,因为是单线程模型,Redis 更喜爱大缓存疾速 CPU,而不是多核

在多核 CPU 服务器下面,Redis 的性能还依赖 NUMA 配置 处理器绑定地位。最显著的影响是 redis-benchmark 会随机应用 CPU 内核。为了取得精准的后果,须要应用固定处理器工具(在 Linux 上能够应用 taskset)。最无效的方法是将客户端和服务端拆散到两个不同的 CPU 来高校应用三级缓存。

退出移动版