一. 项目概述
在前期学习过程中,我们接触过阻塞队列(BlockingQueue),并了解到其核心用途之一是实现“生产者-消费者模型”。该模型广泛应用于后端系统开发中,具有诸多优势:
- 促进模块间的解耦
- 支持并发执行,提升处理效率
- 有效应对任务负载波动
- 具备削峰填谷能力,优化资源利用率
在实际的分布式架构中,不同服务器之间常需通过生产者-消费者机制传递任务。为此,通常会将基础的队列功能封装为独立服务,并扩展更多特性。这种可独立部署的服务即为业界所称的“消息队列”(Message Queue, MQ)。
当前已有多种成熟的消息队列实现方案,例如:
- RabbitMQ
- Kafka
- RocketMQ
- ActiveMQ
其中,RabbitMQ 因其功能完善、生态丰富且广泛应用而备受青睐。接下来的内容中,我们将借鉴 RabbitMQ 的设计思路,动手实现一个简易版本的消息队列系统。
技术选型与开发环境
操作系统:Linux(支持 Centos-7.6 或 Ubuntu-22.04)
编辑工具:VSCode / Vim
编译调试:g++ / gdb
构建管理:Makefile
核心技术栈
编程语言:C++
选择 C++ 主要出于对高性能和底层资源精确控制的需求。对于需要高吞吐、低延迟的中间件系统而言,C++ 能够提供更强的运行效率和系统级操作能力。
序列化方式:Protobuf(Protocol Buffers)
采用 Protobuf 实现数据的二进制序列化。它具备跨平台、体积小、解析快等优点,非常适合网络传输场景,同时便于多语言服务之间的数据交互。
通信架构:自定义应用层协议 + Muduo 网络库
为了避免从零实现 Socket 编程带来的复杂性(如粘包/拆包、连接维护等问题),我们选用 Muduo 作为底层网络框架。Muduo 是一个基于 Reactor 模式的高质量 C++ TCP 库,内部使用 epoll 事件驱动机制,能够轻松支撑高并发连接,使开发者更专注于业务逻辑而非网络细节。
持久化存储:SQLite3
为防止因服务重启导致消息丢失,需将关键数据落盘保存。SQLite3 是一款轻量级嵌入式数据库,无需独立进程即可运行,支持 ACID 事务,满足本项目对简单可靠的数据持久化需求。
测试保障:GTest(Google Test)
为确保代码质量与稳定性,引入 GTest 单元测试框架。通过对各核心组件编写详尽的测试用例,验证功能正确性,增强系统的可维护性和迭代安全性。
二. 环境搭建
2.1 基础工具配置
本项目基于 Ubuntu 24.04 LTS 进行开发。
首先需要安装一系列基础组件以支撑后续开发流程。
sudo apt-get update && sudo apt-get install -y \
wget \
lrzsz \
gcc g++ \
make \
gdb \
git \
cmake
安装完成后,可通过以下命令一键检查是否所有必要组件均已成功部署。
echo "=== 检查工具安装情况 ===" && \
for tool in wget lrzsz gcc g++ make gdb git cmake; do
if command -v $tool &> /dev/null; then
echo "? $tool 已安装: $($tool --version 2>/dev/null | head -n1)"
else
echo "? $tool 未安装"
fi
done
2.2 Protobuf 安装流程
2.2.1 安装依赖项
在开始编译 ProtoBuf(Protocol Buffers)前,必须确保系统已安装必要的构建工具和库文件,包括 autoconf、automake、libtool、curl、make、g++ 和 unzip。这些是完成源码编译的基础环境,任一缺失都可能导致构建失败。
Ubuntu / Debian 用户请执行以下命令进行安装:
sudo apt-get update
sudo apt-get install autoconf automake libtool curl make g++ unzip -y
安装完毕后,建议再次确认所有依赖项状态正常,随后即可进入源码下载阶段。若遇问题,可查阅 ProtoBuf 官方文档或对应发行版的包管理指南获取帮助。
2.2.2 获取源码包
访问 ProtoBuf 的官方发布页面:
Releases · protocolbuffers/protobuf
该地址与前述链接一致。
推荐下载最新稳定版本,例如 v21.11,具体版本可根据本地环境灵活选择。
进入发布页后可见如下内容:
若仅用于 C++ 开发,可选择 cpp.zip;
若用于 Java,则下载 java.zip;
其他语言按需选取对应压缩包。
如需支持全部语言,建议直接下载 all.zip。
本项目选择全语言版本。
点击下载按钮获取文件。
接着登录目标服务器,执行 rz 命令上传文件。
上传完成后进行解压操作。
unzip protobuf-all-21.11.zip
解压结果如下:
此时得到的目录即为 Protobuf 的完整源码,下一步将对其进行编译。
2.2.3 编译构建过程
进入解压后的源码根目录,依次执行以下步骤。
第一步:运行 autogen.sh 脚本
此脚本用于生成 configure 配置文件,为后续的 configure 步骤做准备。
./autogen.sh
2.2.3.2 第二步:运行 configure
在配置过程中,提供两种不同的安装方式,用户可根据实际需求选择其一:
默认安装模式
若采用默认设置,protobuf 将被安装至系统预设路径:
/usr/local
此时,相关的库文件、可执行程序等资源将自动分布于该目录下的各个子目录中。
./configure
自定义安装路径
为便于管理与维护,推荐将所有组件统一部署到指定目录。例如,设定安装位置为:
/usr/local/protobuf
所有生成的文件都将集中存放于此。
./configure --prefix=/usr/local/protobuf
出于结构统一考虑,本文后续操作均基于自定义安装路径方式进行。
完成配置后,当前工作目录下会生成相应构建文件:
这表明环境已准备就绪,可以进入下一步编译流程,直接执行 make 命令。
2.2.3.3 第三步:执行编译
在完成 configure 配置之后,启动编译过程,请运行以下指令:
make # 编译源码
建议在执行
make check
时保持耐心,此阶段会自动运行多项测试用例,以确保整个编译流程正确无误。
我们首先执行:
等待约15分钟……
2.2.3.4 第四步:验证编译结果
为确认编译是否成功,需执行如下命令进行检查:
make check # 验证编译结果(可选,约需15分钟)
具体操作为运行:
继续等待约15分钟。
在整个执行过程中,可能会出现大量警告信息,但只要未出现红色错误提示,则视为正常现象。
若遇到如下报错情况:
其原因在于 test 模块包含大量测试案例,这些案例对服务器运行环境要求较高,尤其是内存和交换空间(swap)资源。解决方法是增加 swap 分区大小,具体步骤如下:
步骤一:查看当前 SWAP 状态
操作前,先通过命令检查 Ubuntu 系统当前的 SWAP 使用情况:
sudo swapon --show
该命令将列出所有已激活的 SWAP 区域。若无任何输出,则表示系统尚未配置 SWAP。
步骤二:创建 SWAP 文件
分配一个 1GB 大小的 swap 文件:
sudo fallocate -l 1G /swapfile
如果在执行过程中提示 fallocate failed: Text file busy,说明当前文件或资源正被占用。
此时应采取以下措施:
sudo swapoff -a
sudo fallocate -l 1G /swapfile
步骤三:设置 SWAP 文件权限
为保障系统安全,需将 SWAP 文件权限限制为仅 root 用户可读写:
sudo chmod 600 /swapfile
步骤四:初始化 SWAP 区域
使用 mkswap 工具在目标文件上建立 Linux 可识别的 SWAP 区域:
sudo mkswap /swapfile
步骤五:启用 SWAP 文件
通过以下命令激活新创建的 swap 文件:
sudo swapon /swapfile
验证 SWAP 是否生效
再次运行以下命令确认 SWAP 已成功启用:
sudo swapon --show
或者使用替代命令:
free -h
步骤六:实现永久化配置
为防止重启后配置丢失,在修改系统关键文件前建议先进行备份:
sudo cp /etc/fstab /etc/fstab.bak
- 将 SWAP 信息写入 /etc/fstab,确保开机自动挂载:
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
(建议先扩容至 3GB,再执行 make check。若仍失败,进一步扩展至 5GB 并重新运行测试。)
我们现在尝试将 swap 扩展至 3GB:
可以看到当前系统已存在一个约 1.9GB 的 swap 文件。
接下来我们新建一个 3GB 的 swap 文件:
# 创建额外的3G swap文件(与现有swap共存)
sudo fallocate -l 3G /swapfile2
sudo chmod 600 /swapfile2
sudo mkswap /swapfile2
sudo swapon /swapfile2
# 验证总swap大小(现在应该有约4.9G)
free -h
sudo swapon --show
完成后,重新执行 make check 进行验证:
cd /root/protobuf/protobuf-21.11
make check
……等待中
结果显示仍然报错,说明 3GB 不足以满足测试需求。现在我们将 swap 提升至 5GB 再次尝试:
# 1. 禁用当前的额外swap
sudo swapoff /swapfile2
# 2. 删除3G文件,创建5G文件
sudo rm -f /swapfile2
sudo fallocate -l 5G /swapfile2
sudo chmod 600 /swapfile2
sudo mkswap /swapfile2
sudo swapon /swapfile2
# 3. 验证新的swap配置
free -h
sudo swapon --show
然后再次运行 make check:
# 再次执行make check
cd /root/protobuf/protobuf-21.11
make check
等待……
最终显示成功通过。注意:本次实验无需将 swap 配置设为永久生效。
2.2.3.5 第五步:安装至系统目录
当 make check 成功完成后,即可将编译成果正式安装到系统目录中:
sudo make install # 安装到系统目录
该过程执行速度较快。
2.2.3.6 第六步:更新系统环境配置
请回顾此前的操作:
在第二步执行 configure 时,若当时使用的是默认方式(即 ./configure),则 protobuf 已可直接使用,无需额外配置。
但如果选择了自定义安装路径,则需要手动将相关路径添加至系统环境变量中。编辑 /etc/profile 文件:
sudo vim /etc/profile
在文件末尾加入以下内容:
# 动态库搜索路径(运行时)
# 指定程序在加载运行期间查找动态链接库的路径,除了系统默认路径外
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/protobuf/lib/
# 静态库搜索路径(编译时)
# 指定程序在编译期间查找静态库的路径
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/protobuf/lib/
# 可执行程序搜索路径
# 指定系统在哪些目录中查找可执行文件
export PATH=$PATH:/usr/local/protobuf/bin/
# C 程序头文件搜索路径
# 指定 C 编译器查找头文件(.h 文件)的目录
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/protobuf/include/
# C++ 程序头文件搜索路径
# 指定 C++ 编译器查找头文件(.h/.hpp 文件)的目录
export CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/protobuf/include/
# pkg-config 工具搜索路径
# 指定 pkg-config 查找 .pc 配置文件的目录,用于获取编译和链接参数
export PKG_CONFIG_PATH=/usr/local/protobuf/lib/pkgconfig/
保存并退出编辑器。
最后一步,刷新 profile 配置使其立即生效:
source /etc/profile
2.2.3.7 第七步:确认安装成功
执行以下命令进行最终验证:
protoc --version
如能正常显示版本信息,则表明 protobuf 安装成功。
2.3 安装 Muduo 库
Muduo 库的官方网站为:

