第4章 客户端-客户端通信协议

Redis是用单线程来处理多个客户端的访问,因此作为Redis的开发和运维人员需要了解Redis服务端和客户端的通信协议,以及主流编程语言的Redis客户端使用方法,同时还需要了解客户端管理的相应API以及开发运维中可能遇到的问题。

几乎所有的主流编程语言都有Redis的客户端(http://redis.io/clients),不考虑Redis非常流行的原因,如果站在技术的角度看原因还有两个:第一,客户端与服务端之间的通信协议是在TCP协议之上构建的。第二,Redis制定了RESP(REdis Serialization Protocol,Redis序列化协议)实现客户端与服务端的正常交互,这种协议简单高效,既能够被机器解析,又容易被人类识别。例如客户端发送一条set hello world命令给服务端,按照RESP的标准,客户端需要将其封装为如下格式(每行用\r\n分隔):

powershell 复制代码
*3
$3
SET
$5
hello
$5
world

这样Redis服务端能够按照RESP将其解析为set hello world命令,执行后回复的格式如下:

powershell 复制代码
+OK

可以看到除了命令(set hello world)和返回结果(OK)本身还包含了一些特殊字符以及数字,下面将对这些格式进行说明。

1.发送命令格式

RESP的规定一条命令的格式如下,CRLF代表"\r\n"。

powershell 复制代码
*<参数数量> CRLF
$<参数1的字节数量> CRLF
<参数1> CRLF
...
$<参数N的字节数量> CRLF
<参数N> CRLF

依然以set hell world这条命令进行说明。参数数量为3个,因此第一行为:

powershell 复制代码
*3

参数字节数分别是355,因此后面几行为:

powershell 复制代码
$3
SET
$5
hello
$5
world

有一点要注意的是,上面只是格式化显示的结果,实际传输格式为如下

代码,整个过程如图4-1所示:

powershell 复制代码
*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$5\r\nworld\r\n

2.返回结果格式

Redis的返回结果类型分为以下五种,如图4-2所示:

  • 状态回复:在RESP中第一个字节为"+"。
  • 错误回复:在RESP中第一个字节为"-"。
  • 整数回复:在RESP中第一个字节为":"。
  • 字符串回复:在RESP中第一个字节为"$"。
  • 多条字符串回复:在RESP中第一个字节为"*"。

    我们知道redis-cli只能看到最终的执行结果,那是因为redis-cli本身就是按照RESP进行结果解析的,所以看不到中间结果,redis-cli.c源码对命令结果的解析结构如下:
powershell 复制代码
static sds cliFormatReplyTTY(redisReply *r, char *prefix) {
	sds out = sdsempty();
	switch (r->type) {
	case REDIS_REPLY_ERROR:
	// 处理错误回复
	case REDIS_REPLY_STATUS:
	// 处理状态回复
	case REDIS_REPLY_INTEGER:
	// 处理整数回复
	case REDIS_REPLY_STRING:
	// 处理字符串回复
	case REDIS_REPLY_NIL:
	// 处理空
	case REDIS_REPLY_ARRAY:
	// 处理多条字符串回复
	return out;
}

为了看到Redis服务端返回的"真正"结果,可以使用nc命令、telnet命令、甚至写一个socket程序进行模拟。下面以nc命令进行演示,首先使用nc127.0.0.16379连接到Redis:

powershell 复制代码
nc 127.0.0.1 6379

状态回复:set hello world的返回结果为+OK:

powershell 复制代码
set hello world
+OK

错误回复:由于sethx这条命令不存在,那么返回结果就是"-"号加上错误消息:

powershell 复制代码
sethx
-ERR unknown command 'sethx'

整数回复:当命令的执行结果是整数时,返回结果就是整数回复,例如incr、exists、del、dbsize返回结果都是整数,例如执行incr counter返回结果就是":"加上整数:

powershell 复制代码
incr counter
:1

字符串回复:当命令的执行结果是字符串时,返回结果就是字符串回复。例如get、hget返回结果都是字符串,例如get hello的结果为"$5\r\nworld\r\n":

powershell 复制代码
get hello
$5
world

多条字符串回复:当命令的执行结果是多条字符串时,返回结果就是多条字符串回复。例如mget、hgetall、lrange等命令会返回多个结果,例如下面操作:首先使用mset设置多个键值对:

powershell 复制代码
mset java jedis python redis-py
+OK

然后执行mget命令返回多个结果,第一个*2代表返回结果的个数,后面的格式是和字符串回复一致的:

powershell 复制代码
mget java python
*2
$5
252
jedis
$8
redis-py

有一点需要注意,无论是字符串回复还是多条字符串回复,如果有nil值,那么会返回$-1。

例如,对一个不存在的键执行get操作,返回结果为:

powershell 复制代码
get not_exist_key
$-1

如果批量操作中包含一条为nil值的结果,那么返回结果如下:

powershell 复制代码
mget hello not_exist_key java
*3
$5
world
$-1
$5
jedis

有了RESP提供的发送命令和返回结果的协议格式,各种编程语言就可以利用其来实现相应的Redis客户端。

相关推荐
想要打 Acm 的小周同学呀1 小时前
Redis三剑客解决方案
数据库·redis·缓存
rkmhr_sef1 小时前
Redis 下载与安装 教程 windows版
数据库·windows·redis
是姜姜啊!2 小时前
redis的应用,缓存,分布式锁
java·redis·spring
库库林_沙琪马2 小时前
Redis 缓存穿透、击穿、雪崩:问题与解决方案
数据库·redis·缓存
Hanson Huang3 小时前
【存储中间件API】MySQL、Redis、MongoDB、ES常见api操作及性能比较
redis·mysql·mongodb·es
落落落sss3 小时前
MongoDB
数据库·windows·redis·mongodb·微服务·wpf
小丑西瓜6665 小时前
分布式简单理解
linux·redis·分布式·架构·架构演变
早起的年轻人8 小时前
Docket Desktop 安装redis 并设置密码
数据库·redis·缓存
qw9498 小时前
Redis(高阶篇)03章——缓存双写一致性之更新策略探讨
数据库·redis·缓存
Ciderw10 小时前
MySQL日志undo log、redo log和binlog详解
数据库·c++·redis·后端·mysql·面试·golang