Redis学习1

100 阅读14分钟
1:Redis的网络通信模型

blog.csdn.net/qq_41688840…

2:redis基于文件事件的网络通信模型

redis基于文件事件的网络通信模型

file event,网络事件,抽象为文件事件,在redis server内部,网络 通信各种事件,其实都是一些文件事件

Socket概念,redis server单机,可以抗几千的QPS,几百上千的并发,同时有几百个redis client对这个redis server发起请求,都需要去建立网络连接,同时间可能会有几百个redis client通过socket和我们的redis server socket建立网络连接

  redis server而言的话,因为可能有很多的、大量的redis client,redis server内部为了支撑并发访问的大量的redis client,redis server内部就会有几百个socket,网络连接同时在维护和维持着

如果大家自己做过java socket网络编程,bio模式,nio模式,一旦要是说跟一个server跟一个client完成了一个网络连接之后,都会多出来一个socket,socket是关键抽象和模型,通过一个socket就可以跟对方的一个socket形成一个连接

当你手头有大量的客户端来并发访问的时候,server端里就可能会有大量的socket,可以多个线程,也可以一个线程,bio模式下,一个socket连接就对应了一个线程来进行监听他的请求,java nio模式下,可以实现IO多路复用,一个线程,就可以多路复用去监听多个socket的网络事件(请求发送过来)

 socket里可能会产生一些网络事件,accept(连接应答)、read(有数据可以读取的事件)、write(有数据可以写出的事件)、close(连接被关闭) -> file event,redis里,网络事件都是抽象为文件事件

3:基于队列串行化的文件事件处理机制

同一时间有大量的redis client,可能会在同一时间,并发的给我们发送大量的请求,在短时间里,大量的请求到达redis server,redis server内部的大量的socket会突然同一时间产生大量的事件,read事件,write事件

此时有两种处理方案,我们可以搞一个queue队列,把这些有事件的socket一个一个怼入queue里,串行化排队,不管你同一时间有多少请求过来,要返回多少响应,我就让你们所有有事件发生的socket都去排队,串行化,等着处理

我们可以把有事件发生的socket,分发给不同的线程,来进行并发的处理,开启大量的多线程,多个线程并发的去处理不同的socket里面的事件

监听socket会产生一个建立连接的请求,发生了一个网络事件 -> 文件事件,很明显是需要我们进行连接应答,连接请求,必然需要我们进行连接应答,把连接应答做完了,才能建立网络连接

3.1 Redis串行化单线程模型为什么能高并发

高并发能力到底是为什么

 那么就说明有大量的redis client要在短时间内高并发的模式发起对你的单个redis server的请求,这个时候会出现哪些事情呢?第一点,必然会出现的一个事情,有大量的redis client同时间要跟你建立网络连接

  负责连接的socket,短时间内会有大量的要建立连接的请求和事件,为什么短时间内redis server可以跟大量的client建立连接,第一点,连接的建立,往往来说,性能开销是可控的,短时间内完成大量的连接的建立,是没问题的,第二点,对于redis client而言,你是短连接还是长连接,建立长连接,短连接模式(频繁的建立和断开连接,这个就不靠谱了),建立的都是长连接,第一次建立连接是要花费一些时间的,后续这个连接就不用重复建立和断开了,就可以复用了

短时间之内大量的客户端来同时建立连接,这个是没有问题的,大量的客户端会基于socket在短时间之内,高并发的发送请求过来,redis server端的各个socket短时间内频繁的出现网络事件,全部进行队列串行化 + 单线程来处理每个请求呢,针对内存里的共享的数据结构,如果说你要是允许多个线程并发的访问共享内存数据结构,会导致频繁的加锁和互斥

  另外一个多线程,多线程对cpu负载消耗是很大的,如果说cpu负载太高了以后,多线程运转的效率会急转直下的,多线程访问一块共享内存数据结构,大量的加锁和互斥,竞争,会导致性能也是不高的

 避免多线程切换对cpu负载消耗,避免对内存数据结构大量的加锁和互斥,竞争;能否抗高并发,靠的是什么?靠的是每个请求执行和处理的速度和效率,假设说你一个请求,如果要耗费10ms,才能处理完毕,此时每秒钟只能处理100个请求,如果说你一个请求只要1ms就可以处理完毕,1000个请求,如果说你一个请求基于纯内存数据结构来操作,而且避免了加锁和互斥之后,低于1ms

  一秒钟进来了几千个请求,都积压在一个队列里,单个线程拿出一个请求就直接基于内存来操作,低于的1ms,1s之内,单个线程就可以快速的把几千个请求基于内存数据结构全部都处理掉   简单来说就是大量的人短时间内建立很多连接,IO多路复用程序,同时监听他们的,一秒钟里几千个请求过来了,串行化积压,redis最核心的一个点,他是基于纯内存进行数据操作,几千个请求,1s钟内,轻轻松松就处理完毕了,高并发就没有问题了

 每个请求处理不需要去写磁盘文件,调用数据库,对他来说并发能力是极为高的

