NestJS vs Encore.ts:选哪个框架打造你的TypeScript微服务最合适?
简介
当 web 应用程序变得更大时,系统开发和维护的复杂性也随之增加。常见的一种解决办法是采用微服务架构,其中开发人员将系统拆分成较小的、易于管理的组件,这些组件可以单独管理和水平扩展。
为了有效地做到这一点,通常使用微服务框架是有帮助的。但是选择一个合适的框架可能会有挑战。在这篇文章里,我们要来探讨两个相关的选择Encore.ts和Nest.js,因为它们都原生支持微服务架构以及TypeScript。
Encore.ts 是一个新推出的开源框架,以其高效率、类型安全和可观测性特性等特性而脱颖而出。相比之下,Nest.js 在使用 TypeScript 构建微服务应用程序的框架中处于领先地位。每个框架都有其优势,因此我们将从架构、性能和可扩展性等各个方面来分析每个框架,并解释如何确定哪个框架最适合您。
在我们开始之前,先来看看下面这张图片里的标准数据。
基准数据显示,Encore.ts 在不进行验证的情况下每秒可以处理 121,005 个请求,在进行验证模式的情况下每秒可以处理 107,018 个请求。这比传统框架快得多。例如,Express.js 与 Zod 结合使用在不进行验证的情况下每秒可以处理约 15,707 个请求,在进行验证的情况下每秒可以处理约 11,878 个请求。因此,Encore.ts 大约是 Express.js 的 9 倍快,而 Nestjs 就是基于 Express 构建的。
Encore.ts 和 NestJS 简介
当你开始一个项目时,你希望有一个既强大又好用的框架,特别是对开发者来说。在支持内置 TypeScript 的微服务框架中,Encore.ts 和 NestJS 都很突出,不过它们各自的工作方式各有特色。
Encore.ts 是一个开源的云原生框架,旨在简化后端开发,自带基础设施自动化。它允许你利用声明式的基础设施库来构建模块化的分布式系统。
Encore.ts 在一个通过 napi 与 Node.js 集成在一起的 Rust 运行时环境中运行,在处理 I/O 和多线程任务时性能卓越,让你可以使用 TypeScript 编写逻辑。
下面是一个使用Encore.ts定义服务的简单例子。
import { 服务 } from "encore.dev/service";
export default new 服务("hello");
点击进入全屏,点击退出全屏
当你创建这个 hello
服务时,Encore.ts 会自动将整个目录当作服务的一部分,不需要额外的配置。
另一方面,NestJS 有自己的风格。它是一个灵活的 TypeScript 框架,让你可以完全掌控应用程序的开发流程,让你可以自由地以你自己的方式构建应用。
虽然它不涉及基础设施自动化,但 NestJS 可以轻松集成几乎任何第三方库,这为各种项目提供了许多可能。
下面是在 NestJS 中定义类似服务的一种方式:
import { Controller, Get } from '@nestjs/common';
// 这是一个简单的 NestJS 控制器,用于显示“Hello, World!”
@Controller('hello')
export class HelloWorldController {
@Get()
sayHello(): string {
return 'Hello, World!';
}
}
全屏预览 退出预览
NestJS, 提供了更大的灵活性,但缺少了 Encore.ts 内置的自动化。
建筑设计
框架的架构决定了你的应用程序如何随时间被构建和维护。Encore.ts 和 NestJS 都很稳健,但它们的核心理念不同。
Encore.ts 非常有主见,并且是以云为先的,这使得它非常适合大型且类型安全的分布式系统,尤其是那些包含许多微服务的系统。其中一大亮点是它对 Pub/Sub 的原生支持,从而可以无缝实现事件驱动架构。
这里是如何在Encore.ts中使用Pub/Sub来定义事件驱动服务的方法:
import { Topic, Subscription } from "encore.dev/pubsub";
// 定义订单创建事件类型
export interface OrderCreatedEvent {
orderId: string;
}
// 创建一个主题用于订单创建事件
export const orders = new Topic<OrderCreatedEvent>("orders", {
deliveryGuarantee: "at-least-once",
});
// 创建一个订阅来监听订单创建事件
export const _ = new Subscription(orders, "process-order", {
handler: async (event: OrderCreatedEvent) => {
console.log('订单创建了:', event.orderId);
},
});
全屏,退出全屏
NestJS 虽然支持微服务和事件驱动架构,NestJS 提供了更模块化的途径。其核心采用 MVC 模式,并通过提供更大的配置灵活性,让开发人员能够按自己的方式构建系统。
例如,这里是如何在 NestJS 中以更加模块化的方式定义服务与事件如下:
// order.event.ts
export class OrderCreatedEvent {
constructor(public readonly order: Order) {}
}
// order.repository.ts
@Injectable()
export class OrderRepository {
async save(order: Order): Promise<Order> {
// Persistence logic
}
}
// order.service.ts
@Injectable()
export class OrderService {
constructor(
private readonly orderRepository: OrderRepository,
private readonly eventEmitter: EventEmitter2
) {}
async createOrder(orderDto: CreateOrderDto): Promise<Order> {
const order = new Order(orderDto);
const savedOrder = await this.orderRepository.save(order);
this.eventEmitter.emit(
'order.created',
new OrderCreatedEvent(savedOrder)
);
return savedOrder;
}
}
// order.listener.ts
@Injectable()
export class OrderEventListener {
@OnEvent('order.created')
async handleOrderCreatedEvent(event: OrderCreatedEvent) {
// 处理相关的逻辑
}
}
// order.module.ts
@Module({
imports: [EventEmitterModule.forRoot()],
providers: [
OrderService,
OrderRepository,
OrderEventListener
],
exports: [OrderService]
})
export class OrderModule {}
全屏模式,按X退出
按照设计初衷,NestJS 提供了很多控制权,让组件可以更灵活地交互,但缺点是需要编写更多的样板代码,并且你自己来管理基础设施配置。
扩展性与内置特性
在开发分布式系统的过程中,框架提供的功能经常会促进开发,但可能因此引入过度复杂性。
Encore.ts 的突出特点是它提供了自动化的基础设施供应方式,既适用于本地开发也适用于云端环境。这涵盖数据库、消息发布与订阅机制、定时任务等。Encore.ts 还提供了一个本地开发控制台,可以自动生成 API 文档、架构图以及分布式追踪信息。它还会生成前端客户端代码,包括 REST API 的 OpenAPI 支持,这将大大节省开发人员的时间。
这里展示了一个使用 Encore.ts 定义 REST API 的示例,并且还会自动生成 OpenAPI 文档:
import { api } from "encore.dev/api";
interface CreateOrderParams {
productId: string;
quantity: number;
}
interface OrderResponse {
orderId: string;
message: string;
}
export const createOrder = api(
{ method: "POST", path: "/orders", expose: true, auth: true },
async (params: CreateOrderParams): Promise<OrderResponse> => {
const orderId = "order123";
return {
orderId,
message: `已为产品${params.productId}创建订单,数量为${params.quantity}。`,
};
}
);
切换到全屏模式 切换回正常模式
使用 Encore.ts,当你定义服务时,文档和图表将自动生成并可用,无需额外步骤。
:这是Encore的架构图。
NestJS 因其灵活性而变得非常流行。从一开始,NestJS 就轻松支持 REST、GraphQL 和 WebSocket,但其真正受到欢迎的原因是它能够很容易地与第三方库集成。
例如,如果你想引入GraphQL支持,这很简单。
import { Resolver, Query, Mutation, Args } from '@nestjs/graphql';
// 定义一个简单的订单模型(这将是 GraphQL 类型)
class Order {
id: string;
product: string;
quantity: number;
}
// 处理 GraphQL 查询和变异的解析类
@Resolver(() => Order)
export class OrderResolver {
// 存储订单的数组(模拟数据库)
private orders: Order[] = [];
// 获取所有订单的查询函数
@Query(() => [Order], { name: 'getAllOrders' })
getAllOrders(): Order[] {
return this.orders;
}
// 创建订单的变异操作
@Mutation(() => Order)
createOrder(
@Args('product') product: string,
@Args('quantity') quantity: number,
): Order {
const newOrder = { id: Date.now().toString(), product, quantity };
this.orders.push(newOrder);
return newOrder;
}
}
切换到全屏模式,退出全屏
NestJS 让构建其核心功能变得简单,但它提供的自动化基础设施和功能没有 Encore.ts 那样丰富。
性能表现和扩展能力
构建大规模分布式系统时,系统性能至关重要。
Encore.ts 依靠其高性能的 Rust 运行时,该运行时能够高效处理 I/O 操作和多线程。Rust 的高速度和内存安全性使 Encore.ts 相对于纯 Node.js 框架具有显著的优势。在扩展性方面,Encore.ts 是云原生的,可以依据您的部署策略,通过无服务器架构或 Kubernetes 实现自动扩展。
相比之下,NestJS 在处理性能和可扩展性方面采用更为传统的方法。由于 NestJS 完全基于 TypeScript 和 JavaScript,它依赖于你在设置过程中进行的性能优化。扩展 NestJS 应用程序通常需要手动配置 Kubernetes、Docker 或无服务器平台(如 AWS Lambda)。
尽管 NestJS 在扩展性上更灵活,但其配置需要更多的手动配置,而相比之下,Encore.ts 自带的自动化工具则更为便捷。
让我们来看看下面的图片中的基准测试数据,从中理解encore.ts和Nest.js在性能方面的区别:
根据基准测试数据,encore.ts 在性能方面尤为出色,启动只需 8.3 毫秒,而 NestJS 则需要大约 143.7 毫秒,几乎是传统框架启动速度的九倍。
部署方案
应用程序的部署方式是每个项目中需考虑的重要因素,尤其是在涉及云环境时。
Encore.ts 通过其开源工具或 Encore 云平台提供了轻松部署的途径。使用开源版本,你可以用 encore build
来构建你的项目并生成一个 Docker 镜像,然后可以在任何支持 Docker 的地方,比如,部署。
运行以下命令来构建 Docker 镜像,并指定所需的 service1
和 service2
服务以及 api-gateway
网关:
encore build docker --services=service1,service2 --gateways=api-gateway MY-IMAGE:TAG
点击进入全屏模式,再点击退出全屏模式
我们生成了一个可以在任何地方部署的Docker镜像。
或者,如果你选择使用Encore云,它会自动管理整个CI/CD流程,并直接部署到你的AWS或GCP云中,同时支持无服务器或Kubernetes架构。
相比之下,NestJS则需要手动设置才能部署应用。通常,开发人员使用Docker将NestJS应用打包成容器,并部署到他们选择的云服务提供商。虽然这给你提供了对部署策略的控制,但它需要更多的配置——例如,即使对于一个简单的应用,你也需要完成许多步骤。
1., 创建一个 Dockerfile
文件:
FROM node:18-alpine # 从node:18-alpine镜像开始
WORKDIR /app # 设置工作目录为/app
COPY package*.json ./ # 将package*.json复制到当前目录
RUN npm install # 运行npm install命令
COPY . . # 将当前目录复制到工作目录
RUN npm run build # 运行npm run build命令
EXPOSE 3000 # 暴露3000端口
CMD ["npm", "run", "start:prod"] # 设置启动命令为npm run start:prod
切换到全屏 / 退出全屏
- 新建一个
docker-compose.yml
文件,
version: '3.8'
services:
api:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:pass@db:5432/myapp
depends_on:
- db
db:
image: postgres:13
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=myapp
全屏显示;退出全屏
- 为 NestJS 创建 GitHub Actions 工作流程
name: 部署 NestJS 应用
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: 构建并推送 Docker 镜像
run: |
docker build -t myapp .
docker push myregistry/myapp:latest
- name: 部署到云
run: |
# 在这里添加你的部署命令,例如:kubectl apply, AWS ECS 部署等。
全屏,退出全屏
随着你的应用规模变得越来越大,随着需求的增长,对多个预备和测试环境的需求也越来越高,这种手动配置方式就越显得负担沉重——维护所需的时间不断增加。
用例考量
在选择 Encore.ts 和 NestJS 之间时,决定应根据项目的具体需求来做出。
Encore.ts非常适合云优先的应用程序和那些可以从内置自动化中受益的大型分布式系统。它基于Rust的运行时和基础设施管理使其非常适合事件驱动架构、微服务和高性能应用程序。Encore快速成长的社区是获取支持和集成第三方工具的好去处。
另一方面,当需要灵活性和自定义时,NestJS 就特别出色。它非常适合需要对每个细节进行精细控制的企业应用,并且在可以接受手动配置的情况下。NestJS 丰富的生态系统和社区支持使找到资源和第三方工具更加容易。
总结
选择 Encore.ts 和 NestJS 取决于你的项目需求。
如果你在寻找一个简单、高性能、内置自动化功能的云原生框架,Encore.ts 是一个非常好的选择。它通过自动管理基础设施来简化分布式系统的开发过程,其基于 Rust 的性能更是难以超越。
然而,如果你需要一个非常灵活、模块化的框架,并且希望在每个细节上都有所掌控,NestJS 可能是你的最佳选择。它的可扩展性和丰富的生态系统使其成为定制企业级解决方案的坚实选择。
这两个框架都非常强大,最佳的选择取决于你更看重性能和简洁,还是最大程度的灵活性和控制。
接下来的步骤
如果你的项目需要高性能和简洁性,尝试Encore.ts可能是个不错的选择。而且它开源了,所以你可以查看代码并在GitHub上进行贡献。
共同学习,写下你的评论
评论加载中...
作者其他优质文章