redis是单线程运行的存储服务,所以启动流程相对是比较好分析的,直接main函数走下来就可以了。
1.读取配置,redis的配置项来源有3种方式,(1)从配置文件里面读取,可以用 ./redis-server reds.conf 来读取redis的配置。(2)通过 --param value 的方式来配置单项属性。(3)如果在(1),(2)两种方式都没有配置的使用默认配置。
常见的配置项作用如下:
masterauth 如果master启用了密码,需要在slave上配置密码,才能连上master
requirepass 设置客户端认证的密码,默认不启用。
maxmemory 最大内存,redis在分配内存的时候均做了记录,如果内存占用超过此值,将启用最大内存策略来解决内存不够用的问题。
maxmemory-policy 最大内存策略
2.监听端口并注册文件事件,注册时间事件。
3.循环处理事件。
既然是单线程,如何决定要执行的下个事件?
- step1.时间事件保存在timeEventHead指针中,这是个链表,循环读取链表中的节点,执行所有已到期的事件(循环执行的事件以下个周期再次塞入队列)。选取最近一次的时间事件还有多久到来为t;
step2.等待t时间,如果在此期间有io事件,执行io事件,回到step1。
io事件处理
redis内部网络是使用异步io来完成,具体的io实现根据编译环境做了差异性处理,linux下是epoll,win下是select,macos为kqueue,函数作用都是大同小异的。首先注册一个监听事件,如果有客户端的连接到来,触发可读事件,调用函数acceptTcpHandler来执行连接处理,处理成功得到连接的socket句柄,创建客户的对象,并将该socket放入监听队列,那么下次客户端发送数据或者断开连接,我们就可以检测到了。处理客户端数据的回调函数是readQueryFromClient,接收到客户端数据以后,先作解析,然后放入各个处理函数中去处理,处理函数列表是:redisCommandTable.需要注意的是:tcp是流模式,并不是每次拿到的数据都是完整的,对于解析不了的多余数据,会放到下次数据的开头。在解析处理过后,将触发一个写io事件,在下次轮回获取可执行io事件的时候将结果数据返回给客户端。
时间事件
时间事件做的东西比较杂,函数入口是serverCron。
- 打印一些运行参数。
- 关闭连接超时的客户端(需开启timeout配置项)
- rehash数据库字典,循环1ms,每次rehash100个key(需开启activerehashing配置项)
- 检查BGSAVE或者BGREWRITEAOF是否已经执行完毕
- 集群相关操作。