Redis Source Code Read Log( 1. bio, Backgound I/O)

Redis source code 版本: 5.0.7

Redis 启动后,main thread 中启动三个bio线程,分别执行三种任务:

#define BIO_CLOSE_FILE    0 /* Deferred close(2) syscall. */
#define BIO_AOF_FSYNC     1 /* Deferred AOF fsync. */
#define BIO_LAZY_FREE     2 /* Deferred objects freeing. */

1. BIO_CLOSE_FILE:   pthread callback task, 任务便是直接执行: close(fd); fd 通过 bioJob 对象的 arg1 域传入。

2. BIO_AOF_FSYNC: 任务是调用 linux: fdatasync(fd); fd 通过 bioJob 对象的 arg1 域传入。

3. BIO_LAZY_FREE: 主要是为了 free Redis server对象中16个redisDb中的的两张 hash table。通过 job 的 arg2, arg3 域传入。

三个线程各自维护一张 redis的 double list。在main thread中 通过 createBioJob 接口封装 job,push如该double list。而bio thread作为消费者,通过生产者消费者模式,pop 内部的 joblist,三个类型的thread 分别执行三种类型的 job。

这是典型的简单生产者消费者模式+jobQueue 的多线程模型,很容易理解。

关键是redis自身对bio线程的一些设置:

1. 设置线程栈大小:

/* Set the stack size as by default it may be small in some system */

pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr,&stacksize);
if (!stacksize) stacksize = 1; /* The world is full of Solaris Fixes */
// bio background job thread neead 4 MB stack size at least
while (stacksize < REDIS_THREAD_STACK_SIZE) {
     stacksize *= 2;
}
pthread_attr_setstacksize(&attr, stacksize);

2. set cancel 请求可用。可自行查询linux pthread cancel的内部机制,在 cond wait的情况下,cancel请求一般是可以被正确处理的。

 /* Make the thread killable at any time, so that bioKillThreads()
     * can work reliably. */
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

3. 处理了 SIGALRM 信号。

/* Block SIGALRM so we are sure that only the main thread will
     * receive the watchdog signal. */
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGALRM);
    if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
    {
        serverLog(LL_WARNING,
            "Warning: can't mask SIGALRM in bio.c thread: %s", strerror(errno));
    }

作用就是将 SIGALRM 信号,添加到 屏蔽字 中。该线程,便不再响应处理该信号了,只会被添加到pending que中一直阻塞,导致该信号一直被处于一个悬而未决的状态,也不允许系统采用默认处理方式处理。当然,只是该线程在active 情况下不处理,那么其他线程收到还是可以处理的。

为什么?

第一点,很好理解。

第三点,对于某个特殊信号,自己不处理,让其他线程统一处理,也可以理解。当然,SIGALRM信号有没有作为 watch dog信号在主线程里面被处理,还需进一步源码确认。

第二点,外部主动调用 bio 提供的 bioKillThreads() unclean stop thread, 而bio不提供 bioDeinit 去主动 join gracefully exit,有点奇怪,不过 bio 提供了bioWaitStepOfType 函数,去阻塞检测 不同任务的类型余量,当任务que为空,再 bioKill其实也可以。不同任务,其实除了第二种任务,进程退出可能有影响外,其他的进程,都是释放 fd 以及内存资源,可以让进程自动回收。

Redis 的实际情况是:

所以 redis-serve作为服务程序启动后,期望的是一直运行。虽然代码暂未通读,但是,某节点 dump之后,数据的丢失看来也是不可避免的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值