Redis知识点全面讲解,建议收藏

目录

1.缓存穿透

2.缓存击穿

​3.缓存雪崩

4.双写一致

5.持久化机制

RDB

AOF

​6.数据过期策略

惰性删除

定期删除

7.数据淘汰策略

8.秒懂Redis分布式锁

9.分布式锁实现原理

setnx

redisson

10.主从同步

11.哨兵机制

12.分片集群

13.Redis到底为什么那么快?

用户空间、内核空间

常见的IO模型

(1)阻塞IO

(2)非阻塞IO

(3)IO多路复用

14、Redis网络模型

1.缓存穿透

问题原因

查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库从而导致宕机

解决方案

我们将DB的数据预热到Redis让缓存拥有全量数据,再从缓存预热到布隆过滤器,然后使用布隆过滤器对请求进行过滤,如果查询的key存在于布隆过滤器之中则对其放行可以去Redis中进行查询,反之不存在则直接返回,这样就不会再有请求打到数据库因为数据且同步在缓存和过滤器中你要查的数据在这里能查到你就查,查不到就返回

布隆过滤器可以用于检索一个元素数据是否在一个集合中

其原理就是存储时将一个Key通过三次hash计算得出的hash值对应在数组中的位置由0改为1,查询时根据你的Key三次hash计算算出在数组中的位置,如果一致则说明数据在布隆过滤器中反之不存在

布隆过滤器存在的问题

2.或者将空值缓存到Redis也可以解决这个问题,也就是Redis查不到然后去数据库中查询我们不对查询解决做判空不不管数据存在还是不存在都缓存到Redis,具体根据业务场景来决定

  //从数据库查询
                CoursePublish coursePublish = getCoursePublish(courseId);
//                if (coursePublish != null){
                    //查询完成再存储到redis
                    redisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish), 300 + new Random().nextInt(100), TimeUnit.MINUTES);
//                }
                return coursePublish;

2.缓存击穿

问题原因

给一个Key设置了过期时间,当Key过期的时候,恰好这个时间点大量的并发请求过来,在缓存中查询不到就去数据库中查询,而从数据库查询的结果缓存到Redis花费的时间又比较久因为有可能是很多张表汇总的数据,此时大量的请求在这个时间间隙去访问数据库从而压垮数据库

解决方案

互斥锁:线程1查询缓存未命中就会获取互斥锁然后去数据库查询数据然后写入缓存最后释放锁,此时线程二也来缓存查询数据也没查到那他也回去获取互斥锁但是此时互斥锁还在线程1手里所以他获取不到那么他就会休眠一会然后不断的重试去获取锁,等线程1将数据写入缓存并且释放锁之后,线程2因为它是不断重试的所以线程1一旦释放他就获取到了从而获取到缓存的数据。

设置key的逻辑过期时间

在设置key的时候,设置一个过期时间字段一块存入缓存中,不给当前key设置过期时间,当查询的时候,从redis取出数据后判断时间是否过期,如果过期则开通另外一个线程进行数据同步,当前线程正常返回数据,这个数据不是最新

3.缓存雪崩

问题原因

缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

解决方案

解决方案主要是可以将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

redisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish), 300 + new Random().nextInt(100), TimeUnit.MINUTES);

4.双写一致

问题原因

很多业务场景使用到Redis那么就需要保证缓存和数据库的数据是同步一致的,这样才能让用户从缓存层查询到最新的数据

其中人们比较熟知的是先删除缓存在操作数据库,或者先操作数据库在更新缓存,其实这是错误的,因为这两种方式不是原子性总有一个先执行一个后执行,如果并发较多就无法保证线程1在执行的过程中线程2从缓存查到的是否是脏数据,所以这种方式不可取。

解决方案

使用MQ我们的数据库的数据一旦发生变更我们就将变更后的数据也就是全量数据进行获取,此数据作为消息发送到MQ然后我们的可以监听MQ的消息队列,将监听到的消息也就是发生改变的数据通过Redis客户端对缓存进行更新操作且删除之前Redis中存在的数据

使用阿里canal组件,canal相当于MySQL的从节点他会去监听MySQL的binlog日志,这个日志记录的就是MySQL的DDL和DML也就是对数据库的操作和增删改的操作然后将监听到的数据通过MQ发送到Redis的客户端然后进行更新从而达到双写一致问题,也可在当前canal监听类下直接注入Redis客户端直接对缓存操作即可

5.持久化机制

问题原因

Redis是存储在内存当中的,一旦Redis发生故障或者宕机那么存储在内存中的数据就会丢失,在企业中数据丢失是不允许的。

