代码库概览
1. 概述
本项目实现了一个受 Redis 启发的轻量级内存键值存储。它支持基本操作,如 GET、SET、DEL 和 EXPIRE,并使用追加只文件(AOF)实现了简单的持久化机制。
2. 核心数据结构
Database
中央内存数据存储。它使用哈希映射(std::unordered_map<std::string, Value>)来存储键和值。每个 Value 是一个标记联合(tagged union),可以表示字符串、列表、哈希或集合。

AOFWriter
处理追加只文件持久化。每个写操作(SET、DEL、EXPIRE)都被序列化为一条命令并追加到 AOF 文件中。写入器使用缓冲流以最小化系统调用。
Parser
一个简单的 RESP(Redis 序列化协议)解析器。它从客户端套接字读取原始字节,并将其转换为结构化的命令对象(例如 Command::Type::GET、Command::Type::SET)。

Connection
表示一个客户端 TCP 连接。它拥有套接字、一个读取缓冲区和一个写入缓冲区。它与 Parser 交互以解码请求,并与 Database 交互以处理这些请求。
Server
主入口。它 TCP 端口,接受新连接,并管理事件循环。它使用非阻塞套接字和基于 epoll 的事件循环来处理数千个并发连接。
3. 主流程
- 启动:
Server绑定到端口6379并进入事件循环。 - 请求解析:当客户端发送数据时,
Connection将其读取到其缓冲区中。Parser将 RESP 协议解码为一条Command。 - 命令执行:
Command被分派到Database。例如,GET命令返回给定键的值,而SET命令更新键值对并写入到AOFWriter。 - 持久化:每个修改命令都被追加到 AOF 文件中。在重启时,服务器重放 AOF 文件以恢复状态。
- 响应写入:命令的结果被序列化回 RESP 格式,并在客户端套接字变为可写时写入到客户端套接字。

4. 关键设计决策
- 单线程事件循环:像 Redis 一样,服务器使用单线程事件循环来保证操作简单性和原子性。
- 非阻塞 I/O:套接字设置为非阻塞模式,允许事件循环在没有线程的情况下处理许多连接。
- 值的标记联合:使用标记联合可以避免小值的堆分配,并使类型检查更加明确。
- AOF 持久化:我们使用追加只日志而不是快照来保证持久性。这确保了在崩溃情况下最多丢失一秒的数据。