Redis Server运行原理.jpg redis客户端和服务端建立连接的时候,会在双方各自建立一个socket,之后会通过socket建立长连接,并以此来进行后续的通信。 redis2.6版本之后,默认的最大client连接数是10000,最大可设置为100000。socket连接对建立了之后,client后续对于redis的操作命令,就会通过socket发送给服务端的socket。redis服务端里有个线程,会将所有socket接收到的操作命令放到队列里面,之后会通过文件事件调度器,将不同的命令分别分发到对应命令类型的处理器中,处理器会将命令写到输入缓冲区中,然后解析请求并找到对应的redis操作命令,执行完之后会将处理结果放到输出缓冲区,命令相应处理器会从输出缓存区中获取响应结果,之后将结果返给client。

4 Redis通信协议与内核级请求数据结构

blog.csdn.net/LT11hka/art…

SET key value -> jedis.set(key, value) -> 通过协议组织成数据

网络通信的过程,代码里的对象和数据结构,往往需要进行按照协议进行封装和组织,按照协议进行组织之后,会得到一坨协议数据,*3\r\n3\nSET˚\n˚3\r\nSET\r\n3\r\nkey\r\n$5\r\nvalue\r\n,

按照协议组织的数据,还必须进行序列化,请求数据,从client端发送到server端来,序列化成字节数据流,byte[]字节数组,然后再去通过socket,使用网络去传输字节数据流,以字节数据流的格式,传输到server端去server,通过socket读取出来的一般是字节流,还得把字节流进行反序列化的过程,拿到一个*3\r\n3\nSET˚\n˚3\r\nSET\r\n3\r\nkey\r\n$5\r\nvalue\r\n,请求串,此时会被放入到你的RedisClient的输入缓冲区里

5 Redis Server启动时的流程原理分析

如果redis进程重启的话,内存里的数据就全部都丢失了,所以一般来说我们也会给redis开启一个数据持久化机制,一般来说,都是用AOF来进行数据持久化,用RDB可以去做一个周期性的冷备份

 

AOF,每次当你对内存里的数据进行更新之后,都会有一个对应的记录写入到一个内存里的缓冲结构里去,我们可以设定AOF记录刷新到磁盘的周期,比如说可以设定为,每条数据写入内存后就把他的AOF记录刷到磁盘去,确保每条数据都不会丢失,会导致你的redis的性能退化到磁盘的数据存储的级别

 每秒钟,把内存里的AOF的记录数据刷到磁盘文件里去,突然把redis-server进程进行重启,此时可能会丢失1秒内写入到内存里的数据对应的AOF内存里的记录,但是只要他redis-server重启了之后,就会把磁盘文件里的之前的AOF记录都读取出来,还原出来内存里的数据情况

  AOF以外,RDB -> 周期性的,把内存的数据写一份快照放到磁盘文件里去,比较适合做数据冷备份,你可以数据备份成一个文件,放到其他服务器上去,如果这台服务器万一磁盘坏了,导致AOF都没了,此时可以基于1个小时之前的RDB去做一个数据恢复

6 基于slots槽位机制的数据分片原理分析

分布式数据存储,我把100GB的数据分布式的存储在各个节点里了

当我写入一条数据的时候,这条数据到底是写入哪个节点里,我们首当其冲的,就是要决定我的数据是写入哪个数据分片,data sharding,就是数据在redis各个节点之间的迁移/rebalance过程

数据节点的扩容上,缩容,redis集群刚开始是5个节点,6个节点,8个节点,往集群里加入1个、3个节点,刚刚加入集群的节点是空的,没有数据的,这是不合理的,rebalance,把已有的几个节点上的数据,迁移到新的空节点上去

让已有的节点上的数据变少,让新的空节点上的数据变多,实现这样的效果

缩容,5个节点,公司里要节约成本,缩容为3个节点,减少的2个节点的数据迁移到3个节点上去,数据迁移,如何进行数据迁移  

数据分片的概念,各个节点里有一个数据分片的概念了,每个节点包含n个数据分片,在写入数据的时候,我们可以通过一定的路由算法,把每条数据写入到一个节点的1个数据分片里去,随机分配、轮询分配

