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

Redis服务器剖析

2015-08-03 19:32 591 查看
本文主要分析redis服务器的工作的实现原理,事件,以及redis与memcache处理高并发请求的对比。

1. Redis的工作流程

首先从宏观上来看一下redis如何处理一个请求,以set key value为例,分为以下4步:

(1) client向server发送命令请求set key value



client会将

set key value
转换成协议:

*3\r\n$3\r\nSET\r\n$3\r\nKEY\r\n$5\r\nVALUE\r\n然后将这段协议内容发给服务器。

(2) 当client与server的socket可用时(IO多路复用技术,稍后介绍),server将协议内容保存到redisClient的输入缓冲区;然后分析命令,保存到argc和argv中。

(3) 命令执行器

根据argv[0]在command table中查找set命令,执行预备操作(判断参数、身份验证等)后,调用命令执行;

(4) 当client socket变为可写状态时,服务器执行命令回复处理器(函数),将保存在client输出缓冲区的"OK"回复给client。

2. Redis的事件

Redis服务器是一个事件驱动程序,event是server对socket操作的一种抽象,每次的accept、read、write等都会产生一个event,服务器需要处理如下两类事件:

file event(文件事件)
time event(时间事件)
接下来主要介绍file event。

首先需要了解IO多路复用,这一点请参考另一篇博客。
接下来,我们来了解redis的网络事件处理器——file event handler

file event handler采用IO multiplexing来监听多个socket,并根据socket的任务来关联不同的handler(functoin);
每一个accept、read、write、close都会产生一个event,socket被封装在event中;

它的构成如下:



如图,IO多路复用程序负责监听多个socket,每当一个socket可用时,IO多路复用程序便会产生一个file event,并将产生事件的socket放入一个队列,如下图:



当一个socket产生的event被处理完毕后,IO多路复用程序才会向文件事件分派器传送下一个socket。

由以上,file event handler以单线程方式运行,但通过IO多路复用技术来监听socket,既实现了高性能的网络通信模型,又可以很好地与redis server中其它同样以单线程运行的模块对接,从而保证了redis实现的简单性。

我们来看IO多路复用程序是如何实现的:

Redis的IO multiplexing的实现都是通过包装常见的select、epoll(Liunx)、kqueue(BSD)、evport(Solaris)的IO多路复用函数库实现的,具体在文件ae_select.c, ae_epoll.c, ae_kqueue.c中实现;

Redis源码中用#include macro定义了相应的规则,使系统自动选择性能最高的IO多路复用函数库作为其底层实现。

3. Redis与Memcached的比较

从实验中可以看出,redis的速度非常快;作为单线程的redis为什么快?先给出以下三点原因:

绝大部分操作时基于内存的(非常快);
采用单线程,避免了高并发时线程之间的上下文交换和竞争条件;
采用异步非阻塞IO,它的性能远高于同步阻塞IO。

另外,redis采用了epoll+自己实现的简单event框架,绝不在io上浪费一点时间。由于网络IO是瓶颈,redis在这一点上作了很好地处理。

有的人分析了CAS(compare & set或者compare & swap)问题,CAS是memcached中一种比较方便的防止竞争修改资源的一种方法。虽然开销非常小,但不排除高并发情况下对memcached的性能有微小影响。

CAS是cpu指令支持的一种原子操作,GCC、windows、C++中各有对CAS不同的实现,类似的原子操作还有:

fetch and add(原子+1),test and set(写值到内存并返回旧值)等等。

下面的网址有如何用CAS来实现无锁队列(lock free queues):

http://coolshell.cn/articles/8239.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: