万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • Redis

    • Redis简介
    • 缓存的认识
    • Linux安装Redis的正确方式
    • Redis数据类型
    • Redis底层数据结构
    • Redis回收策略与缓存过期
    • Redis持久化
    • Redis发布与订阅
    • Redis事务
    • Redis Lua脚本
    • Redis 慢查询
    • Redis 监视器
    • Redis通讯协议
      • 请求响应模式
      • 请求数据格式
      • 协议响应格式
      • 协议解析及处理
      • 命令处理流程
    • Redis事件处理机制与NIO演进
    • Redis 常用命令
    • Redis与MyBatis整合
    • Spring、SpringBoot整合Redis
  • 集群架构

  • Redis
  • Redis
2022-03-29
目录

Redis通讯协议

# Redis通讯协议

Redis(单进程单线程)是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。

应用系统和Redis通过Redis协议(RESP)进行交互。

# 请求响应模式

Redis协议(RESP)位于TCP层之上,即客户端和Redis实例保持双工的连接。

protocol_1

有以下几种请求响应模式:

  • 串行化-ping-pong:串行化是最简单模式,客户端与服务器端建立长连接,连接通过心跳机制检测(ping-pong),ack应答。客户端发送请求,服务端响应,客户端收到响应后,再发起第二个请求,服务器端再响应。telnet 和 redis-cli 发出的命令都属于该种模式。网络传输命令耗时,性能较低。

    protocol_2

  • 双工批量-管道(Pipelining) (opens new window):双工模式指请求响应交叉进行,不会混淆(TCP双工),适用于批量请求,批量响应。

    管道的作用是将一批命令进行打包,然后发送给服务器,服务器执行完按顺序打包返回。

    一次pipeline(n条命令)= 一次网络时间 + n次命令时间。(注意,换行符的转换)

    protocol_3

    通过Jedis可以很方便的使用pipeline:

    Jedis redis = new Jedis("192.168.1.111", 6379); 
    redis.auth("12345678"); //授权密码 对应redis.conf的requirepass密码 
    Pipeline pipe = jedis.pipelined(); 
    for (int i = 0; i <50000; i++) { 
      pipe.set("key_"+String.valueOf(i),String.valueOf(i)); 
    }
    //将封装后的PIPE一次性发给redis 
    pipe.sync();
    
  • 原子批量-事务 (opens new window):将一组命令放在同一个事务中进行处理。

  • 发布订阅-pub/sub:一个客户端触发,多个客户端被动接收,通过服务器中转。

  • 脚本批量-lua (opens new window):客户端向服务器端提交一个lua脚本,服务器端执行该脚本。

# 请求数据格式

Redis客户端与服务器交互采用序列化协议(RESP)。

请求以字符串数组的形式来表示要执行命令的参数。Redis使用命令特有(command-specific)数据类型作为回复。

Redis通信协议的主要特点有:

  • 客户端和服务器通过 TCP 连接来进行数据交互, 服务器默认的端口号为 6379 。
  • 客户端和服务器发送的命令或数据一律以 \r\n (CRLF)结尾。
  • 在这个协议中, 所有发送至 Redis 服务器的参数都是二进制安全(binary safe)的。

# 内联格式(telnet)

可以使用telnet给Redis发送命令,首字符为Redis命令名的字符,格式为 str1 str2 str3......

[wenwl@localhost ~]$ telnet 127.0.0.1 6379
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
ping
+PONG
keys *
*1
$2
k2

# 规范格式(redis-cli)

  • 间隔符号,在Linux下是\r\n,在Windows下是\n
  • 简单字符串 Simple Strings, 以 "+"加号 开头
  • 错误 Errors, 以"-"减号 开头
  • 整数型 Integer, 以 ":" 冒号开头
  • 大字符串类型 Bulk Strings, 以 "$"美元符号开头,长度限制512M
  • 数组类型 Arrays,以 "*"星号开头

用SET命令来举例说明RESP协议的格式:

127.0.0.1:6379> set k1 hello-world
OK

