news 2026/3/22 12:41:02

Redis 协议兼容:编写一个支持 RESP 协议的 KV Server

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis 协议兼容:编写一个支持 RESP 协议的 KV Server

标签:#Redis #RESP #Go语言 #网络编程 #中间件开发 #Socket


📜 一、 破译 RESP:Redis 的通信语言

RESP 是一个基于文本的协议,极其简单且高效。它主要由前缀符号CRLF (\r\n)组成。

客户端发送给服务端的,永远是一个RESP 数组 (Array),其中包含了命令和参数。

核心数据类型:
类型前缀示例含义
简单字符串++OK\r\n操作成功
错误--Error message\r\n报错
整数::100\r\n数字结果
多行字符串$$5\r\nhello\r\n字符串 “hello” (长度5)
数组**2\r\n$3\r\nGET\r\n$1\r\na\r\n命令数组["GET", "a"]

举个栗子:
当你输入SET name gemini时,客户端实际发送的是:

*3\r\n (数组长度 3) $3\r\nSET\r\n (第一个元素,长度3,内容SET) $4\r\nname\r\n (第二个元素,长度4,内容name) $6\r\ngemini\r\n (第三个元素,长度6,内容gemini)

🏗️ 二、 架构设计:从 Socket 到存储

我们要实现的 Server 架构非常清晰:

TCP Socket

服务端内部逻辑

Accept

Read Bytes

Command Object

Response Object

Write Bytes

TCP Listener (Port 6379)

Connection Handler

RESP 解析器

命令执行引擎 (Map)

RESP 序列化器

redis-cli (客户端)

你的 Go 程序


💻 三、 代码实战:Go 语言实现

为了保持代码简洁,我们只实现最核心的SETGET命令。

1. 编写 RESP 解析器 (Parser)

这是最难的部分。我们需要读取流,解析出*开头的数组。

packagemainimport("bufio""fmt""io""net""strconv""strings""sync")// 内存数据库,简单的并发安全 MapvarkvStore=struct{sync.RWMutex mmap[string]string}{m:make(map[string]string)}funcmain(){// 1. 启动 TCP 监听listener,err:=net.Listen("tcp",":6379")iferr!=nil{fmt.Println("Error starting server:",err)return}fmt.Println("🚀 Mini-Redis is running on port 6379...")for{conn,err:=listener.Accept()iferr!=nil{continue}// 为每个连接启动一个协程gohandleConnection(conn)}}funchandleConnection(conn net.Conn){deferconn.Close()reader:=bufio.NewReader(conn)for{// 2. 解析 RESP 协议 (简化版,只处理 Arrays)// 读取第一个字节,必须是 '*'prefix,err:=reader.ReadByte()iferr==io.EOF{break}ifprefix!='*'{// 这里简单处理,忽略非数组请求或 pingreader.ReadString('\n')continue}// 读取数组长度line,_:=reader.ReadString('\n')arrLen,_:=strconv.Atoi(strings.TrimSpace(line))// 读取命令参数args:=make([]string,0,arrLen)fori:=0;i<arrLen;i++{// 读取多行字符串前缀 '$'reader.ReadByte()// 读取长度line,_=reader.ReadString('\n')strLen,_:=strconv.Atoi(strings.TrimSpace(line))// 读取实际内容buf:=make([]byte,strLen)io.ReadFull(reader,buf)args=append(args,string(buf))// 读取末尾的 CRLFreader.ReadString('\n')}// 3. 执行命令response:=executeCommand(args)// 4. 发送响应conn.Write([]byte(response))}}
2. 编写命令执行引擎 (Handler)

这里处理业务逻辑,并返回符合 RESP 格式的字符串。