解决方案

RDB

RDB也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。

手动

save命令:由Redis主进程生成RDB文件,如果文件数据量很多没有立即生成完毕的话,比如他生成时间需要五秒,在这5秒之内如果有新的线程命令过来,他不会进行处理就会造成阻塞等待,直到这次RDB文件生成完成,才能继续接受新的命令

bgsave命令:由子进程来完成RDB持久化,就相当于异步执行,就算异步执行的时间太久也没有关系,由子进程完成RDB,主进程可以持续处理用户请求,不受影响。

自动

上面两种都是以手动的方式才会执行持久化,如果说你正常运行然后突然宕机你还没来得及做持久化,那么数据就丢了,所以我们要实现让他隔一段时间就做一次持久化,然后在Redis内存就提供了自动持久化的方式,在redis.conf文件中可以进行配置,具体配置就是多少秒内至少有几个key被修改那么就执行bgsave进行持久化,并且RDB的其他配置也可以在Redis.conf中配置,比如可以修改RDB文件名称,也可以对RDB文件进行压缩,压缩的好处是节省了磁盘,但是压缩的过程会消耗CPU的资源,所以一般不开启压缩。

原理介绍

就是说当满足条件就会触发bagesave完成异步的持久化,异步的持久化就是开启一个子进程,由子进程去完成内存数据的读取和写入RDB文件,因为他是异步的所以主进程就几乎是0阻塞的,为啥说几乎0阻塞呢,就是说把内存数据写入RDB这个过程确实实现了0阻塞,但是子进程需要去主进程拿数据这个动作叫fork,但是fork的过程是阻塞的,因为此时主进程只能干这件事不能干其他的,所以我们必须加快fork的速度,才能让主进程更快的去接受用户请求,避免阻塞。

那么fork他是这样实现的,就是说在操作系统当中分为物理内存和虚拟内存,任何一个进程操作物理内存其实就是操作虚拟内存,那么虚拟内存会维护一个页表的东西,这个页表就是一个映射文件他会映射虚拟内存中物理内存的地址,从而找到物理内存真实的数据

1、然后你的子进程fork主进程之前,主进程会先进行数据的读取去内存当中,其实就是通过页表找到虚拟内存从而找到物理内存的数据进行读的操作,然后为了不堵塞会开启一个子进程

2、此时子进程并没有把数据直接复制一份而是把页表映射文件复制了一份,因为它可以通过页表找到内存中的数据,找到之后进行读取

3、读完数据之后写RDB文件,写完RDB文件之后就要替换掉原来磁盘中的旧RDB文件,每次RDB持久化往磁盘写数据的bgsave操作都要经历这个过程

这里面临一个问题就是

因为子线程生成RDB是异步的,那么意味着在子进程正在RDB的期间比如需要五秒,在这五秒之内,主进程收到了更新的用户请求,那么他就会更改内存中的数据,就有可能导致子进程在去通过页表读取的数据跟主进程接收到新命令修改内存数据它们两个不一致,那么Redis是这样解决的,他会去物理内存也就是把原来的数据挪动到这个副本,然后主进程对副本进行写的操作,不会对子进程正在读取的内存数据操作,更改的数据和没更改的数据分开,然后等子进程生成RDB完成后,再将数据保持一致,这样子进程在通过页表读取数据生成RDB时,数据就是一致的了

AOF

Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件

原理介绍

AOF也叫追加文件,为啥叫追加文件,因为AOF的本质其实就是把Redis接收到的写操作累加记录到一个文件当中,那么这个文件其实就是记录Redis写操作的一个命令日志,比如将来Redis出现了故障你只需要去读取文件,把文件中的命令,从头开始一个一个在执行一遍就好了,然后你的数据就会恢复到原始的状态,然后AOF默认是关闭的,需要手动去开启,修改就是去Redis.conf配置文件中的appendonly 改成yes就可以了,然后AOF还有一个记录频率就是多久记录一次命令,一共有三种常用的是,everysec意思就是每1秒刷盘

出现的问题

因为是记录命令,AOF文件会比RDB文件大的多。而且AOF会记录对同一个key的多次写操作,但只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同效果。

RDB于AOF的区别

6.数据过期策略

问题原因

Redis对数据设置数据的有效时间,数据过期以后,就需要将数据从内存中删除掉。可以按照不同的规则进行删除,这种删除规则就被称之为数据的删除策略(数据过期策略)

解决方案

惰性删除

惰性删除:设置该key过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key

例子
set name zhangsan  10 get name   //发现name过期了,直接删除key