查看appendonly.aof,查看实际请求的数据

# 实际发送应该是 *3\r\n$3\r\nset\r\n$2\r\nk1\r\n$11\r\nhello-world\r\n
*3
$3
set
$2
k1
$11
hello-world

#实际响应数据
+OK\r\n

# 协议响应格式

RESP协议响应格式分为状态回复、错误回复、整数回复、批量回复和多条批量回复:

  • 状态回复:回复的第一个字节是“+”

    "+OK"
    
  • 错误回复:对于错误,回复的第一个字节是“ - ”

    -ERR unknown command 'foobar'
    -WRONGTYPE Operation against a key holding the wrong kind of value
    
  • 整数回复:对于整数,回复的第一个字节是“:”

    ":6"
    
  • 批量回复:对于批量字符串,回复的第一个字节是$

    "$6 foobar"
    
  • 多条批量回复:对于多条批量回复(数组),回复的第一个字节是“*”

    "*3"
    

# 协议解析及处理

RESP协议解析及处理包括协议解析、调用命令、返回结果。

# 协议解析

用户在Redis客户端键入命令后,Redis-cli会把命令转化为RESP协议格式,然后发送给服务器。服务器再对协议进行解析,分为三个步骤:

  1. 解析命令请求参数数量:命令请求参数数量的协议格式为*N\r\n ,其中N就是数量,比如

    127.0.0.1:6379> set k1 hello-world
    

    打开aof文件可以看到协议内容

    *3\r\n
    $3\r\n
    set\r\n
    $2\r\n
    k1\r\n
    $11\r\n
    hello-world\r\n
    

    首字符必须是*,使用\r\n定位到行尾,之间的数就是参数数量了。

  2. 循环解析请求参数:首字符必须是"$",使用\r\n定位到行尾,之间的数是参数的长度,然后从\n后到下一个"$"之间就是参 数的值了,循环解析直到没有"$"。

# 协议执行

协议的执行包括命令的调用和返回结果。详细见命令处理流程.命令处理。

  • 判断参数个数和取出的参数是否一致
  • RedisServer解析完命令后,会调用函数processCommand处理该命令请求
  • quit校验,如果是“quit”命令,直接返回并关闭客户端
  • 命令语法校验,执行lookupCommand,查找命令(set),如果不存在则返回:“unknown command”错误。
  • 参数数目校验,参数数目和解析出来的参数个数要匹配,如果不匹配则返回:“wrong number of arguments”错误。
  • 此外还有权限校验,最大内存校验,集群校验,持久化校验等等。
  • 校验成功后,会调用call函数执行命令,并记录命令执行时间和调用次数
  • 如果执行命令时间过长还要记录慢查询日志
  • 执行命令后返回结果的类型不同则协议格式也不同,分为5类:状态回复、错误回复、整数回复、批量回复、多条批量回复。

# 命令处理流程

Redis命令处理整个流程包括:服务器启动监听、接收命令请求并解析、执行命令请求、返回命令回复等。

protocol_4

  1. Server启动时监听socket:启动调用 initServer方法,创建eventLoop(事件机制),注册时间事件处理器,注册文件事件(socket)处理器,监听 socket 建立连接。

  2. 建立Client:redis-cli建立socket,redis-server为每个连接(socket)创建一个 Client 对象创建文件事件监听socket,指定事件处理函数,读取socket数据到输入缓冲区,从client中读取客户端的查询缓冲区内容。

  3. 解析获取命令:将输入缓冲区中的数据解析成对应的命令,判断是单条命令还是多条命令并调用相应的解析器解析

  4. 执行命令:解析成功后调用 processCommand 方法执行命令,大致分三个部分:

    • 调用 lookupCommand 方法获得对应的 redisCommand
    • 检测当前 Redis 是否可以执行该命令
    • 调用 call 方法真正执行命令

    如下图:

    protocol_5

上次更新: 5/30/2023, 11:42:20 PM
Redis事件处理机制与NIO演进

Redis事件处理机制与NIO演进→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式