Intro前阵子在公司搭建了一个日志服务,用于记录前端的错误信息。这个过程非常简单。前端通过get将如下格式的信息发送给日志服务:{"url":"https://www.arkie.cn/scenarios","channel":"frontend","level":"FATAL","crashId":"02x32f3","stack":"base64string......",...}日志服务收到该请求后,将Stack解析成JSON:JSON.parse(decodeURIComponent(Buffer.from(query.stack,'base64').toString())),解析后的栈是这样的:[{"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},]然后日志服务会根据文件对应的sourcemap解析出原来的错误位置(部署时前端项目已经上传到私有CDN)。例如:{filename:'./src/modules/design/design.container.tsx',line:102}***将处理后的信息输出到阿里云的LogHub。优化完第一个脆弱的版本,发现只过去了一天半,于是开始思考优化。第一个版本有两个问题。第一个问题是后端处理日志的过程太长,导致性能消耗大。第二个问题是日志的实时处理会导致用户数量增加后服务器不堪重负。其实日志服务的实时性要求并没有那么高。第一个问题可以优化代码性能(能优化才怪),拆分步骤(这个靠谱),第二个问题也可以通过拆分数据处理步骤来解决。拆分处理步骤的解决方案可以通过在日志服务中添加队列来解决。比如接收到前端请求后,直接将原始数据塞入队列,然后一个消费者以最大速率从队列中取出原始日志,处理后放入LogHub。这部分的细节不再赘述。扩写的话又是一长串的事情了。在性能优化方面,我并没有抱太大希望,因为实在看不出有什么可以优化的。base64decode-->JSON.parse-->sourcemapparse都使用第一层的标准库调用(sourcemapparse使用Mozilla出品的https://github.com/mozilla/source-map),但是在前夕上线的时候突然想起一个库neon-bindingsRust!Rust!,是前不久学习Rust的时候看到的!是否可以使用更快的语言来优化Sourcemap处理的过程?同时,大部分主要的繁琐业务仍然是用TypeScript编写的。研究了一圈,发现国内一些公司已经在项目中使用neon来写业务:https://www.zhihu.com/question/19903210/answer/207779913而熟悉的sentry在生产环境中也使用Rust解析sourcemaphttps://segmentfault.com/a/1190000007299177,虽然都是绑定python的,但是他们开源了Rust代码:https://github.com/getsentry/rust-sourcemap也就是说,我只需要通过neon-bindgs将这部分Rust代码封装成一个模块,NodeJS可以调用。不像sentry,需要先移植出CAPI,然后通过python调用C代码。写代码的过程和原理就省略了。代码可以看:https://github.com/Brooooooklyn/sourcemap-decoder,主要分享一些数据和陷阱:Benchmark,所以Rust在处理同样的Sourcemap比JavaScript代码parse快多少?我做了一个简单的基准测试,测试结果如下:$nodebenchmarkJavaScriptparsetime50794microsecondsRustparsetime:39microsecondsJavaScriptparseresult,Source:webpack:///src/utils/logger/logger.ts,Line:56Rustparse结果,来源:webpack:///./src/utils/logger/logger.ts,行:56:火花:在0.33秒内完成。硬件信息:产品名称:MacOSXProductVersion:10.13.3BuildVersion:17D47型号名称:MacBookProModel标识符:MacBookPro14,2处理器名称:英特尔酷睿i5处理器速度:3.1GHz处理器数量:1内核总数:2L2高速缓存(每个内核):256KBL3高速缓存:4MB内存:16GB基准代码:https://github.com/Brooooooklyn/sourcemap-decoder/blob/master/benchmark/index.js因为每次调用Rust代码都会有一个bootstrap过程,JavaScript代码运行多次后会被JIT优化,差距可能会缩小一次跑几万次的情况十次以上,如果你有兴趣泰德,你可以自己试试。CI/CD刚写完上线的时候,想把production镜像做的越小越好(我们用的是Docker),所以在Production镜像上直接使用node:8-alpine作为基础镜像,对应的,CI镜像(我们用的是Gitlabrunner的Dockerexecutor)也是用同样的baseimage,然后花了三个多小时尝试在Alpine上安装最新的rusttoolchains失败,***不得不忍受了更多的体积差异开关距离超过100m到达节点:8-slim。国内最终能顺利搭建的Dockerfile安装在https://github.com/Brooooooklyn/sourcemap-decoder/blob/master/DockerfileToolschains。由于众所周知的原因,CI在刚开始构建镜像时异常缓慢,直到超时被Gitlabkill挡住,经过一个多小时的顽强抵抗,所有可能撞墙的步骤都换成了USTC镜像.主要是开发机rustup安装需要:curlhttps://sh.rustup.rs-sSf|sed"s/https:\/\/st??atic.rust-lang.org\/rustup\/dist/https:\/\/mirrors.ustc.edu.cn\/rust-static\/rustup\/dist/g"|sh使用USTC源安装Rustupbuild安装前:cat>$HOME/.cargo/config<
