Redis 为什么快
很多人接触 Redis 的原因是因为它快,一般说到 Redis 为什么快,一般都会说 Redis 是基于内存的数据库,操作内存和操作磁盘的时间相差很大,还有是 Redis 使用了单线程,减少了多线程频繁切换带来的损耗。
本文从我对 Redis 的理解,列出 Redis 快的原因。
基于内存
Redis 是基于内存的存储,众所周知,访问内存比访问磁盘快得多。虽然 Redis 有持久化的机制,最终的数据都会以某种形式落盘,用于防止服务器宕机造成数据丢失,但使用 Redis 过程中的读写都是对内存进行操作的,访问速度很快。
数据结构
Redis 的数据结构同样也提高了数据库查询的效率,主要有两个方面:
- 存储方式是键值形式(key-value),底层是哈希表,哈希表的时间复杂度是 O(1)。有哈希表就一定有哈希冲突,Redis 对于哈希冲突的解决方案是链地址法,这样在数据多的时候访问性能也会下降,但 Redis 使用了一些优化方式来解决这个问题。
- Value 有五种数据类型,分别是字符串、列表、集合、有序集合、哈希表,每一种数据类型底层都对应着多种实现和优化。
上面提到关于数据结构的两点也是 Redis 快的原因之一。
单线程
单线程和多线程各有好处,针对 Redis 的使用场景使用多线程的预期效果和实际效果如下:
为什么会出现这种情况呢?对于 Redis 来说,一个关键的原因是多线程访问共享内存,为了保证共享资源的准确性,就需要额外的逻辑来保证,比如加锁、请求队列等。
比如现在如果两个线程同时执行 set a b 和 set a c,那么最后 a 的值是 b 还是 c 呢?因此 Redis 如果在读写内存时,如果采用多线程,需要处理共享资源的问题,不管是哪种机制去处理,都会有一定的性能损耗。
但 Redis 也不是只用单线程,上面说的单线程的情况,是对键值进行存储时使用了单线程,因为在键值操作时,单线程已经能满足大部分业务场景。
在 Redis 6 中提到了使用多线程,是在操作键值时使用多线程吗?其实不是,Redis 6 的多线程是在内存和网络 IO 的地方使用了多线程。比如一个请求进来,接受、解析请求时用多线程,处理完请求后的回包处理也用了多线程,因为这些操作都是互相独立、互不影响的,使用多线程可以明显提高 Redis 的性能。
IO 多路复用
Redis 还有一个提升性能的点——IO 多路复用,这个 IO 多路复用就是经常听到的 select/epoll 机制。
Redis 的 IO 复用是 epoll 机制,简单说一下流程:
- 首先内核监听多个套接字,这样做是为了保证不会因为某个客户端的请求阻塞导致其他客户端请求的等待,这里只能对客户端请求的并发做了处理。
- 而对于请求的处理机制,Redis 使用了 epoll 机制,epoll 一旦监听到有请求到达时,这些请求会被放在一个队列里,Redis 对队列进行处理,处理时会使用对应的处理函数。
有兴趣可以深入了解 select/epoll 机制。
总结
| 原因 | 说明 |
|---|---|
| 基于内存 | 内存读写远快于磁盘读写 |
| 数据结构优化 | 哈希表 O(1) 查找 + 5 种 value 类型底层优化 |
| 单线程模型 | 避免多线程竞争共享资源的锁开销 |
| IO 多路复用(epoll) | 高效处理大量并发连接,避免阻塞 |