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的pid是18741。
除了out.18741
是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来实现的。因此它可以处理并发。
当我们开一个客户端:
也追踪到了客户端数据的到达:
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:
该进程是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。