funcexecuteCommand(args[]string)string{iflen(args)==0{return"-ERR empty command\r\n"}cmd:=strings.ToUpper(args[0])switchcmd{case"PING":return"+PONG\r\n"case"SET":iflen(args)!=3{return"-ERR wrong number of arguments for 'set' command\r\n"}key,val:=args[1],args[2]kvStore.Lock()kvStore.m[key]=val kvStore.Unlock()return"+OK\r\n"// 简单字符串case"GET":iflen(args)!=2{return"-ERR wrong number of arguments for 'get' command\r\n"}key:=args[1]kvStore.RLock()val,ok:=kvStore.m[key]kvStore.RUnlock()if!ok{return"$-1\r\n"// Null Bulk String (表示不存在)}// 返回 Bulk Stringreturnfmt.Sprintf("$%d\r\n%s\r\n",len(val),val)default:returnfmt.Sprintf("-ERR unknown command '%s'\r\n",cmd)}}

🎩 四、 见证奇迹时刻

1. 运行你的服务端
go run main.go# 输出: 🚀 Mini-Redis is running on port 6379...
2. 使用官方 Redis-CLI 连接

打开一个新的终端窗口:

redis-cli -p6379

输入命令测试:

127.0.0.1:6379>PING PONG127.0.0.1:6379>SET user gemini OK127.0.0.1:6379>GET user"gemini"127.0.0.1:6379>GET unknown(nil)

成功了!你的程序现在“骗”过了官方客户端,它以为自己在跟真正的 Redis 对话。


🔍 五、 为什么这很重要?

掌握 RESP 协议解析,意味着你拥有了开发以下系统的能力:

  1. Redis Proxy (代理):像 Twemproxy 或 Codis 一样,拦截客户端请求,实现分片(Sharding)或读写分离。
  2. 兼容 Redis 的新数据库:比如你可以用 RocksDB 做底层存储,外面套一层 RESP 协议,做一个持久化的“大容量 Redis”。
  3. 流量录制与回放:通过解析 RESP 流量,分析热 Key 或进行故障复现。

🎯 总结

Redis 之所以流行,除了它快,还因为它简单的协议设计。RESP 协议通过简单的文本规则,实现了高性能与易读性的平衡。
今天的代码虽然简单,但它已经包含了一个数据库中间件的雏形:监听 -> 解析 -> 路由 -> 执行 -> 响应

Next Step:
目前的解析器是同步阻塞的,效率较低。
尝试引入 Go 的bufioScanner机制,或者尝试支持PIPELINE(一次发送多条命令),这将极大提升你的 Server 吞吐量。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 5:34:28

12.1 全身动力学与任务空间控制:基于零空间投影的层级化任务实现

12.1 全身动力学与任务空间控制:基于零空间投影的层级化任务实现 12.1.1 引言:人形机器人全身控制的范式转变 传统工业机械臂的控制通常围绕单一的末端执行器任务(如轨迹跟踪)展开,其控制目标明确且自由度有限。然而,人形机器人是一个具有高度运动冗余(通常拥有30个以…

作者头像 李华
网站建设 2026/3/22 11:48:08

【开题答辩全过程】以 宜居房屋交易系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华
网站建设 2026/3/17 1:25:44

ssm474的高校运动会管理网站

目录高校运动会管理网站&#xff08;SSM474&#xff09;摘要开发技术源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;高校运动会管理网站&#xff08;SSM474&#xff09;摘要 高校运动会管理网站基于SSM框架&#xff08;SpringSpringMV…

作者头像 李华
网站建设 2026/3/18 12:27:48

Python 使用 Chainlit + Ollama 快速搭建本地 AI 聊天应用

使用 Chainlit Ollama 快速搭建本地 AI 聊天应用 大家好&#xff01;今天分享一个超级简单的本地 AI 聊天界面实现方案&#xff1a;Chainlit Ollama。 无需部署复杂的后端&#xff0c;只需本地运行 Ollama&#xff0c;再用几行 Python 代码&#xff0c;就能拥有一个支持模型切…

作者头像 李华
网站建设 2026/3/19 10:03:50

单位冲击函数和单位冲击响应

这是一个信号与系统、控制理论以及工程数学中的核心概念。我们来系统地梳理一下单位冲击函数&#xff08;狄拉克δ函数&#xff09;和单位冲击响应的定义与性质。一、 单位冲击函数 (Unit Impulse Function) - δ(t) 单位冲击函数δ(t)是一个广义函数或分布&#xff0c;它不是通…

作者头像 李华