在开始安装 Muduo 库之前,首先需要确保系统中已安装必要的依赖工具。
sudo apt-get install libz-dev libboost-all-dev
接着,前往项目的官方仓库获取源码:
GitHub - chenshuo/muduo: Event-driven network library for multi-threaded Linux server in C++11
使用 rz 命令将下载的源码文件上传至远程服务器。
unzip muduo-master.zip
cd muduo-master
完成上传后,进入编译与安装流程。
./build.sh
该步骤对应的是源码的编译过程。
./build.sh install
随后执行的命令则用于安装编译生成的内容。那么这些文件究竟被安装到了哪个路径?实际上,默认情况下,所有产物会被放置在上一级目录中的 build 文件夹内。
我们所需的核心库文件均位于此目录下!
值得注意的是,该目录中还包含大量官方提供的使用示例,以下列出的均为已编译完成的可执行程序。
我们可以选取其中一个进行功能测试。
同时打开另一个终端窗口,用于发起连接或发送测试数据。
此时观察原终端的输出状态,其显示内容已发生变化。
这表明服务端已正常运行并成功接收客户端请求——安装配置成功!
从结果可见,每发送一个字符,服务器都能准确回显,通信无误。
2.4 安装 sqlite3 与 GTest
sudo apt-get install sqlite3 libsqlite3-dev
接下来继续安装辅助开发与测试所需的组件:sqlite3 和 Google Test(GTest)框架。
sudo apt-get install libgtest-dev
安装完成后,编写一个简单的测试文件以验证环境是否配置正确。
// 引入 Google Test 框架的头文件
#include <gtest/gtest.h>
// 定义一个简单的加法函数
int add(int a, int b) {
return a + b;
}
// 创建测试用例
// TEST 是 Google Test 的宏,用于定义测试
// 参数1: testCase - 测试用例的名称
// 参数2: test1 - 测试的名称
TEST(testCase, test1) {
// EXPECT_EQ 是断言宏,检查两个值是否相等
// 这里测试 add(2,3) 的结果是否等于 5
EXPECT_EQ(add(2, 3), 5);
}
// 程序主函数
int main(int argc, char **argv) {
// 初始化 Google Test 框架
// 这行代码会解析命令行参数(如 --gtest_filter 等)
testing::InitGoogleTest(&argc, argv);
// 运行所有测试用例并返回结果
// RUN_ALL_TESTS() 会执行所有 TEST 定义的测试
// 返回 0 表示所有测试通过,非 0 表示有测试失败
return RUN_ALL_TESTS();
}
尝试对该测试文件进行编译。
# 需要链接 gtest 库
g++ main.cpp -lgtest
编译通过且运行正常,说明相关组件已成功安装并可用。