使用 Rust 加速前端 Log Service

新闻 前端
前阵子在公司内搭建了一个 Log Service,用来记录前端的报错信息,代码一顿乱写搞的七七八八之后实现了第一版的功能。

Intro

前阵子在公司内搭建了一个 Log Service,用来记录前端的报错信息,代码一顿乱写搞的七七八八之后实现了***版的功能。

流程很简单,前端将以下格式的信息用 get 发到 Log Service:

{
  "url": "https://www.arkie.cn/scenarios",
  "channel": "frontend",
  "level": "FATAL",
  "crashId": "02x32f3",
  "stack": "base64 string ......",
  ...
}

Log Service 接受到这个请求以后,将 Stack 解析成 JSON : JSON.parse(decodeURIComponent(Buffer.from(query.stack, 'base64').toString())) , 解析后的 stack 是这样的 :

[
  { "filename": "https://arkie-public.oss-cn-hangzhou.aliyuncs.com/js/main.c3600f3f.js", line: 1, column: 334222 },
  { "filename": "https://arkie-public.oss-cn-hangzhou.aliyuncs.com/js/common.752d2f13.js", line: 1, column: 113242 },
]

然后 Log service 会根据文件对应的 sourcemap (前端各项目 deploy 的时候已经上传到私有 CDN 了) 解析出原始报错位置。比如:

{
  filename: './src/modules/design/design.container.tsx',
  line: 102
}

***会将这些处理后的信息输出到阿里云的 LogHub。

优化

做完***个脆弱的版本后发现时间仅仅过去了一天半,所以开始考虑优化的事情了。

***个版本有两个问题,***个问题是在后端处理 log 的流程太长导致性能消耗有点大,第二个问题是实时处理 Log 在后面用户增多之后服务器会不堪重负,而其实 Log Service 的实时性要求并没有那么高。

对于***个问题,可以优化代码性能(能优化才怪),分拆步骤(这个靠谱)来解决,第二个问题也可以通过分拆数据处理步骤来解决。

而分拆处理步骤这个解决方案可以通过在 Log Service 中加入一个 queue 来解决。比如接受到前端请求后,直接将原始数据塞到 queue 中,然后有一个 consumer 按一个***速率从 queue 中取出原始日志,处理之后再放入 LogHub,这一部分的细节就不赘述了,要写的话展开又是一个长篇大论。

