tegg v3 - 性能飞跃

简介: tegg v3 - 性能飞跃

编者按:本文作者是蚂蚁集团前端工程师零弌,介绍了 tegg v3 究竟有多快,快在哪,以及 tegg v3 如何做到性能飞跃。

 AsyncLocalStorage 与 eggjs

AsyncLocalStorage [1] 可以在一个 AsyncFunction 以及其相关的异步操作内安全的获取到在 store 内存储的变量。我们通过一段简单的代码就可以看到其演示效果。

AsyncLocalStorage 演示

const http = require('http');
const { AsyncLocalStorage } = require('async_hooks');
const asyncLocalStorage = new AsyncLocalStorage();
function logWithId(msg) {
  const id = asyncLocalStorage.getStore();
  console.log(`${id}: `, msg);
}
let idSeq = 0;
http.createServer((req, res) => {
  asyncLocalStorage.run(idSeq++, () => {
    logWithId('start');
    setImmediate(() => {
      logWithId('finish');
      res.end();
    });
  });
})
.listen(8080);

发起两次 HTTP 请求

curl http://127.0.0.1:8080
curl http://127.0.0.1:8080

打印内容为

0:  start
0:  finish
1:  start
1:  finish

AsyncLocalStorage 实现原理

nodejs 通过 v8 提供的 Promise lifecycle hooks [2] 实现了 Promise 执行追踪 [3] 。也就是说在一个 Promise 实例化、resolve、reject、then、catch 时均能被追踪到,AsyncLocalStorage 通过这些 hook 将 asyncId 进行了传播,因此可以通过一个 storage 在异步函数中安全的获取到当前的上下文变量。

node 中除了 Promise 之外还有 timer、fs、net 这些模块也能执行移步操作,比如上面演示代码中就是有 http server 和 setTimeout。node 通过 AsyncResource [4] 这层抽象对这些方式进行了实现,如果有自己的 addon 实现,也可以通过这个类来实现。

egg

koa 已支持 [5] ,通过 asyncLocalStorage 参数开启。

egg 已支持 [6] ,通过 app.currentContext 即可获取当前 egg context。

 Benchmark

测试地址:https://github.com/eggjs/tegg_benchmark/actions/runs/4025979558

测试场景

项目规模测试

通过在项目里创建大量的 controller 和 service 来模拟项目规模。Benchmark 分别测试了 1, 10, 100, 1000, 10000 个 controller/service 的情况。

业务复杂度测试

通过在 controller 访问 service 来模拟业务复杂度。Benchmark 分别测试了 1, 10, 100, 1000, 10000 个 service 的情况。

结论

  • tegg v3 不会因为项目规模扩张而引起性能衰退。
  • tegg v3 因为业务复杂度扩张而引起的性能衰退比 egg/tegg v1 慢。

Profile

CPU

egg 项目规模复杂度(1w)

性能热点集中在 egg 中的 defineProperty 和 ClassLoader,原因是 controller/service 过多导致。

tegg 项目规模复杂度(1w)

热点耗时在 node 本身,gc、async_hook。

内存

egg 项目规模复杂度(1w)

由于 controller/service 数量过多,导致存在内存分配瓶颈。可以看到 controller 每次实例化都会占用大量内存。


tegg 项目规模复杂度(1w)

目前内存压力存在于 async_hook。

  如何飞跃

tegg 注入原理

tegg 实例代码,HelloWorldController 注入了 Foo 类, Foo 类注入了 Tracer 类。

@HTTPController()
class HelloWorldController {
  @Inject()
  private readonly foo: Foo;
}
@Context()
class Foo {
  @Inject()
  private readonly tracer: Tracer;
}

请求在进入框架执行阶段后,首先会找到入口类。本例中为 HelloWorldController,并根据对象图实例化所有的对象。

tegg v1 性能瓶颈

每个请求需要创建 10001 个对象,需要分配大量的内存,导致 gc 压力很大。

tegg v3 优化原理

减少实例化对象,看示例代码,HelloWorkerController, Foo 与请求上下文是无关的,只有 Tracer 是与请求上下文相关。因此 HelloWorldController, Foo 不应该需要每次都实例化,这对于 CPU 和 内存 都是利好。

使用 AsyncLocalStorage 来代理对象,HelloWorldController、Foo 将会改造成单例模式,如何在不同的请求中获取到正确的对象将会是一个问题。我们需要将 tracer 改造成一个代理,通过 ctxStorage 来获取到正确的对象。

优化后效果

从 10001 到 0。极大的降低了内存压力,tegg v1 的堆大小从 200M 到 1G 波动,tegg v3 可以稳定在 200M。

  tegg v3 代码改造

修改注解

仅需将 @ContextProto() 替换为 @SingletonProto。

~~@ContextProto()~~
@SingletonProto()
class Foo {
  @Inject()
  private readonly tracer: Tracer;
}

实现有状态

Foo 这个类的状态和当前上下文有关,如果改成 Singleton 模式,所有上下文中共享会导致对象用串了,所以需要保持 ContextProto。

@ContextProto()
class Foo {
  state: State;
  foo() {
    this.state = 'foo';
  }
  bar() {
    this.state = 'bar';
  }
}

单测改造

describe('test/index.test.ts', () => {
  let foo: Foo;
  beforeEach(async () => {
    foo = await app.getEggObject(Foo);
  });
  it('should work', () => {
    assert(foo.hello());
  });
});


