我造不了的东西我就搞不懂!
分布式系统就是多台电脑一起工作,对于客户端而言就像是用一台电脑一样。
你可能想不到分布式系统有多普遍!即使是小型的 B2B 初创公司,运行三个服务器,分别是用 Go 语言,Python 和 Node.js,也已经是分布式架构了。
这是我硬学得的。在我第一份开发工作的第三个月,我不得不接手一个项目。这既不在计划中,也不在我的职责范围内——但我别无选择。大多数教程?在那样的时候都不管用。我必须在实战中历练。带着伤痕累累。
我现在来给你讲明白。
让我们搭建一个使用纯JavaScript编写的Broker的分布式系统。
分布式架构我更偏向实践,而不是理论——我更愿意先动手做,再争论定义。
别管那些学术上的吹毛求疵了。这里有一个更实用的定义:
分布式系统就像一个蜂巢——多台机器协同工作,仿佛是由一个统一的大脑控制。从客户端的角度来看,它感觉就像在使用一台计算机。
我们可以建那个。
最简单的服务器设置是我称之为单元系统(即后端的“与非门”):
客户端到服务器再到[数据库,存储桶[]]
切换到全屏模式 退出全屏
面试技巧:在系统设计面试中,从最简单的开始,比如一个用户和一个服务器。搞定这个后,然后开始扩展。每次都管用。
项目启动
创建项目结构:
生产者/
send.js
消费者目录/
consume.js
.auth
messagebroker.js
package.json
全屏显示 退出全屏
安装所需的依赖项:
你可以试试在终端中运行这个命令:
npm i bunnimq@latest bunnimq-driver
切换到全屏 退出全屏
无来源信息。
运行以下命令克隆仓库: git clone https://github.com/SfundoMhlungu/bunni-example.git
全屏 退出全屏
消息代理:蜂巢心消息中介就像是蜂巢的指挥中心,负责协调发送方和接收方。
设置代理
请注意,原文中的“Setting Up the Broker”在上下文中可能更准确地是指“设置消息代理”或“设置代理服务器”。如果需要更符合上下文的专业术语,请提供更多信息。此处根据专家建议直接翻译为“设置代理”。
在 messagebroker.js 中:
import Bunny, { OPTS } from "bunnimq";
import path from "path";
import { fileURLToPath } from "url";
OPTS.cwd = path.dirname(fileURLToPath(import.meta.url)); // 读取 .auth 文件的内容
Bunny({ port: 3000, DEBUG: true });
切换到全屏模式 退出全屏模式
在 .auth
文件里:
简:doeeee:3
约翰:doeees:3
全屏进入 退出全屏
运行代理程序:
(注:此处“broker”根据具体上下文可能有不同译法,如“中间件”、“代理”等,此处采用“代理程序”作为示例。如有更具体的行业背景,建议使用更准确的翻译。)
运行消息代理文件
node messagebroker.js
全屏,退出全屏
当 Bunny 启动时,它会找寻两个东西:
- .auth 文件 – 类似于数据库中的用户记录。
- 缓存队列 – 用于保证消息的持久化。
权限映射:
const perms = {
1: "发布",
2: "消费",
3: "发布和消费",
4: "管理"
};
全屏 退出全屏
为什么要用分布式系统?
请求和响应的周期非常快,但却很短暂。
app.get("/endpoint", (req, res) => {
// 做一些事情
res.send();
});
切换到全屏模式,退出全屏
这没问题——直到你遇到长时间运行的任务(比如 FFMPEG 音频转换)。你不能让请求阻塞这么久。
所以我们开始分工了:
- 注册任务
- 发送给代理
- 立即返回任务ID
app.get("/endpoint", (req, res) => {
const jobId = genUniqueJobId();
sendMessageToBroker(jobId);
res.send(jobId); // 客户端会轮询此ID以获取进度
});
进入全屏模式 退出全屏模式
兔子找到一个可用的工人,分配任务,并跟踪任务进度(例如,可以使用 Redis)。
{
"jobId": "xyz123",
"progress": "20%"
}
点击这里进入全屏 点击这里退出全屏
生产者:派发工作
在 send.js 文件中,代码如下所示:
import Bunnymq from "bunnimq-driver";
const 兔子mq = new Bunnymq({
port: 3000,
host: "localhost",
username: "john",
password: "doeees" // 请匹配你的 .auth 凭据
});
// 创建或连接到队列
兔子mq.QueueDeclare(
{
name: "myqueue",
config: {
QueueExpiry: 60,
MessageExpiry: 20,
AckExpiry: 10,
Durable: true, // 持久化消息内容
noAck: false // 需要确认应答
}
},
(res) => console.log("队列创建成功:", res)
);
// 发布 500 个作业
// 发布 500 个随机任务,每个任务都有一个唯一的 ID
for (let i = 0; i < 500; i++) {
兔子mq.Publish(`${Math.random()}-${i + 800}`, (res) => console.log(res));
}
切换到全屏 退出全屏
运行生产者程序。
执行以下命令: node send.js
全屏 全退
你会看到来自 Bunni 的 "试图发送" 日志记录——但还没有进行处理。
目前还没有工人哩...
工作者:处理工作
在 'consume.js' 中:
import Bunnymq from "bunnimq-driver";
const 邦尼 = new Bunnymq({
port: 3000,
host: "localhost",
username: "john",
password: "doeees"
});
// 连接到队列
邦尼.QueueDeclare({ name: "myqueue", config: undefined }, (res) => {
console.log("队列连接:", res);
});
let 已处理的消息数量 = 0;
// 消费消息
邦尼.Consume("myqueue", async (msg) => {
console.log("处理中:", msg);
已处理的消息数量++;
const [id, time] = msg.split("-");
console.log(`任务ID: ${id}, 时长: ${time}毫秒`);
await new Promise((resolve) => setTimeout(resolve, Number(time)));
console.log(`已消费的消息数量: ${已处理的消息数量}`);
邦尼.Ack((success) => console.log("准备好处理更多消息:", success));
});
进入全屏模式 退出全屏模式
启动工作者:
运行 node consume.js
点击此处全屏/退出全屏
一旦工人连接并成功握手,就开始接收消息。
想要看看蜂巢的运作吗? 打开多个终端并启动更多工作进程,它们会自动分担工作。
这就是所谓的规模扩展,也是所谓的蜂群意识。
在实际场景中,你会将生产和消费的过程包裹在一个合适的服务器程序中,以便更好地管理和控制。
这篇文章是一个更大系列的一部分,在该系列中我们将从零开始构建bunni,面向对网络和系统感兴趣的开发者,并希望超越 CRUD 操作。
构建基于TCP的消息代理:超越API和端点 - Payhip payhip.com
本文涵盖了:
✅ 分布式系统的入门
✅ 自己动手做的一款消息中转站(用Node.js写的)
✅ 扩大用户规模来分配任务
溜了!🫡
共同学习,写下你的评论
评论加载中...
作者其他优质文章