天天看点

redis的单线程

redis的worker是单线程的,所以redis是一把天然的锁。

但是,怎么才能知道worker是单线程的呢?

我们用这个命令来启动一个前台的redis:

strace -ff -o ../../test_redis/out ./redis-server 
           

我们将追踪所有

fork

系指令,并且把结果放在

../../test_redis_process

这个文件夹里,以

out

作为前缀。

运行之后,在

test_redis

目录下,我们看到:

-rw-r--r-- 1 root root 35690 May 22 18:55 out.18741
-rw-r--r-- 1 root root   134 May 22 18:55 out.18742
-rw-r--r-- 1 root root   134 May 22 18:55 out.18743
-rw-r--r-- 1 root root   134 May 22 18:55 out.18744

           

有4个文件。

redis的单线程

前台显示redis的pid是18741。

除了

out.18741

是redis本身的线程之外,其余三个都与redis的实际工作无关。

redis的单线程

我们查看linux18741进程的任务,有4个线程。和我们用strace追踪到的是一样的。

现在的问题是,这个

out.18741

的文件里有什么?以及,单线程的redis如何处理并发?

我们很自然的

vi out.18741

熟悉的东西找到了:

epoll_create(1024)                      = 5

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 7

bind(7, {sa_family=AF_INET, sin_port=htons(6379), 
sin_addr=inet_addr("0.0.0.0")}, 16) = 0

listen(7, 511)                          = 0

epoll_ctl(5, EPOLL_CTL_ADD, 6, {EPOLLIN, {u32=6, u64=6}}) = 0

epoll_wait(5, [], 10128, 0)             = 0

           

我们证明了,redis底层使用epoll来实现的。因此它可以处理并发。

当我们开一个客户端:

redis的单线程

也追踪到了客户端数据的到达:

read(8, "*3\r\n$3\r\nset\r\n$6\r\nuser:1\r\n$9\r\noce"..., 16384) = 40
           

我们知道,bgsave会触发rdb的持久化,这时会fork一个子进程来完成。

前台的log:

redis的单线程

该进程是19154。

我们在

out.18741

中查一下:

clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ff811c3c250) = 19154
write(1, "18741:M 22 May 2020 19:20:12.468"..., 74) = 74
read(3, 0x7ffefeed83cf, 1)              = -1 EAGAIN (Resource temporarily unavailable)
write(8, "+Background saving started\r\n", 28) = 28

           

它用了

clone

,当然这也是一种fork。

继续阅读