您的位置:首页 > 数据库 > Redis

单线程的REDIS为什么这么快?

2017-04-04 21:40 736 查看
REDIS是单线程处理所有请求,和一般经典实际上推荐的方式相反,那么单线程串行处理,为什么依然能够做到很快呢?知乎上的一个答案如下,其中线程切换和锁不是性能主要影响因素的观点和一般的答案都不同
作者:杨海坡
链接:https://www.zhihu.com/question/19764056/answer/20241839
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

纯内存数据库,如果只是简单的 key-value,内存不是瓶颈。一般情况下,hash 查找可以达到每秒数百万次的数量级。

瓶颈在于网络 IO 上。

根据你测的的 10000/s 来看,客户端和 redis 应该是部署在两台不同的机器,并且是使用同步的方式请求 redis. 每次请求需要通过网络把请求发送到 redis 所在的机器,然后等待 redis 返回数据。时间大部分消耗在网络传输中。

如果把 redis 和客户端放在同一台机器,网络延迟会更小,一般情况下可以打到 60000 次每秒甚至更高,取决于机器性能。

锁不是影响性能的主要因素。线程锁 (mutex_lock) 只有在遇到冲突的情况下性能会下降,而正常情况下,遇到冲突的概率很低。如果只是简单的加锁、释放锁速度是非常快的,每秒钟上千万次没问题。memcache 内部用到了大量的锁,并没有见到性能降低。

线程也不是影响吞吐量的重要因素。如第一点来说,一般情况下,程序处理内存数据的速度远高于网卡接收的速度。使用线程好处是可以同时处理多条连接,在极端情况下,可能会提高响应速度。

使用 epoll 或 libevent 等因为异步非阻塞 IO 编程只能这么做。与之对应的是同步阻塞 IO 编程,使用多进程或多线程实现多条连接的处理,比如 apache。一般情况下,异步非阻塞 IO 模型性能是远高于同步阻塞 IO 模型的,可以参考 nginx 与 apache 性能的对比。

libevent 并不比 redis 自己实现的 ae_event 慢,代码多是应为 ae_event 只实现了 redis 需要的功能,而 libevent 则具有更多的功能,比如更快的定时器、buffer event 模型,甚至自带了 DNS、HTTP 协议的处理。并且 libevent 更通用,而 redis 只专注于 linux 平台。

最后回答题主问题,快在哪?
1、纯内存操作
2、异步非阻塞 IO

本博客的个人观点:
1. REDIS很注重让线程的每次操作都尽量简短,会将功能细分成多个逻辑块,每个逻辑块都分别让线程在自己的独立的时间片完成,而不是一个时间片做整个功能。
比如,主从服务器的复制功能。从服务器收到SLAVE OF的命令后,会记录信息,然后交由serverCron来进行socket建链,然后再次交由serverCron进行slave向master的ping操作,然后再次交由serverCron进行Pong的接收。这样其他功能在每次功能块执行结束后都能被执行,而不至于线程的时间都堵塞在某一个功能上。

REDIS epoll 讲解 https://www.cnblogs.com/yuxingfirst/archive/2012/11/18/2776012.html
/* Include the best multiplexing layer supported by this system.
* The following should be ordered by performances, descending. */
#ifdef HAVE_EVPORT
#include "ae_evport.c"
#else
#ifdef HAVE_EPOLL
#include "ae_epoll.c"
#else
#ifdef HAVE_KQUEUE
#include "ae_kqueue.c"
#else
#include "ae_select.c"
#endif
#endif
#endif

建链流程:
2 initServer->aeCreateEventLoop->aeApiCreate 创建epoll实例 state->epfd = epoll_create(1024);
3.initServer->listenToPort->anetUnixServer->anetTcpServer 创建本地socket fd-1
4. initServer->aeCreateFileEvent->aeApiAddEvent->epoll_ctl(epfd,fd-1);把处理函数acceptTcpHandler注册到wfileProc/rfileProc

5. main->acMain->aeProcessEvents->aeApiPoll->epoll_wait->如果有数据->wfileProc/rfileProc 回调到 acceptTcpHandler->accept,建链完成
建链完成后,会针对这个新的fd创建redis client结构
而在client的创建过程中,createClient会再次注册一个event,回调函数readQueryFromClient,来进行从这个新socket的数据的接收
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: