redis的主要事件源包括信号,网络,文件和时间事件,文件事件没看到用于做什么。
1、信号事件
redis忽略了SIGHUP和SIGPIPE信号,当收到SIGTERM信号时,将会置标志位,在定时任务serverCron中安全退出,这个定时任务1毫秒执行一次。
2、网络事件
1)redis启动的时候使用anetTcpServer创建服务的fd,并开始监听服务的fd。
2)创建服务fd的读事件,事件处理函数acceptTcpHandler。
3)当接收到connect请求时,redis为新连接生成一个新的fd,并创建一个redisClient。
4)设置连接noblock,nodelay,创建新fd的读事件,事件处理函数readQueryFromClient。
5)处理完client的命令后,创建一个写事件,给client回复响应,回复完删除这个写事件。
3、时间事件
redis的时间事件是通过双向链表实现的,目前redis主要的时间事件就是serverCron,1毫秒执行一次,其它的定时任务都是在serverCron中调用的,因为时间事件只有这一个,所以redis的实现逻辑都是O(n)的。
4、其它
1)linux版本的redis是使用epoll模型来处理并发请求的,使用LT的模式,socket是非阻塞的。
LT(level triggered)是缺省的工作方式,并且同时支持block和no-blocksocket。在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表。
ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once)。
2)redis处理事件的函数先找到最近的时间事件,然后把这个时间作为epoll_wait的超时时间参数,这样做可以把时间事件之外的时间都用于处理其它事件,但redis的时间事件是1毫秒一次,所以应该每次超时时间都是0。