JavaScript微服务:架构与实践
微服务架构(MSA)已成为构建复杂、可扩展且容错应用程序的事实标准。与所有代码都在一个进程中耦合的单体架构不同,微服务将系统拆分为小型、独立的服务。JavaScript,特别是Node.js平台,凭借其事件驱动模型和庞大的生态系统,是实现微服务的绝佳选择。在本文中,我们将分析架构的关键原则,编写几个可运行的服务,并探讨它们交互的实践方面。
微服务架构的基本原则
在编写代码之前,理解什么使微服务成为"微服务"很重要。基本原则:
- 单一职责(Single Responsibility):每个服务解决一个特定的业务任务(例如,仅负责认证或仅负责订单管理)。
- 独立性:服务彼此独立地开发、测试和部署。
- 数据隔离:每个服务拥有自己的数据库。没有共享的存储库。
- 松耦合(Loose Coupling):服务通过网络(API)通信,而不是通过直接的函数调用。
- 容错性:一个服务的故障不应导致整个系统崩溃。
Node.js凭借其非阻塞特性和异步性,非常适合这些任务,这在服务之间存在大量网络调用时至关重要。
实践:创建两个简单的微服务
让我们在Express.js上编写两个简单的服务:User Service(用户管理)和 Order Service(订单管理)。
1. User Service(用户服务)
创建文件 user-service/server.js:
const express = require('express');const app = express();app.use(express.json());
const users = [{ id: 1, name: 'Alice', email: 'alice@example.com' }];
app.get('/users/:id', (req, res) => { const user = users.find(u => u.id === parseInt(req.params.id)); if (!user) return res.status(404).json({ error: 'User not found' }); res.json(user);});
app.listen(3001, () => console.log('User Service running on port 3001'));2. Order Service(订单服务)
创建文件 order-service/server.js:
const express = require('express');const app = express();app.use(express.json());
const orders = [ { id: 1, userId: 1, product: 'Laptop', amount: 1500 }];
app.get('/orders/user/:userId', (req, res) => { const userOrders = orders.filter(o => o.userId === parseInt(req.params.userId)); res.json(userOrders);});
app.listen(3002, () => console.log('Order Service running on port 3002'));现在我们有两个独立的服务,运行在不同的端口上。这是微服务架构的基础。
服务间交互:REST 和 Message Broker
服务必须进行通信。让我们考虑两种主要方法。
3.1 同步交互(REST API)
一个服务直接调用另一个服务的API。例如,为了获取包含用户名的订单,我们创建一个API Gateway或服务组合器。
// api-gateway.jsconst axios = require('axios');
app.get('/users/:id/orders', async (req, res) => { try { const userResponse = await axios.get(`http://localhost:3001/users/${req.params.id}`); const ordersResponse = await axios.get(`http://localhost:3002/orders/user/${req.params.id}`); res.json({ user: userResponse.data, orders: ordersResponse.data }); } catch (error) { res.status(