🔗 相关链接

[1] https://nodejs.org/dist/latest-v18.x/docs/api/async_context.html#class-asynclocalstorage

[2] https://docs.google.com/document/d/1rda3yKGHimKIhg5YeoAmCOtyURgsbTH_qaYR79FELlk/edit

[3]https://nodejs.org/dist/latest-v18.x/docs/api/async_hooks.html#promise-execution-tracking

[4]https://nodejs.org/dist/latest-v18.x/docs/api/async_context.html#class-asyncresource

[5]https://github.com/koajs/koa/pull/1721

[6]https://github.com/eggjs/egg-core/pull/251

相关文章
|
2月前
|
存储 安全 物联网
探索现代操作系统的进化与挑战
本文将深入探讨现代操作系统的核心功能、历史演变及面临的主要挑战。我们将从操作系统的基本定义和目的出发,逐步揭示其复杂性背后的设计理念,并通过具体案例分析现代操作系统如何应对日益增长的性能要求和安全威胁。此外,文章还将展望未来操作系统可能的发展方向,为读者提供一个全面而深入的视角。
56 9
|
2天前
|
缓存 监控 数据库
接口性能飞跃:一次成功的优化实践
在软件开发中,接口性能优化是一个永恒的话题。一个高效的接口不仅能提升用户体验,还能减轻服务器压力,降低运营成本。本文将分享一次成功的接口优化案例,从问题诊断到解决方案实施,详细介绍我们的优化过程。
19 0
|
2月前
|
机器学习/深度学习 算法 安全
量子计算的飞跃:重新定义计算能力的极限
【9月更文挑战第10天】量子计算作为颠覆性技术,正改变我们对计算能力的认知。本文深入探讨量子计算的基本原理及其飞跃性进展,包括量子霸权的实现和量子纠错技术的发展。量子计算不仅能够解决复杂问题、加强加密安全,还能推动科学发现。尽管面临挑战,其未来前景广阔,有望成为主流计算工具,开启全新计算时代。
|
3月前
|
机器学习/深度学习 存储 监控
利用机器学习技术优化数据中心能效
【7月更文挑战第36天】在数据中心管理和运营中,能源效率已成为关键性能指标之一。随着能源成本的不断上升以及环境保护意识的增强,开发智能化、自动化的解决方案以降低能耗和提高能源利用率变得尤为重要。本文探讨了如何应用机器学习技术对数据中心的能源消耗进行建模、预测和优化,提出了一个基于机器学习的框架来动态调整资源分配和工作负载管理,以达到节能的目的。通过实验验证,该框架能够有效减少数据中心的能耗,同时保持服务质量。
|
3月前
|
人工智能
就AI 基础设施的演进与挑战问题之大模型推理中显存瓶颈的问题如何解决
就AI 基础设施的演进与挑战问题之大模型推理中显存瓶颈的问题如何解决
|
6月前
|
缓存 Dubbo 应用服务中间件
实现从10s到0.5s的飞跃,揭秘性能提升的秘诀
在数字时代,性能优化对各类技术系统和应用至关重要,关乎用户体验、效率和成本。某团队在面对系统响应慢的问题时,通过梳理逻辑、使用stopwatch排查,发现了数据库、连接池、日志打印和Dubbo配置等问题。他们优化了数据库的索引和锁机制,减少了日志打印的负担,调整了Dubbo的线程配置,并改进了日志组件,最终显著提升了系统性能。性能优化的方法包括代码优化、数据库优化、缓存技术、并发处理和资源管理,这是一个持续且需综合考虑稳定性和可靠性的过程。
56 2
|
6月前
|
机器学习/深度学习 存储 监控
利用机器学习优化数据中心冷却效率
【4月更文挑战第25天】在数据中心的运营成本中,冷却系统占据了一大块。随着能源价格的不断攀升以及环保意识的增强,如何降低冷却系统的能耗成为了一个亟待解决的问题。本文提出了一种基于机器学习的方法来优化数据中心的冷却效率,通过实时监控和数据分析,动态调整冷却设备的工作状态,以达到节能的目的。实验结果表明,该方法可以显著降低数据中心的能耗,同时保证服务器的正常运行。
|
6月前
|
存储 人工智能 缓存
探索AIGC未来:CPU源码优化、多GPU编程与中国算力瓶颈与发展
近年来,AIGC的技术取得了长足的进步,其中最为重要的技术之一是基于源代码的CPU调优,可以有效地提高人工智能模型的训练速度和效率,从而加快了人工智能的应用进程。同时,多GPU编程技术也在不断发展,大大提高人工智能模型的计算能力,更好地满足实际应用的需求。 本文将分析AIGC的最新进展,深入探讨以上话题,以及中国算力产业的瓶颈和趋势。
|
6月前
|
机器学习/深度学习 人工智能 芯片
AI芯片设计与优化:算力提升、能耗降低与硬件加速器的发展趋势
AI芯片设计与优化:算力提升、能耗降低与硬件加速器的发展趋势
1172 0
|
机器学习/深度学习 人工智能 自然语言处理
AIGC给生活带来的优势和劣势分析
AIGC(人工智能产业发展联盟)作为人工智能领域的重要组织,通过推动人工智能技术的发展和应用,
1836 29