专栏首页源码阅读redis代码走读与编程实践——网络交互篇(上)
原创

redis代码走读与编程实践——网络交互篇(上)

导语

redis是一种内存数据存储系统,可被用作数据库、缓存、消息队列等;以高性能、高并发能力著称;本文分为上下两篇,其中上篇主要着眼于最简单的单机数据库&非事务命令场景,对网络框架相关代码进行走读,阐述redis服务器如何接收来自客户端的连接请求,建立连接并与响应客户端的指令,找到对应的处理代码;下篇主要是尝试编写简单的redis客户端,从最简单的建立连接开始,到和redis-server进行交互,借此加深对上篇阅读代码的理解,并在最后模仿redis-server的连接管理模型,实现一个简单的server demo。

概述

redis是基于事件驱动的单线程应用;事件收集器收集事件(这里主要是网络事件和定时事件)之后,分发到各个模块进行处理(在redis中是找到对应事件的注册回调函数);如下图所示:

配置相关

本文主要关注于网络事件模块的代码走读,为便于分析,会略过无关的代码和配置。

1. 服务端相关配置

因为后续需要通过修改相关的redis配置信息来配合一些实验,所以先介绍redis相关的一些配置信息:

a) redis通过启动命令redis-server [conf-file-path]命令指定配置文件

b) 若是不指定,则默认使用同目录下redis.conf文件作为配置文件

Redis.conf中和网络相关的配置包括:

a) port:指定监听端口号

b) bind: bind用于配置redis进程监听的IP地址;若是没有配置的话,redis进程会监听机器上的所有的IP

c) protected-mode no/yes: 配置保护模式是否开启

  1. 保护模式是redis的一个安全措施,用于避免redis被暴露到外网
  2. 保护模式开启,则只有本机的客户端可以连接到redis的服务进程
  3. 为使得redis服务可以被其他机器访问,需要关闭保护模式&bind非回环地址(现网场景下,需要配置密码requirepass)

d) timeout::配置client闲置多少秒之后,断开链接;0表示不启用, 为便于调试,实验环境我们不启用这个机制

e) logfile/loglevel: 配置日志文件的路径和等级

f) Maxclients: 表示redis服务器端,能接收的最大链接数

g) requirepass: 配置redis服务的密码

启动阶段

redis-server的网络模块在启动过程中主要完成两块工作:

  1. 解析配置文件和命令行参数,完成初始化工作;
  2. 根据配置信息,创建要监听的socket,并注册回调;

下面依次进行论述。

启动阶段

redis-server的网络模块在启动过程中主要完成两块工作:

l 解析配置文件和命令行参数,完成初始化工作;

l 根据配置信息,创建要监听的socket,并注册回调;

下面依次进行论述。

a) 解析配置及初始化

如代码所示

  1. 接口loadServerConfig,接收命令行参数,其中filename指定了配置的文件名;而options则指定了其他配置参数;最终都被存放到config数组中,传入到接口loadServerConfigFromString进行解析
  2. 接口loadServerConfigFromString,对字符数组进行按照\t\r\n进行分割;并且对于空串”\0”和”\#”不进行处理
  3. 所有的配置,都被解析,存放在类型为redisServer的全局变量server中;具体可参照源码,不再赘述

b) 创建监听socket并注册事件回调

所有配置信息都被读入到server结构体之后,接口initServer开始创建监听socket并注册回调,代码如下所示:

主要做了以下工作:

  1. l结构体aeEventLoop事件收集器
  2. 接口aeCreateEventLoop通过接口aeApiCreate创建一个epoll实例
  3. 接口listenToPort绑定所有IP上对应的端口,
  4. 通过接口aeCreateFileEvent注册监听的socket句柄,及对应的回调函数acceptTcpHandler

客户端连接建立阶段

连接建立请求检测轮询接口
连接建立请求接口

主要流程包括:

  1. 客户端请求建立连接触发监听接口读事件,从而触发回调acceptTcpHandler
  2. acceptTcpHandler调用接口anetTcpAccept来接收连接,分配对应socket
  3. 连接建立之后,通过acceptCommonHandler,创建描述客户端的类型为client结构体&注册事件监听和回调,并通过全局变量server的client链表管理所有的客户端
  4. 此外接口acceptCommonHandler还进行最大连接数检查(客户端连接数是否大于server.maxclients)和保护模式下检查(保护模式下未配置密码只允许本地访问),检查通过则连接正式建立

交互流程

redis客户端和服务器建立连接之后,即可以通过客户端向redis-server发送命令;执行流程如下所述:

客户端输入指令的主调接口
指令解析接口

主流程如下:

  1. 主循环通过接口aeProcessEvents收集已经有客户端数据上来的socket
  2. 对于有数据的socket,触发回调readQueryFromClient,读入客户端请求
  3. 针对非管道指令,通过调用链processInputBuffer->processMultibulkBuffer对请求的参数进行解析(同时校验请求的合法性,参数合法性、参数个数合法性、长度合法性等),解析的结果存放在client->argv和client->argc中
  4. 解析出客户端请求的各个字段之后,通过processCommand这个接口找到对应的命令结构体,执行其对应的回调

以上为redis网络交互模块,监听接口注册、连接建立、注册回调以及命令解析与交互的主要流程源码走读;因笔者能力有限,若有疏误欢迎留言指正;

参考资料

1. https://redis.io/

2. https://www.xilidou.com/2018/03/22/redis-event/

3. https://www.runoob.com/redis/redis-pipelining.html

4. https://cloud.tencent.com/developer/article/1005481

5. http://blog.chinaunix.net/uid-28541347-id-4238524.html

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Redis源码走读及编程实践——数据安全篇(一)

    redis作为内存数据库,为了防止因为程序bug或者机器故障导致的数据丢失,redis采取了多维度的措施来保障redis写入数据的安全。从单机层面:采取备份磁盘...

    王鹏程1990
  • redis代码走读与编程实践——网络交互篇(下)

    在文章《redis代码走读与编程实践——网络交互篇(上)》中,对redis连接请求与建立流程进行源码剖析和走读;本文主要尝试编写一个简单的redis客户...

    王鹏程1990
  • Redis源码走读及编程实践——数据安全篇(二)

    《Redis源码走读及编程实践——数据安全篇(一)》介绍了RDB的落地原理并走读了redis的RDB落地流程,本文继续介绍redis的另外一种数据落地机制AOF...

    王鹏程1990
  • CentOS使用dnf安装Redis

    代码改变世界-coding
  • Redis-3.2.9集群配置(redis cluster)

    本文参考官方文档而成:http://redis.io/topics/cluster-tutorial。经测试,安装过程也适用于redis-3.2.0。

    一见
  • Yii2 redis同步数据到mysql

    本次案例讲解将如何将商城中商品浏览次数通过缓存记录并写入mysql中 具体的redis安装过程暂且就省略了.....

    botkenni
  • Linux下Redis开机自启(Centos)

    Coxhuang
  • PHP+Redis 商品超卖

    码缘
  • Linux下 php7安装redis的方法

    以上所述是小编给大家介绍的Linux下 php7安装redis的方法,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家...

    砸漏
  • Linux下 php7安装redis的办法

    ??? 进入安装目录打开 cd redis-stable/src/redis-cli

    砸漏

扫码关注云+社区

领取腾讯云代金券