最近在做一个面向中小制造企业的生产管理系统,代号「轻排 PMClite」。做到现在有一些架构层面的思考,记录一下,供有类似需求的同学参考。文章不谈具体实现细节,主要聊技术选型的逻辑和踩过的坑。
一、轻排 PMClite 是什么
先给结论:轻排 PMClite 是一款面向中小制造企业的本地部署、买断制、轻量级生产管理系统。
它的目标场景很具体:
10-200 人的中小制造工厂
销售、采购、仓库各一份 Excel,数据永远对不上
多级 BOM 用 VLOOKUP 拼,改一个料号公式全乱
缺料要等到开工才发现
排产靠资深 PMC 人脑,这个人一休假就乱
轻排 PMClite 的核心定位是替代中小工厂里"多份 Excel 各管一块"的低效协作方式,聚焦 PMC(生产计划与物料控制)最痛的几件事:多级 BOM、齐套检查、排产、领料、追溯。
它不做全流程 ERP,只解决上面这几个具体问题。
二、技术选型的逻辑
轻排 PMClite 的技术栈是:
| 层级 | 选型 |
|---|---|
| 桌面框架 | Tauri 2.x |
| 后端语言 | Rust |
| 数据库 | SQLite + SQLCipher |
| 前端 | 原生 HTML/CSS/JS |
| 多机通信 | 局域网 UDP + HTTP |
为什么选 Tauri 而不是 Electron
这是轻排 PMClite 最早做的一个决定。对比:
| 维度 | Tauri | Electron |
|---|---|---|
| 安装包 | ~30MB | ~150MB |
| 内存 | ~60MB | ~200MB |
| 渲染 | 系统 WebView | 内置 Chromium |
| 后端 | Rust | Node.js |
面向工厂的软件,装完不占资源、启动快,比什么都重要。工厂电脑很多是几年前的老机器,150MB 的包体加上 200MB 内存,会直接影响体验。
为什么不用 MySQL
用户是工厂,不是互联网公司。没人愿意为了一套管理软件再装数据库、配用户权限、定期备份。SQLite 单文件丢进应用目录就跑,这是轻排 PMClite 最合适的存储方案。
选择 SQLCipher(SQLite 的加密分支)而不是明文 SQLite,是因为轻排 PMClite 的用户明确要求"数据不能外流"。
为什么不用云
轻排 PMClite 从一开始就确定了本地部署的路线。原因:
用户明确表示不信任公有云
工厂网络条件参差不齐,云端延迟不可控
客户名单、成本价这类数据,老板不想放在别人服务器上
这不是技术问题,是产品定位问题。轻排 PMClite 的目标用户就是"不想上云"那一批人。
三、局域网多机同步的思路
这是轻排 PMClite 做得最费劲的部分。用户不想上云,但多台电脑要看到同一份数据。
3.1 架构选择
常见的多机同步方案有三种:
中心服务器—— 需要单独一台机器做服务端
云同步—— 数据经第三方中转
去中心化—— 每台电脑都能发现彼此
轻排 PMClite 选了去中心化发现 + 主机-客户端模型:
局域网内所有节点通过 UDP 广播自动发现彼此
一台电脑作为"主机",负责存储数据
其他电脑作为"客户端",定时从主机拉取
不需要单独买服务器,也不需要任何云服务。
3.2 节点发现
轻排 PMClite 用 UDP 广播做节点发现:
每台机器定时向局域网广播自己的信息(主机名、IP、角色)
同时监听广播,维护一份"附近设备列表"
超时未响应的节点自动移除
踩坑:UDP 广播在部分企业网络环境下会被路由器拦截。轻排 PMClite 目前依赖的是"办公 WiFi 或交换机直连"这个前提。
3.3 数据传输
主机启动一个轻量 HTTP 服务(tiny_http),暴露三个接口:
| 接口 | 用途 |
|---|---|
/api/info | 返回主机版本信息 |
/api/snapshot | 返回全量数据快照 |
/api/push | 接收客户端的增量推送 |
为什么用tiny_http而不是axum/actix-web:轻排 PMClite 只有一个 web 服务线程,没必要引入异步框架。tiny_http足够简单,编译后体积也小。
踩坑:CORS 必须显式处理。Tauri 的 WebView 发起 fetch 时会带 Origin 头,服务端要返回Access-Control-Allow-Origin。
3.4 增量同步
全量传输显然不行——5 万行数据一次传几十 MB。轻排 PMClite 的做法是前端算差异、后端应用差异:
前端维护一份"上次保存时的快照"
保存时对比当前数据与快照,生成差异列表(新增、修改、删除)
差异列表通过 IPC 发送到 Rust 后端
后端在一个事务里应用所有变化
设计取舍:不追求极致性能,优先保证数据一致性。目前已知的优化点是差异计算本身还可以加速,但 5 万行以内体验完全可接受。
四、几个具体的坑
4.1 Tauri IPC 的类型陷阱
轻排 PMClite 开发过程中,遇到最隐蔽的一个 bug 是 Tauri IPC 的类型问题:
Rust 端某个命令参数是
Option<String>前端传了一个数字类型的 id
serde 反序列化报错
invalid type: integer, expected a string而这个错误被 Promise 的
catch吞掉了,表现为"命令静默失败"
教训:轻排 PMClite 后来统一约定了"所有 id 相关字段前端传参前必须转字符串"。
4.2 手写签名的性能问题
轻排 PMClite 的领料单支持手写电子签名(可选功能)。最初实现有个性能问题:
每次鼠标移动都调
canvas.toDataURL()生成 base641600×400 的 canvas 上单次 10-20ms
鼠标每 16ms 触发一次,直接卡成幻灯片
修正:只在抬手时生成一次,并改用 JPEG 格式。
收益:手写流畅,签名体积降到原来的三分之一。
4.3 批量操作的事务问题
轻排 PMClite 的领料单一次可能涉及几十个物料。最初的实现里,每个物料更新都会触发一次完整保存:
50 个物料 = 50 次差异计算 + 50 次 IPC 保存
耗时约 10 秒
修正:给"更新库存"这个操作加了"延迟保存"参数,循环内不保存,循环外统一保存一次。
效果:10 秒降到 0.5 秒。
4.4 数据备份
轻排 PMClite 的备份不用文件拷贝(会锁库、可能损坏),用的是 SQLite 的VACUUM INTO:
原子操作
生成的备份文件同样是加密的
不需要停服务
踩坑:目标文件必须不存在,否则报错。所以要先检查路径。
五、一些设计原则
做轻排 PMClite 这一年,总结了几个原则:
原则一:不做全流程 ERP
大型 ERP 有 60% 的功能,中小工厂根本用不上。轻排 PMClite 只解决 PMC 最痛的几件事——多级 BOM、齐套检查、排产、领料、追溯。其他模块,比如总账、报税、HR,一律不做。
原则二:数据安全优先
轻排 PMClite 的用户画像里,"不相信云"是很核心的一条。所以:
数据全部本地存储
数据库加密
不依赖任何第三方服务
断网照常用
原则三:开箱即用
工厂老板没有耐心等三个月实施。轻排 PMClite 的目标是"下载、安装、3 分钟上手"——不装数据库、不配服务器、不培训。
原则四:买断制
SaaS 的订阅模式对中小工厂不友好——他们宁可为一次性投入,也不愿意每年付续费。轻排 PMClite 从第一天就是买断制。
六、目前还没解决的问题
诚实地列一下轻排 PMClite 已知的优化点:
差异计算的全表扫描:5 万行数据下每次保存约 300ms,可以优化
数据库连接每次重开:每个命令约 20-50ms 开销,可以缓存
审计日志队列的 flush 时机:目前是去抖机制,极端情况下可能丢日志
同步接口的认证:目前依赖"局域网内"这个前提,将来可能加共享密钥
本地图片上传:目前只支持在线 URL,本地图片要考虑多机同步、备份、路径失效等一堆问题
这些问题都不影响轻排 PMClite 的基本可用性,但会在数据量增长或场景复杂后暴露。
七、小结
轻排 PMClite 的技术选型核心思路是:用最小依赖解决最核心问题。
不用 Electron,因为 30MB vs 150MB 差太多
不用 MySQL,因为工厂不愿装数据库
不用云,因为轻排 PMClite 的目标用户明确不要
不用异步框架,因为单进程场景不需要
不做全流程 ERP,因为 60% 功能用不上
这套方案不追求技术先进性,追求的是在中小工厂这个具体场景下,用最少的运维成本解决最痛的问题。
轻排 PMClite 目前提供 30 天免费试用,支持中文、English、Tiếng Việt、ไทย、Bahasa Indonesia、Español、Português 七种语言。如果对轻排 PMClite 的技术方案或产品定位有讨论兴趣,欢迎交流。