用户可通过该项目学习将 Node.js 小服务迁移到仓颉语言的完整过程,包含迁移步骤、问题解决办法及性能对比。项目提供可复现的测试资产,帮助工程师与研究者评估仓颉迁移可行性,理解关键差异并展开优化。【此简介由AI生成】
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 7 个月前 | ||
| 7 个月前 | ||
| 7 个月前 | ||
| 7 个月前 | ||
| 7 个月前 |
迁移案例研究:将 Node.js 小服务迁移到 仓颉(Cangjie)
概要
本档为一项“仓颉语言迁移案例研究”:将一个现有的小型 Node.js 服务完整迁移为仓颉(Cangjie)实现,记录迁移步骤、遇到的问题与解决办法,量化性能与代码量差异,并提供可复现的测试资产(脚本、基准输出与一键运行包)。文档面向希望评估或实践仓颉迁移的工程师与研究者,帮助快速复现、理解关键差异并展开后续优化。
目标与范围
- 功能等价:实现与 Node 相同的 HTTP 端点,保持 Content-Type 与返回格式兼容。
- 最小化依赖:使用
stdx.net.http(vendor 化以便离线复现),避免外部数据库或复杂中间件。 - 可复现性:提供一键运行脚本、bench 脚本与说明,便于他人复现结果。
项目结构(关键路径)
test1文件夹下
src/— 仓颉实现源代码(入口main.cj,controllers 等)。node-ref/— Node 参考实现与基准脚本(node-ref/bench/simple-bench.js)。bench/— 运行脚本、日志与结果(bench/run-cj-bench.ps1、bench/results/等)。bench/one-click/— 一键打包脚本与说明(run-all.ps1、README、LICENSE)。
迁移步骤摘要
- 搭建仓颉工程骨架(
cjpm.toml指向 vendor stdx,src/放置 handler)。 - 将每个路由移植为仓颉 handler(GET/POST),对 POST 的 body 使用 InputStream 逐块读取并按需合并。若可知 Content-Length,优先预分配缓冲区以提高性能。
- 处理 HTTP 头:显式设置
Content-Type,并在高并发测试中避免一开始就强制Connection: close(移除Connection: close后稳定性更好)。 - 运行并调试:使用
bench/run-cj-bench.ps1启动服务、轮询就绪并运行node-ref/bench/simple-bench.js进行压测,保存输出到bench/results/。 - 记录问题并迭代:针对
socket is closed警告、echo 实现的拼接效率、Windows 下的 OpenSSL 依赖和文件锁问题逐项修复或给出规避建议。
环境与先决条件
- 操作系统:Windows(PowerShell 环境)
- 必备:Node.js(用于运行基准脚本)、Cangjie 工具链(
cjpm/cjo,如需运行 Cangjie 服务) - 运行时库:Windows 下
stdx.net.http可能需要 OpenSSL DLL(libssl/libcrypto),请把 DLL 放入vendor/或系统 PATH。
运行与复现(快速命令示例)
在仓库根目录的 PowerShell 中:
# 启动 Cangjie(背景)并把日志写入文件
Start-Process -FilePath 'powershell.exe' -ArgumentList '-NoProfile','-Command','cjpm run' -WorkingDirectory (Resolve-Path .).Path -RedirectStandardOutput 'bench\cj_stdout.log' -RedirectStandardError 'bench\cj_stderr.log' -PassThru
# 等待服务就绪(轮询)
for ($i=0; $i -lt 60; $i++) { try { $r = Invoke-WebRequest -Uri 'http://127.0.0.1:3000/' -UseBasicParsing -TimeoutSec 1 -ErrorAction Stop; if ($r.StatusCode -eq 200) { break } } catch { Start-Sleep -Milliseconds 200 } }
# 运行 bench(示例:50 并发 10 秒)
node node-ref\bench\simple-bench.js -c 50 -d 10 http://127.0.0.1:3000/api/hello | Tee-Object -FilePath bench\results\cj-api-hello-$(Get-Date -Format yyyyMMdd-HHmmss).txt
# 启动 Node 参考服务(若单独跑 Node 基线)
node node-ref\index.js
我还添加了 bench/one-click/run-all.ps1,可以自动:运行 CJ 的 bench(若 CANGJIE_RUN_CMD 已设置)、运行 Node 的 bench、收集输出并把 src/、node-ref/、cjpm.toml 等拷贝到 bench/one-click-output-<ts>/ 以便打包发布。
关键基准结果(摘选)
- Cangjie —
GET /hello-min(50c × 10s): requests 37917, errors 0, mean 13.15 ms, rps ≈ 3791.7。 - Cangjie —
GET /api/hello(移除Connection: close)(50c × 10s): requests 32876, errors 0, mean 15.18 ms, rps ≈ 3287.6。 - Node —
GET /api/hello(50c × 10s, Node 运行于 3001): requests 108912, errors 0, mean 4.57 ms, rps ≈ 10891.2。
说明:Node 在该机与实现上显示更高吞吐与更低延迟;Cangjie 在调整后表现稳定且无错误。完整测试数据见 bench/results/benchmark-comparison.md 与 bench/results/ 中的具体输出文件。
遇到的问题与已采取的解决办法
- socket 警告(
ConnectionException: socket is closed)- 原因分析:与短连接(
Connection: close)与流式/阻塞读取逻辑有关,客户端或服务器在高并发下可能提前关闭连接。 - 解决:在多数 handler 中移除显式
Connection: close,启用 keep-alive;并把 echo handler 改为先完整读取 body 后解析。问题明显缓解,错误数降为 0。
- 原因分析:与短连接(
- Echo 的缓冲合并性能
- 问题:使用
acc = acc.concat(part)在大体量或多次拼接场景下会产生 O(N^2) 行为。 - 建议:使用 parts 列表并在最后一次性合并;或在可知 Content-Length 时预分配缓冲区;或实现可增长的 ByteBuffer。
- 问题:使用
- Windows OpenSSL 与文件锁
- 建议:将必要的 OpenSSL DLL 复制到
vendor/并在 README 中注明;在构建脚本中停止运行实例以避免文件锁。
- 建议:将必要的 OpenSSL DLL 复制到
建议的后续工作(优先级)
- 优化
POST /api/echo:改为 parts 列表 + 最后合并;添加单元/集成测试覆盖大/小 payload。 - 并发阶梯测试:自动化对并发级别 [1,5,10,20,50] 的短时测试,生成 CSV 汇总以便制图比较。
- 增加 DEBUG 日志(可选)以记录请求/连接 id,便于在高并发下追踪何时/为何连接被关闭。
- 若计划开源:完善
bench/one-click/README.md、选择并统一许可证(bench/one-click/LICENSE已为 MIT 示例),并考虑把大型二进制(如 OpenSSL DLL)以合规方式提供或指向安装说明。
参考与附录
- 仓颉 HTTP 文档:https://developer.huawei.com/consumer/cn/doc/cangjie-guides-V5/net_http-V5
- 仓颉 stdx 二进制发布(示例):https://gitcode.com/Cangjie/cangjie-stdx-bin/releases
- 仓库内重要文件:
bench/results/benchmark-comparison.md、bench/run-cj-bench.ps1、node-ref/bench/simple-bench.js、bench/one-click/run-all.ps1。
项目介绍
用户可通过该项目学习将 Node.js 小服务迁移到仓颉语言的完整过程,包含迁移步骤、问题解决办法及性能对比。项目提供可复现的测试资产,帮助工程师与研究者评估仓颉迁移可行性,理解关键差异并展开优化。【此简介由AI生成】
定制我的领域