扩容加机器,通过一定的算法计算出来,已有的每个节点要迁移哪些数据分片给我们的新节点就可以了,把指定的数据分片去做一个迁移就可以了,缩容,把减少的机器上的数据分片迁移给我们的剩余的机器就可以了

数据分片 -> slots,槽位的概念,所有的数据分片是固定的数量的,16384个slots,我们就需要给集群的各个节点分配他们负责的slots槽位,每个节点会负责一部分的slots槽位,每个slot槽位就是一个数据分片

7 Redis SYNC主从复制原理以及缺陷

redis主从复制原理,演进过程,redis 2.x以前的老版本里,SYNC复制,有很多的缺陷

原理大家也是需要知道的,你就不理解redis主从复制是如何一步一步演进过来的,BGSAVE,background save,后台保存

slave崩溃了,重启,slave断线重启,会导致每次slave重启,都需要去发送SYNC命令给master,让master按照之前的步骤去把数据同步重新做一遍,每次salve重启都要执行sync,这里开销最大的点在于bgsave操作,是一个极为重量级,耗时的操作  

把redis master内存里的大量数据(几个GB,多则几十个GB),执行大量的磁盘IO,耗时的,把这么大的一个文件(几个GB~几十个GB),传输给salve,也非常耗费网络资源,网络带宽,可能都会被打满,slave收到了RDB之后,几乎会阻塞掉对外部的服务和操作,专门把RDB通过大量的网络磁盘IO,加载到内存里来,SYNC模式执行slave->master主从同步,缺陷就在于这里

redis老版本,主从复制,就支持一个SYNC机制,每次断线重连,都要bgsave一遍,rdb来传快照是非常不好的,在很多情况下,从服务器他可能仅仅是做一些运维工作,重启,断线重连的时间间隔,其实不长,没有必要每次都传输rdb快照

redis新版本,就玩儿了一个PSYNC,主要是针对断线重连,做了一些优化,如果说你断开的时间间隔还比较短的话,那其实就还好,就不需要传输rdb,bgsave,其实只要想办法把你断开这段时间里,做出一些命令变更,传输给你,你把这些命令去重新执行一遍,就完事了

  如果说你要是断开的时间太长了,几个小时,几天,在这段时间里做出的数据变更太多了,此时就没办法了,还是得走一个老路子,bgsave,生成rdb传输,把命令传输过去,做一个同步

 

偏移量,复制积压缓冲区

如果说导致偏移量差距的这些命令都在复制积压缓冲区里,此时就可以把这些命令传输给从节点,他把这些命令执行一遍,就可以让数据完成同步

 如果说你要是落后的太多太多了,导致重启的时候,主从之间的数据偏移量差距太大太大了,这些偏移量对应的命令在复制积压缓冲区里找不到了,此时就只能做一个全量的同步,rdb快照传输过去,实现主从数据同步

8 Redis主节点选举算法以及故障转移

对于这个master节点,如果说他挂掉的话,他的slave节点肯定会感知到他的fail下线的状态,

   每个redis节点,slave节点也是一样,都会定时的发送ping消息给所有的其他节点,每个节点都会定时的发送ping消息给其他节点,集群里,是没有controller/leader的概念,大家都是对等的,中心化的一个总控节点,都是通过集群里各个节点互相之间进行探测和通信实现集群的功能,每个人尝试去探测其他节点,是否还存活,定时发送ping,如果说人家是存活的,pong,ping-pong,ping-pong,探测的消息来回,两个slave节点,发送出去的ping消息,并没有在指定的时间范围内,收到pong

  此时,每个slave节点,都会把这个master标记为,pfail,疑似下线

一旦说slave节点感知到自己的master节点故障下线了,slave节点会尝试开始进行master选举

每个slave节点,都会发送投票请求给其他的一些master,请求master给自己投一票,这个时候,其他master如果说要是还没有给任何人投过票,此时就可以给这个slave投出一票,看你的各个salve谁的投票请求先过来 收票的时候,如果说发现自己得到了n节点/2+1大多数人的投票,此时就可以把自己选举为一个新的master,他就会去通知所有的节点,之前下线的master,他负责的槽位slots都归自己管了,所有人都会更新自己内存里的数据结构,之前的其他的salve,此时就会开始从新的master那里去同步数据

 如果一轮投票里没人收到n/2+1大多数人的投票,此时开启下一轮投票就可以了

 redis最核心的一些内核原理,都已经理解了,整体性、深入的理解

 如果针对redis内核需要进行深一步的研究和学习,redis的各种内存数据结构可以研究一下,AOF和RDB持久化机制可以研究,pub/sub、事务、lua、慢查询、监控、LRU、expire,redis提供的方方面面的机制都可以研究他的内核的原理