mini-redis源码分析-概述篇
mini-redis 是一个 Tokio 编程示例性质的项目,其中演示了一些 Tokio 异步编程模式。在进行网络编程时,我们可以参考这些示例使用这些模式。下面我们对 mini-redis 的源码进行分析,并学习其中的异步网络编程模式。并在充分理解的基础上对其进行重新实现。
我们将仓库的实现层次整体绘制为下图所示的架构图。
mini-redis 整体基于 Tokio 进行开发。在进行日志记录时,使用 Tokio 团队主推的 tracing 作为门面,支持将程序运行中产生的 Metric、Log、Trace 基于 OpenTelemetry 发送到 Prometheus、Jaeger 等可观测方案中。在连接的处理方面,在 Tokio 提供的 TCP 流的基础上封装 Connection 并在这一层实现 Redis 帧到字节流的编解码和收发。在数据的读写方面,mini-redis基于内存实现连接间共享的数据存储,并使用 Mutex 互斥锁进行保护,防止数据竞争问题。在帧结构的基础上,命令模块将若干帧解析为 Redis 命令。Redis 命令在执行时,调用存储模块提供的功能实现数据的读写等动作。为了对外提供统一接口,在命令模块的基础上进行封装,整合为客户端库和服务端库。最终利用客户端库和服务端库的能力,构建客户端和服务端的命令行程序以及端到端的测试模块。
项目创建及日志配置
下面我们开始进行项目的搭建。
- 创建 Library 类型的 Rust 项目。完成后我们得到下面的项目结构。其中 lib.rs 包含作为示例的 add 函数和一个测试模块。
1 | . |
- lib.rs 中定义自己的错误类型以供一般路径上使用,使用dyn trait类型作为错误类型可以减少大量转换工作。重新定义结果类型,通过默认的错误类型,简化结果类型的声明。
1 | /// 应用中普通路径上的错误类型,为了简单起见我们直接使用dyn trait对象。 |
- 下面我们为这个项目引入日志相关的依赖。tracing 提供日志门面,tracing-subscriber 提供日志输出能力。我们暂时不需要考虑将日志写入文件或发送到成熟的日志服务,因此我们不需要引入 opentelemetry 和 opentelemetry 需要的特定实现库。下面的配置步骤也就只需将日志输出到终端即可。
1 | cargo add tracing |
- 在 lib.rs 中定义一个简单的日志初始化函数。将 tracing 输出的日志导出到终端上显示。在测试模块中执行创建测试函数,确认日志功能工作正常。
1 | fn set_up_logging() -> crate::Result<()> { |
- 运行测试函数,观察终端输出。在运行时可以通过 RUST_LOG=debug 来调整日志输出级别。指定日志级别为 debug 后,终端输出如下图。可以看到 debug 及以上级别日志可以正常输出,且日志级别有高亮显示。同时,在 span 内部的日志输出上都附带了 span 名称 root。
总结
这一篇展示了 mini-redis 的模块框架,对其结构进行了简单介绍;定义了项目中的通用错误和结果类型,简化了在后续使用结果类型时的声明工作量;并对项目的日志输出能力进行了配置,使其具备了结构化日志输出能力。下面的几篇中,将对存储模块、帧解析、命令解析、构筑整体工作结构的客户端、服务端库等进行展开介绍。