mini-redis源码分析-帧解析篇
与许多网络协议一样,Redis客户端和服务器端之间的通信可以使用帧结构作为基本的构成指令。mini-redis中命令模块在命令解析时就是从帧结构出发。本篇就对帧的解析进行分析和实现。
Redis客户端与服务端之间的通信,整体上属于请求-响应模型,但是引入了流水线、推送等一些特例情况。在Redis的请求和响应中具有一些固定的形态。在请求中,命令总是表示为批量字符串的的数组,响应则可以是帧结构中的各种类型。每种类型消息的第一个字节总是用来标识消息的类型。\r\n
作为协议中的终止符,用于划分不同部分。
下面是一些消息的格式或示例,在文章的后半部分需要对这些命令进行解析并封装为 Rust 中的数据结构。
1 | +OK\r\n |
这些消息代表的类型分别为简单字符串、错误、整型、批量字符串、Null、数组。在 mini-redis 支持的几个命令中,利用这些帧结构即可实现支持的几个命令。
mini-redis源码分析-存储篇
概述篇对mini-redis的模块结构进行了介绍,并构建了具有日志能力的基本项目结构。存储篇将对mini-redis的数据存储进行分析,并在存储上实现其需要对外提供的功能。
提供的功能
在分析存储模块的实现前,我们首先对存储模块所需提供的功能进行分析。mini-redis 在整体上提供了两套功能,带有过期能力的KV存储、发布-订阅功能。
在KV存储方面,需要提供根据键获取值的 get 功能和提供键、值以及可选的有效期的 set 功能。同时,需要在请求-响应之外提供按照过期时间清理过期数据的能力。
在发布-订阅方面,需要提供 subscribe 功能用于订阅特定通道,从而在给定的通道上发布消息时进行接收;还需要提供 publish 功能用于向给定的通道上发布消息。
由于不同客户端的处理任务需要共享相同的存储,存储模块需要能够在不同任务间共享,并保证线程安全。
mini-redis源码分析-概述篇
mini-redis 是一个 Tokio 编程示例性质的项目,其中演示了一些 Tokio 异步编程模式。在进行网络编程时,我们可以参考这些示例使用这些模式。下面我们对 mini-redis 的源码进行分析,并学习其中的异步网络编程模式。并在充分理解的基础上对其进行重新实现。
我们将仓库的实现层次整体绘制为下图所示的架构图。
SQL窗口函数用法
malloc在glibc中的实现原理
在C++编程中,可以通过 new/delete
或 new[]/delete[]
在堆上进行内存分配和释放。Linux环境下,这些操作中的内存分配和释放往往由glibc中的 malloc()/free()
函数实现。在C编程中,更是直接通过 malloc()/free()
来进行堆上内存的分配和释放。
malloc作为操作系统和应用程序的中间层,向操作系统申请大块内存,按需求将其划分为小块内存分配到应用程序。在应用程序释放内存后,在整块内存可用时返回给操作系统。
这里我们对glibc中的malloc原理进行分析,以便分析其性能等特征。
Rust异步教程
网络编程中,对多个连接的并发处理是一个非常常见的需求。
要并发处理多个连接,最简单的思路就是使用OS线程,每个线程处理一个连接。这样每个控制流只处理一个连接上的数据收发,与大多数人的思维模式匹配,因此编写起来最容易,心智负担最低。但这种模式需要大量OS线程,消耗大量的系统资源,因此限制了这种模型的并发处理能力。
基于事件驱动编程则采用另一种思路,将连接的处理流程打乱,基于连接上发生的事件及存储的状态判断所需的处理逻辑。这种方案下,单个线程即可处理大量连接,效率极高。但由于这种模式下非线性的控制流,要做到正确编写,需要较高的水平。
基于“程序首先是给人看的,其次才是给机器看的”这一思路,心智负担较低的1:1模型必然更受开发人员欢迎,只是OS线程的性能损失阻止了这种方案的广泛应用。而Golang中协程的使用极大地降低了1:1模型的性能损失,因此得到了广泛的使用。
Golang提供的有栈协程虽然比OS线程便宜,但终究要付出额外的成本。Rust提供的async/.await异步却是“零成本抽象”的无栈协程,使用异步不需要使用堆分配或动态分发等。(异步本身是零成本的,但提供异步I/O的异步运行时可能有成本,所以性能低于其他方案也不是没有可能。)基于async/.await的Rust异步在高性能的同时,仍具有类似于1:1模型的线性控制流。
Python import 出错的解决方案
在多文件的Python程序编写中,使用 import 引用其他文件中的代码经常会出错。尤其是在涉及到包时,要达到目标往往需要反复调整,通过不断尝试来得到正确的结果。下面针对 Python 中的 import 机制进行一些探索。
基于LFS11.3从源码构建Linux系统-思路篇
为了从源代码构建一个全新的Linux系统,不可避免地涉及到大量的编译工作。而这里的编译,又不仅仅是“编译”,还隐含了“链接”等步骤。如果不仔细设计编译的过程,就容易在这个过程中发生链接错误,导致最终的产物无法正常工作。同时,gcc与glibc又涉及到相互依赖的“循环依赖”问题。
在这里,我们对交叉编译等概念进行介绍,并结合这些概念对LFS编译的思路进行分析。
基于LFS11.3从源码构建Linux系统-实践篇
在 Hyper-V 中根据 LFS11.3 从源码构建 Linux 系统。