Redis:单机处理逻辑。

面对高吞吐量的访问需求,同一个db这个key-value的hashtable面临着来自客户端的并发访问。这个过程中hashtable可能会访问相同桶、rehase,如何保证客户端并发访问时hashtable的线程安全?Redis的做法很直接:单线程的处理来自所有客户端的并发请求。

多路复用

Redis服务器端对于命令的处理是单线程的,但是I/O层面却同时面向多个客户端并发的提供服务,并发到内部单线程的转化通过多路复用框架实现,如下图所示。

上图中粗线描述的就是这个单线程主循环的主要逻辑:

  • 首先从多路复用框架中select出已经ready的fileDescriptor,aeApiPoll函数的实现根据实际宿主机器的具体环境分为4种实现方式:epoll、evport、kqueue,以上实现都找不到时使用select这种最通用的方式。
  • ready的标准是依据每个fd的interestSet,如已有数据到达kernel(AE_READABLE)、已准备好写入数据(AE_READABLE)。
  • 对于上一步已经ready的fd,redis会分别对每个fd上已ready的事件进行处理,处理完相同fd上的所有事件后,再处理一下ready的fd。fd的事件处理逻辑根据所属场景主要分为3种实现:

acceptTcpHandler处理redis的serverSocket上来自客户端的连接建立请求。他会为客户端对应的id注册其关注的事件(interestSet):AE_READABLE,以便感知该fd后续发来的数据;

readQueryFromClient处理来自客户端的数据,他会读取每一个完整的命令并执行,再将执行结果暂存,待客户端对应fd准备好写时向客户端写入。所以该方法需要为fd注册AE_WRITABLE事件并以sendReplyToClient作为处理器。所以该方法需要为fd注册AE_WRITABLE事件并以sendReplyToClient作为处理器。对于multi(批处理的事务),需等到multi包含一个全部的命令时才进行执行;

sendReplyToClient将暂存的执行结果写回客户端。

  • 对来自客户端的命令执行结束后,接下来处理定时任务(processEvent)。
  • asApiPoll的等待时间取决于定时任务处理(TimeEvents)逻辑。
  • 本次主循环完毕,进入下一次主循环的beforeSleep逻辑,后者负责处理数据过期、增量持久化的文件写入等任务。

定时任务处理

在主线程的主循环执行过程中,有一个对象持续的流转并记录着Redis的事件状态,Redis就是由这些事件驱动运转的:

typedef struct aeEventLoop {
    int maxfd;
    int setsize;
    long long timeEventNextId;
    time_t lastTime;
    aeFileEvent *events;
    aeFiredEvent *fired;
    aeTimeEvent *timeEventHead;
    int stop;
    void *apidata;
    aeBeforeSleepProc *beforesleep;
} aeEventLoop;

其中events和fired共同维护着和多路复用框架交互的各个事件,而aeTimeEvent*以链表的形式维护着待处理的定时任务(aeTimeEvent):

typedef strut aeTimeEvent{
    long long id;
    long when_sec;
    long when_ms;
    aeTimeProc *timeProc;
    aeEventFinalizerProc *finalizerProc;
    void *clientData;
    struct aeTimeEvent *next;
} aeTimeEvent;

其中两个when_表示这个任务下一次执行时间,timeProc表示定时任务的执行逻辑。timeProc函数的返回值为这个任务执行完了以后下次再执行的时间间隔,对于周期性的定时任务,timeProc每次总是返回一个正数(执行间隔),而对于一次性的任务timeProc则返回AE_NOMORE表示“不存在下次执行”。

上节提到“aeApiPoll的等待超时时间取决于定时任务”,redis只有一个线程,循环的处理来自客户端的请求和定时任务,如何保证每个定时任务按时执行呢?下图展示了定时任务的执行过程。

如上图所示,aeApiPoll方法最多等到待处理定时任务中最近的一个的执行时刻,如果多路复用框架未返回已ready的事件,则Redis直接执行定时任务。

每次一个aeTimeEvent执行结束后,都会根据其timeProc方法的返回值更改其下次执行的时间(when_sec/when_ms),如果timeProc返回AE_NOMORE,则将aeTimeEvent删除之。

默认情况下,Redis指挥有一个周期性定时任务serverCron存在,他负责:

  • 主动的处理过期key
  • 执行命令执行频度、网络读写、内存使用等统计信息
  • hash表的增量rehase
  • 内存数据持久化逻辑(GBSAVE/AOF)
  • 清理过期的客户端连接
  • 主备复制的重连

serverCron通过redisServer类的hz属性进行控制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值