优点 :对CPU友好,只会在使用该key时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查

缺点 :对内存不友好,如果一个key已经过期,但是一直没有使用,那么该key就会一直存在内存中,内存永远不会释放

定期删除

定期删除:每隔一段时间,我们就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查,并删除其中的过期key)。

定期清理有两种模式:(每次执行时间这么短是为了不影响主进程的操作,一次清理不完等一下在清理就好了)

SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,以通过修改配置文件redis.conf 的hz 选项来调整这个次数

FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms

优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。

缺点:难以确定删除操作执行的时长和频率。

总结:Redis的过期删除策略:惰性删除 + 定期删除两种策略进行配合使用。

7.数据淘汰策略

问题原因

当Redis中的内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略。

解决方案

Redis支持8种不同策略来选择要删除的key

  • noeviction: 不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。
  • volatile-ttl: 对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰
  • allkeys-random:对全体key ,随机进行淘汰。
  • volatile-random:对设置了TTL的key ,随机进行淘汰。
  • allkeys-lru: 对全体key,基于LRU算法进行淘汰
  • volatile-lru: 对设置了TTL的key,基于LRU算法进行淘汰
  • allkeys-lfu: 对全体key,基于LFU算法进行淘汰
  • volatile-lfu: 对设置了TTL的key,基于LFU算法进行淘汰

一般项目中使用以下两种具体根据业务场景使用

LRU(Least Recently Used)最近最少使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。(key1是在3s之前访问的, key2是在9s之前访问的,删除的就是key2)

LFU(Least Frequently Used)最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。(key1最近5s访问了4次, key2最近5s访问了9次, 删除的就是key1)

8.秒懂Redis分布式锁

问题原因

这段代码的意思是一个线程获取优惠卷数量如果优惠卷为空那么就抛出异常,反之优惠卷还有就减去一个,然后重新设置Redis中优惠卷的数量,如图所示

/* 抢购优惠券
 * @throws InterruptedException 
*/

