5. 关于效率的讨论
Last updated
Was this helpful?
Last updated
Was this helpful?
[toc]
Redis一个比较出名的点, 就是吞吐量如此恐怖的怪兽, 居然是跑在单线程上的, 即使到今天, 他的绝大部分常用功能依旧是单线程的. 这一节我们会介绍为什么Redis会这么钟爱单线程.
首先单线程不代表客户端的请求是串行/顺序执行的, 单线程也能并发处理客户端请求, 我们上一节介绍了IO Multiplexing
, 这使得我们一次性可以接非常多的请求, 然后那个fd先就绪那个先响应.
继续, 设想一下, 如果你每秒都能处理百万级的请求, 但是你还是使用单线程, 那么是不是说明单线程对你来说就已经够用了? 那么我们把这句话延伸一下: 如果单线程就够用, 那就是说Redis对CPU就是无所谓的. 为什么呢? 你需要设想一下Redis的工作模式:
Redis并不是一个IO密集型服务:(如果在不开AOF的情况下)基本都不会涉及磁盘IO操作, 它的工作模式就是: 从内存里读, 往内存里写
Redis同时也不是一个CPU密集的服务: 因为它也不怎么需要大量计算
这种特征导致, 等待网络IO成为最大的瓶颈
那么Redis你的弱点到底是什么呢? Redis真正的瓶颈在于等待网络IO上, 等待网络传输带来的延迟, 以及等待用户输入中消耗的时间. 这才是真正的问题. "等待网络IO"这种问题我们已经在上一节讨论过了, 合理的处理IO Multiplexing
能妥善处理网络IO的问题. 所以Redis对于Multiplexing的处理一定会是一大亮点
Redis内部使用file event handler, 这个文件事件处理器(其实所谓的事件就是指IO就绪), 本身是单线程的, 因此决定了Redis也得是单线程的, 就是这个文件事件处理器搞的IO多路复用, 监听着众多连接其上的socket, 它的结构为:
管理多个连接其上的socket
IO多路复用的处理核心
事件分派器
事件处理器: 连接应答, 命令接收, 命令回复
[使用多线程的问题] 不错, 你会说搞多线程, 大家一起读, 这样不会出现有的fd明明已经就绪了, 但是来不及读的情况. 但是多线程的引入会带来一些麻烦: 上锁 / 开发/维护麻烦 / 如果一个Redis里搞了多个线程, 那么线程切换所带来的耗时反而可能导致性能下降.
[不使用多线程的问题] 如果不使用多线程, 那对于多核心的机器就利用的不充分, 对于这个问题的解决, 一个是现在都不会给你一整个机器, 经过虚拟化以后我们主要讨论分到了几个核心, 几个内存, 另外如果真的有好几个核心, 你可以拿来起好几个Redis实例, 用来做主从, 分片, 扩展你缓存的吞吐能力
[为数不多用到了多线程的场景] 我们简单介绍一下. Redis在最新的几个版本里也搞了一些多线程, 举个例子, DEL
命令用于删除一个键, 小键好说, 大键的话需要删很久, 这个问题并不是网络IO造成的, 因此Multiplexing在这个问题上也帮不了你. 单线程模型下, 所有人就必须得等你删完才行. 因此对于大键我们是这样办的, 我们先解除这个键与值的匹配, 然后你去搞你的, 我在后台再开一个线程把东西删了