软件技术学习笔记

个人博客,记录软件技术与程序员的点点滴滴。

NodeJS网络调用链优化

为了提升用户体验,前端首屏使用NodeJS SSR。为了容易观测多个环境NodeJS层的网络调用链与性能,我们加入了Jaeger链路追踪,这也是微服务开发中常用的手段。

通过Jaeger UI观察,我们很容易发现首屏SSR与API转发有以下问题:

  1. 多段接口依次执行,有先后次序依赖,没有发挥并发请求的优势。
  2. 未区分用户类型,有多余的网络请求。
  3. 转发的API请求,也请求多余的用户信息等。

如果使用以前打日志的方式,缺少可视化的分析手段,定位问题的周期比较长。处理以上的问题之后,首屏SSR与API转发的网络性能提升50%,给后端的请求数分别减少3/8与3/4。在并发量比较大的情况下,可以很大程度上减轻服务器的压力。

目前,用户量比较少,在云上后端接口返回在50ms时,首屏SSR可以在100ms内处理完成(不算用户到服务器的网络延时)。这也是我目前性能优化的极限了。

继续阅读→

新的方式传递链路追踪上下文(NodeJS)

最近一个多月都在忙于项目,没有时间记录新的知识。我们起了一个全新的前端项目,技术选型是React + SSR + Dva。要求的起点也比较高:用户导航首屏SSR,其它时候CSR;代码要求SSR与CSR复用;所有的请求经过Node层;页面显示、接口请求均要求小于1秒。

为了容易定位调用链路的性能点,我们加入了Jaeger Open Tracing,这就涉及到链路追踪上下文的传递。

继续阅读→

NodeJS微服务间传递用户上下文

后端包含众多微服务时,如果每个微服务都是自己去查询用户信息(比如: 用户ID、登录名),会造成用户微服务压力过大、响应延时增大。为了解决这类问题,可以在网关服务中查询用户信息等共用信息,然后传递到其它的微服务中,微服务之间也相互传递。

为了前端代码复用,在NodeJS中也使用Axios完成网络请求,也方便我们拦截处理。文本演示Express + Axios + Async hooks解决微服务间用户上下文传递的问题。

继续阅读→

NodeJS微服务APM

上微服务时,我们必需有全链路追踪、应用程序性能监测(APM)。开源的Elastic Stack是一个不错的选择,它包含日志、指标、APM、搜索、Kibana等。使用Elastic Stack做NodeJS APM时,使用起来非常方便,代码也无入侵。

只需在程序的前面添加一行代码: const apm = require('elastic-apm-node').start(); 然后添加环境变量ELASTIC_APM_SERVER_URL,正常启动程序: node index.js

能如此方便地使用,也是得益于NodeJS的事件模型、async_hookselastic-apm-node,其中的elastic-apm-node已经帮我们创建好同步或异步流程中的Transaction与Span。大部分时候,我们只需写好自己的业务代码。

样例代码:apm-nodejs-app-aapm-nodejs-app-bapm-nodejs-app-c

继续阅读→

NodeJS C++插件开发体验(N-API)

NodeJS C++插件直接扩展NodeJS V8引擎,性能比JS要高很多。同时,通过N-API跨越JS与C++的边界,不需要做序列化/反序列化,性能代价也很小。根据二八法则,使用C++插件来解决NodeJS业务系统的性能问题/密集型计算,而不是完整业务系统的主要功能。

在开发NodeJS插件时,可以选择N-API、nan、或者内部V8接口实现。但是,N-API有良好的ABI兼容性,可确保插件一次编译能够在多个NodeJS版本中运行,更新NodeJS版本之后不需要重新编译插件。学习NodeJS插件开发,可参考官方的node-addon-examples

在本示例中,我们使用C++11 std与boost实现4个导出函数:

generateNumbers(n: number, callback: (v: number) => void): void;
joinStrings(arr: string[], sep: string): string;
isPrime(n: number) => boolean;
isPrimeAsync(n: number): Promise<boolean>;

本示例源码:napi-addon-1-hello-primes

继续阅读→