而优化性能这方面,我本来没有抱什么希望,因为实在是看不出有啥可优化的。 base64 decode --> JSON.parse --> sourcemap parse 都用的是***层的标准库调用( sourcemap parse 用的是 Mozilla 出品的 https://github.com/mozilla/source-map )

然而在上线的前夕,我突然想起了前不久学习 Rust 的时候看到的一个库 neon-bindings

Rust!Rust!

是不是可以用更快的语言来优化 Sourcemap 处理的过程呢,同时大部分主要的繁琐的业务还是使用 TypeScript 编写。

调研了一圈发现,已经有国内的公司在项目里面用 neon 写业务了: https://www.zhihu.com/question/19903210/answer/207779913

并且大家熟悉的 sentry 在生产环境中也是使用 Rust 来 parse Sourcemap https://segmentfault.com/a/1190000007299177,虽然他们是 binding 到了 python 上,但他们已经把 Rust 代码开源出来了: https://github.com/getsentry/rust-sourcemap

也就是说我只需要把这部分的 Rust 代码通过 neon-bindgs 封装成 NodeJS 可调用的模块就行了,不像 sentry 还要 port 出 C API 再通过 python 调用 C 的代码,美滋滋。

写代码的过程和原理就省略了,代码可以在: https://github.com/Brooooooklyn/sourcemap-decoder 看到,主要分享一些数据和踩的坑:

Benchmark

所以 Rust 比 JavaScript 代码在处理同样的 Sourcemap 时 parse 快多少呢?

我做了一个简单的 benchmark, 测试结果如下:

$ node benchmark

JavaScript parse time 50794 microseconds

Rust parse time: 39 microseconds

JavaScript parse result, Source: webpack:///src/utils/logger/logger.ts, Line: 56

Rust parse result, Source: webpack:///./src/utils/logger/logger.ts, Line: 56

:sparkles:  Done in 0.33s.

Hardware Info:

ProductName:    Mac OS X
ProductVersion: 10.13.3
BuildVersion:   17D47
Model Name: MacBook Pro
Model Identifier: MacBookPro14,2
Processor Name: Intel Core i5
Processor Speed: 3.1 GHz
Number of Processors: 1
Total Number of Cores: 2
L2 Cache (per Core): 256 KB
L3 Cache: 4 MB
Memory: 16 GB

Benchmark 代码: https://github.com/Brooooooklyn/sourcemap-decoder/blob/master/benchmark/index.js

因为每次调用 Rust 的代码会有一次 bootstrap 的过程以及 JavaScript 代码在运行很多次后会被 JIT 优化,在一次性运行几万次的情况下差距可能缩小为十几倍,有兴趣大家可以自行尝试。

CI/CD

刚写完打算上线的时候,想让 production 的镜像尽量小一点(我们用的 Docker),所以直接在 Production 的 Image 上用了 node:8-alpine 作为 base image,相应的,CI 的镜像(我们使用的是 Gitlab runner 的 Docker executor )也是用同样的 base image,然后花了三个多小时尝试在 Alpine 上安装 latest rust toolchains 后失败了,***不得不忍受 100 多 m 的体积差切换到了 node:8-slim。最终的国内可以流畅 build 的 Dockerfile 在 https://github.com/Brooooooklyn/sourcemap-decoder/blob/master/Dockerfile

Toolschains 安装

由于众所周知的原因,CI 在刚开始 build image 的时候异常的缓慢,直到超时被 Gitlab kill 掉,经过一个多小时顽强的抵抗后将所有可能撞墙的步骤全部替换成了 USTC 的 mirror。

主要是 dev 机器 rustup 安装需要:

curl https://sh.rustup.rs -sSf | sed "s/https:\/\/static.rust-lang.org\/rustup\/dist/https:\/\/mirrors.ustc.edu.cn\/rust-static\/rustup\/dist/g" | sh

使用 USTC 的源安装 Rustup

build 前需要:

cat > $HOME/.cargo/config << EOF
[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = 'ustc'
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"
EOF

让 Cargo 也是用 UTSC 的源(CI 环境也需要执行同样的命令)

在 CI 的 Docker Image build 的时候需要 替换 Rust 下载源 以及 替换 Rustup源

详情请参考 README

责任编辑:张燕妮 来源: 前端外刊评论
相关推荐

2021-07-16 10:32:33

前端元编程代码

2023-10-27 10:16:17

前端项目Rust

2024-05-22 10:03:59

2020-09-01 12:23:01

CDN加速前端

2024-02-28 08:38:07

Rust前端效率

2024-09-30 09:25:29

2023-06-15 17:00:11

Rust循环

2015-04-20 10:06:37

PHP Rust 创建PHP 扩展

2024-05-23 08:12:45

Rust前端开发JavaScrip

2024-03-12 08:22:50

TypeScriptRust框架

2020-10-21 14:54:02

RustGolang开发

2023-05-26 17:21:15

PythonRust

2023-05-04 07:33:39

Rust变量常量

2024-09-06 11:34:15

RustAI语言

2024-04-03 10:00:44

Rust编译开发

2023-06-12 08:00:48

Napi-rsRust 前端工具

2021-05-19 10:43:28

恶意软件Rust的Buer

2024-01-09 09:27:57

Rust编程泛型

2021-10-26 21:50:10

Rust嵌入式开发

2024-01-07 17:29:10

编程语言线程Rust
点赞
收藏

51CTO技术栈公众号