1.redis的单线程怎么理解?
redis的单线程指的是客户端接收请求-解析请求-进行数据读写操作-返回数据给客户端这个过程都是由一个主线程进行的,对于命令的执行是由单线程进行的。但是redis还会开启三个后台线程
三个后台线程分别处理:
close_file:关闭 AOF、RDB 等过程中产生的大临时文件
aof_fsync:将追加至 AOF 文件的数据刷盘(将命令缓存写入磁盘中的aof文件中)
lazy_free:惰性释放大key
因为redis是基于内存的,所以它对数据的处理的局限不在于cpu限制,所以就没必要用多线程,比较多线程切换消耗较大
但随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上,所以6.0后出现了io多线程
所以redis实际上是有一个主线程、三个后台线程、以及多个io线程
2.为什么Redis 采用单线程那么快
有如下几个原因:
- Redis 的大部分操作都在内存中完成,并且采用了高效的数据结构,因此 Redis 瓶颈可能是机器的内存或者网络带宽,而并非 CPU,既然 CPU 不是瓶颈,那么自然就采用单线程的解决方案了;
- Redis 采用单线程模型可以避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,而且也不会导致死锁问题。
- Redis 采用了 I/O 多路复用机制处理大量的客户端 Socket 请求,IO 多路复用机制是指一个线程处理多个 IO 流,就是我们经常听到的 select/epoll 机制。简单来说,在 Redis 只运行单线程的情况下,该机制允许内核中,同时存在多个监听 Socket 和已连接 Socket。内核会一直监听这些 Socket 上的连接请求或数据请求。一旦有请求到达,就会交给 Redis 线程处理,这就实现了一个 Redis 线程处理多个 IO 流的效果。
3.Redis的分布式锁是怎么实现的?
- 可重入:可重入指的是在同一个线程里的不同业务中都需要先后获取一个锁;实现:锁是通过一个哈希表实现的,key是线程id,value是重入次数。当线程想要获取锁时,会先查询锁是否存在,如果不存在该锁,则直接创建获取该锁,如果存在则先比对key是否为自己的线程id,如果不是则获取失败,如果是则value的次数+1
- 可重试:当第一次获取该锁时出现失败,并不会直接重试,而是订阅一个channel,去订阅到该锁的publish出的消息,等占有锁的线程释放锁后,才会收到释放的消息,然后才开始while循环重试获取该锁
- 超时续约:如果锁的自动释放时间设置为-1,就会利用看门狗机制(默认30s),开启一个守护线程,每隔一段时间(30/3 = 10s)重置超时时间
4.Redis的过期删除策略是怎么样的?
每当我们对一个key设置了过期时间,就会把这个key以及过期时间存储到一个过期字典中,每次操作数据之前,都会先从这个【过期字典】查询key对应的过期时间,与当前时间比对是否过期。
对于过期的key,Redis 使用的过期删除策略是【惰性删除+定期删除】
- 惰性删除:不会主动检查key的是否过期,直到需要访问该key时,才会检查过期性,如果过期了才删除
- 定期删除:每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期key