JavaScript 微服务:高级架构与实践

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

JavaScript 微服务:从单体到分布式系统



从单体应用过渡到微服务架构,不仅仅是技术上的重构,更是开发理念的转变。在使用 Node.js 进行高级开发时,我们面临的不仅仅是拆分代码为模块,而是要构建一个稳定、可扩展且容错的分布式系统。在本文中,我们将深入探讨关键的架构决策和实用模式,帮助您使用 JavaScript 构建生产就绪的微服务。



开发人员面临的主要挑战包括:服务间的数据同步、维护事务完整性、服务发现以及高效通信。设计阶段的错误可能导致生产环境中的混乱。让我们看看如何避免这些问题。



1. 服务间通信:RabbitMQ 和 gRPC



在微服务世界中,选择通信协议至关重要。对于 Node.js,最流行的两种方法是:异步消息队列(RabbitMQ)和同步高性能 RPC(gRPC)。



异步队列(RabbitMQ)

用于事件驱动架构。生产者服务不等待响应,而是发布事件。这降低了耦合度。我们来看一个将订单发送到配送服务的示例。



// "订单"服务 — 生产者const amqp = require('amqplib');

async function publishOrderCreated(order) { const connection = await amqp.connect('amqp://rabbitmq:5672'); const channel = await connection.createChannel(); const exchange = 'order.events'; await channel.assertExchange(exchange, 'topic', { durable: true });

channel.publish(exchange, 'order.created', Buffer.from(JSON.stringify(order)), { persistent: true });

console.log(`[x] Sent order: ${order.id}`); await channel.close(); await connection.close();}

// 创建订单时调用publishOrderCreated({ id: '123', userId: '456', amount: 1500 });


消费者服务(配送)订阅队列:



// "配送"服务 — 消费者const amqp = require('amqplib');

async function consumeOrders() { const connection = await amqp.connect('amqp://rabbitmq:5672'); const channel = await connection.createChannel(); const exchange = 'order.events'; await channel.assertExchange(exchange, 'topic', { durable: true });

const q = await channel.assertQueue('', { exclusive: true }); await channel.bindQueue(q.queue, exchange, 'order.created');

channel.consume(q.queue, (msg) => { if (msg.content) { const order = JSON.parse(msg.content.toString()); console.log(`[x] Received order: ${order.id}`); // 创建配送的逻辑 channel.ack(msg); } });}

consumeOrders();


同步 gRPC

对于需要即时响应的场景(例如,检查用户余额),gRPC 通过 HTTP/2 提供强类型和高速度。定义 proto 文件:



// user.protoservice UserService {  rpc GetUserBalance (UserRequest) returns (UserResponse);}

message UserRequest { string user_id = 1;}

message UserResponse { double balance = 1;}


在 Node.js 上实现服务器:



const grpc = require('@grpc/grpc-js');const protoLoader = require('@grpc/proto-loader');const PROTO_PATH = './user.proto';

const packageDefinition = protoLoader.loadSync(PROTO_PATH, { keepCase: true, longs: String, enums: String, defaults: true, oneofs: true});const userProto = grpc.loadPackageDefinition(packageDefinition).userservice;

function getBalance(call, callback) { const userId = call.request.user_id; // 模拟数据库查询 const balance = userId === '456' ? 5000 : 0; callback(null, { balance });}

const server = new grpc.Server();server.addSe

博客

书籍推荐