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 来高校应用三级缓存。