public void rushToPurchase() throws InterruptedException {

//获取优惠券数量    
Integer num = (Integer) redisTemplate.opsForValue().get(“num”);
//判断是否抢完    
if (null == num || num <= 0) { 
  throw new RuntimeException(“优惠券已抢完")
}
//优惠券数量减一,说明抢到了优惠券   
 num = num - 1;    
//重新设置优惠券的数量
redisTemplate.opsForValue().set("num", num);

}

那么此时有这样一种情况同时有两个线程同时进行查询优惠卷然后进行扣减,如图所示,那么就有可能两个线程同时查询到唯一的1张优惠卷,然后此时的线程一进行扣减操作,然后因为线程二也查询到了剩余的1张优惠卷他也进行扣减操作,那么1张优惠卷被两个线程同时扣减了,那么就变成了-1也就出现了超卖情况。

解决方案

我们都知道java里面有锁例如synchronize就可以解决这个问题如图所示,线程1进行优惠卷扣减操作先获取互斥锁,然后进行扣减完成后在释放锁,此时线程二由于线程一占用锁他就会获取锁失败,就会不断进行尝试知道线程一释放锁他才会获取到从而进行扣减

但是这种方案只能满足单体项目也就是单个JVM来进行上锁,如果是分布式微服务,同一份代码部署多个实例,则就无法满足了,如图所示,所以我们就用到了分布式锁,当线程一8080对优惠卷进行操作时他会去分布式锁新增一条记录证明已经有线程持有锁了,此时线程二就无法获取锁,就会不断进行尝试获取锁,等什么时候线程一释放锁,才能轮到线程二

9.分布式锁实现原理

setnx

Redis实现分布式锁主要利用Redis的setnx命令,他的原理是这样的,加锁流程是一个线程来了之后先去获取锁,如果获取到了锁那么他就去执行自己的业务代码,执行完成后直接释放锁,然后当有其他线程想要来获取锁的时候,那么就会返回给这个线程一个null就是说已经有其他线程获取锁了,然后这个线程就会阻塞,也就是获取锁失败了

然后这里涉及到两个问题:

1.在设置锁时一定要添加锁的过期时间,如果不添加就有可能,你这个线程获取锁成功然后宕机了,你还没有释放锁,那么其他线程就不能继续获取锁了,因为锁还没释放,所以我们必须得加一个锁失效的时间,假如服务宕机没关系,到了释放锁的时间就会自动释放锁,不会造成死锁

2.但是加上锁的过期时间了,就会出现一个问题,假如你的业务执行的时间太久了,已经超过了释放锁的时间,然后你还没有执行完,那么就会自动释放锁,那么这个时候其他线程来获取锁,就可以获取成功,这样就不能保证业务执行的原子性,就会影响你的业务数据。

# 添加锁,NX是互斥、EX是设置超时时间
SET lock value NX EX 10
# 释放锁,删除即可
DEL key

redisson

使用redisson实现的分布式锁,也是基于setnx实现的,他的执行流程就是,首先一个线程来了以后他先会加锁,加锁完成后就可以去操作Redis,然后就是在他加锁成功以后,他会另开启一个线程进行监控,一般都管他叫看门狗,他的作用就是会不断的监听持有锁的线程,每隔(锁的过期时间除以3的时间),就给这个持有锁的线程的时间做一次续期的操作,每次都会重置这个过期的时间,比如锁的失效时间是30秒,每次续期都会重新设置30秒的过期时间,然后执行完成后需要手动的释放锁

还有一个好处就是,比如线程A已经持有锁了,那么线程B进来了不会马上拒绝,他会自己不断的尝试获取锁,等线程A释放锁之后,线程B就可以马上持有锁。性能也得到了提升

10.主从同步

问题原因

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。一般都是一主多从,主节点负责写数据,从节点负责读数据,主节点写入数据之后,需要把数据同步到从节点中。

解决方案

redis已经默认实现主从之间的数据同步解决方案分为以下两种

全量同步:

第一:从节点请求主节点同步数据,其中从节点会携带自己的replication id和offset偏移量。

第二:主节点判断是否是第一次请求,主要判断的依据就是,主节点与从节点是否是同一个replication id,如果不是,就说明是第一次同步,那主节点就会把自己的replication id和offset发送给从节点,让从节点与主节点的信息保持一致。

第三:在同时主节点会执行bgsave,生成rdb文件后,发送给从节点去执行,从节点先把自己的数据清空,然后执行主节点发送过来的rdb文件,这样就保持了一致

当然,如果在rdb生成执行期间,依然有请求到了主节点,而主节点会以命令的方式记录到缓冲区,缓冲区是一个日志文件,最后把这个日志文件发送给从节点,这样就能保证主节点与从节点完全一致了,后期再同步数据的时候,都是依赖于这个日志文件,这个就是全量同步

增量同步:


增量同步指的是,当从节点服务重启之后,数据就不一致了,所以这个时候,从节点会请求主节点同步数据,主节点还是判断不是第一次请求,不是第一次就获取从节点的offset值,然后主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步

11.哨兵机制

问题原因

我们项目Redis都是集群模式的方式,主节点负责写,从节点负责读,那么生产环境下一旦主节点宕机,就无法接收用户写的操作,就会出现问题。

解决方案

Redis提供了哨兵机制终极目的就是为了在宕机时快速恢复,其核心功能有三个

监控:Sentinel 会不断检查您的master和slave是否按预期工作。

自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主。

通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端,也就是告诉客户端最新的主节点是谁。

Redis哨兵机制核心关键点有两个

服务状态监控:

Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令: 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。

哨兵选主规则:

首先判断主与从节点断开时间长短,如超过指定值就排该从节点 然后判断从节点的slave-priority值,越小优先级越高 如果slave-prority一样,则判断slave节点的offset值,越大优先级越高 最后是判断slave节点的运行id大小,越小优先级越高。

12.分片集群

问题原因

主从和哨兵集群可以解决高可用宕机时快速恢复、高并发读的问题。但是依然有两个问题没有解决: 海量数据存储问题 高并发写的问题

解决方案

使用分片集群可以解决上述问题

分片集群特征:

1、集群中有多个master,每个master保存不同数据

2、每个master都可以有多个slave节点

3、master之间通过ping监测彼此健康状态(不需要哨兵来监控,各自进行监控)

4、客户端请求可以访问集群任意节点,最终都会被转发到正确节点

分片集群不需要哨兵机制,一旦宕机,那么客户端是怎么知道存储到那个master的呢?

Redis 分片集群引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key通过 CRC16 计算出他的hash值后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽,假如你想将一部分数据放到一个Redis节点中那么就可以指定他的Key为一致,也可以指定key前面的一部分为一致。

13.Redis到底为什么那么快?

Redis快的原因是因为

1、Redis是纯内存操作,执行速度非常快

2、采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题

3、使用I/O多路复用模型,非阻塞IO

用户空间、内核空间

拿Linux系统举例其中一个进程使用的内存情况划分为两部分:内核空间、用户空间

用户空间:只能执行受限的命令,权限比较低,不能直接调用系统资源必须通过内核提供的接口才能访问。

内核空间:权限大可以调用一切系统资源

它们二者的关系就好比,我们在电脑上打开微信发送给你的朋友张三今晚吃火锅,其中打开微信相当于开启一个进程,编辑的聊天信息今晚吃火锅就相当于在用户空间操作的,那么编辑完的信息是通过什么样的方式发送出去的呢?,首先我们电脑都有一个硬件叫做网卡它能够连接互联网找到张三进行消息发送,但是我们编辑的内容属于在用户空间,可是用户空间是不能直接操控网卡发送消息的,这个时候就需要内核空间操作网卡把消息发送出去,简单说就是用户空间没有权限操作网卡的设备但是内核空间有,用户空间需要内核空间所提供的接口才能把消息发送出去。

其中Linux系统为了提高IO效率,会在用户空间和内核空间加入缓冲区
1、当我们要写数据时需要从用户空间的缓冲区把数据拷贝到内核的缓冲区,然后再去写入到设备,这些设备就包括磁盘或者网卡这些硬件。

2、当我们去读取设备时也是一样先从设备读到内核缓冲区,再由内核缓冲区拷贝到用户缓冲区,就比如你给张三发微信,编辑好的内容是在用户的缓冲区,你需要把这些内容拷贝到内核的缓冲区,然后再由内核的指令操作硬件比如网卡,然后把消息给发出去,如果张三给你回复消息,接收到的消息是由网卡过来的,然后读到内核缓冲区,在由内核缓冲区拷贝到用户缓冲区,才能在微信上看到张三给你回复的消息。

在整个过程中涉及到各种状态的切换,其实真正映像我们IO效率的有两个原因

1、在用户空间需要数据需要去内核空间获取,假如内核空间没有数据用户则只能等待数据就绪,假如内核一直没有数据就在这白等,这就是一个效率的浪费。

2、数据的拷贝需要从内核到用户,写数据需要用户拷贝到内核,这种来回的拷贝非常影响性能,所以说我们想要提升IO的效率,就是从这两点出发解决,减少无效的等待、减少用户与内核之间数据的拷贝。

常见的IO模型

因为Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度, I/O多路复用模型主要就是实现了高效的网络请求

  (1)阻塞IO

1、用户进程去内核读取数据(比如网卡数据),但是内核还没有数据也就是还没到达,那么内核就需要等待数据,内核等待数据的过程中此时用户进程处于阻塞状态

2、数据到达内核并将数据拷贝到用户缓冲区,但是拷贝的这个过程,用户进程依然是阻塞等待的,只有当拷贝完成,用户进程解除阻塞,才可以处理数据

可以看到,阻塞IO模型中,用户进程在两个阶段都是阻塞状态。

(2)非阻塞IO

1、用户进程去内核读取数据(比如网卡数据)数据可能尚未到达,内核需要等待数据到来,此时内核会返回一个异常给用户进程,用户进程拿到异常后他会再次尝试读取,循环往复知道数据就绪

2、内核将数据拷贝到用户缓冲区,拷贝过程中,用户进程依然阻塞等待,拷贝完成时用户进程才会接触阻塞,处理数据

可以看到,非阻塞IO第一阶段是非阻塞的,第二阶段是阻塞的,但是虽然是非阻塞可性能并没有得到提高,因为阶段一重复获取机制也就是忙等会导致CPU空转,CPU使用率暴增。

(3)IO多路复用

利用单个线程来同时监听多个Socket,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。

1、用户进程调用select 同时监听多个 Socket,并阻塞等待数据

2、用户进程一旦找到就绪的Socket也就是有数据可读可写时,就会调用recvfrom读取数据然后内核拷贝到用户空间,如果有多个准备就绪的Socket那么用户进程就会循环处理。

IO多路复用是利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。不过监听Socket的方式、通知的方式又有多种实现,

常见的有:select  poll  epoll

select和poll只会通知用户进程有Socket就绪,但不确定具体是哪个Socket ,需要用户进程逐个遍历Socket来确认

epoll则会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间

14、Redis网络模型

Redis网络模型其实就是一个IO多路复用+事件派发机制,也就是说客户端请求来了之后,都会交给我们的IO多路复用,相当于做一个事件的监听,无论是增删改查请求客户端Socket事件都拿过来,提前定义好事件处理器然后去对应不同的事件,派发给不同的处理器去处理,其中在网络上做了优化,分别是在接收参数转换成Redis命令和响应客户端这里加入了多线程的操作减少网络IO,因为Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度.

 

  • 19
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值