前言
这篇文章讲的是我负责的一个产品,记录一下它从一个 MVP (最小可行性产品) 开始,一步步走向分布式,再到拥抱云原生的演进过程。
过程不算一帆风順,充满了各种技术选型、架构决策的纠结与取舍。想把这些思考和踩过的坑记录下来。
第一阶段:MVP - 一切为了快
故事始于 2023 年初。当时的目标很明确:用最快的速度验证一个产品概念,拿出原型 Demo。因此,我的技术选型一切从简,怎么快怎么来。
- 技术架构:选择了团队最熟悉的 Qt (WebAssembly) 前端 + C++ (Drogon 框架) 后端 的 B/S 架构。
- 服务集成:为了验证核心功能,直接用命令行调用的方式,集成了两个现成的 Python 工具脚本。
这个阶段,速度就是一切。现在回头看,这种务实的选择是正确的,它帮助我快速验证了想法,为产品后续的发展方向拿到了宝贵的“入场券”。
第二阶段:V1.0 - 打下分布式与 DevOps 的地基
MVP 验证成功后,产品被确立为一条独立的业务线,组建了新的研发小组。原有的“小作坊”架构显然已经撑不起未来的“大厦”,一次彻底的技术重构势在必行。
2.1 后端重构:走向微服务与云原生
为了支撑产品未来的 SAAS 模式,我决定用 Go 语言重写后端,目标是构建一个可扩展、高可用的微服务架构。
- 语言选型:从 C++ 迁移到 Go。Go 的高并发性能、简单的部署方式以及日益丰富的生态,对我很有吸引力。
- 权限体系:之前用 C++ 时,因为缺少成熟的开源方案,我自己实现了一套基础的 RBAC 系统。但这套“轮子”在功能扩展和维护上越来越吃力,这也成了我迁移到 Go 的一个推力。重构后的 Go 后端采用了业界主流的 Casbin 库,实现了更灵活、更精细的权限管理,省下了不少功夫。
- 通信协议:告别了原始的命令行调用,我引入了 gRPC 作为 Go 后端与 Python 工具服务之间的标准通信方式。这使得服务间的职责更清晰,也为后续的容器化部署铺平了道路。当时,我编写了初版的 Python gRPC 服务端,顺利地将原有工具切换到了新协议上。
- 分布式存储:引入 MinIO 作为对象存储服务,将数据集与结果文件进行统一管理,实现了存储与计算的解耦。为了方便工具组的同学,我还基于 MinIO 的 SDK 封装了一套简单易用的函数库。
- 异步任务流:
- 任务生产:Go 后端负责创建并分发任务。
- 实时反馈:Python 工具在执行任务时,通过 gRPC 流式(Streaming) 通信,向后端实时汇报日志和进度。
- 结果回传:任务完成后,将结构化的结果数据返回给后端。
- 容器化探索:当时也调研了 Kubernetes (K8S),但考虑到初期的团队规模和运维复杂度,觉得一步到位可能有点“用力过猛”,最终决定采用逐步迁移的策略,先将各个服务容器化。
- AI能力探索:在模型上下文协议(MCP)概念刚兴起时,我对此很感兴趣,便对 Go 和 Python 的 MCP 库进行了一些技术预研。我尝试为后端服务实现了 MCP 接口,并在 Dify 平台上打通了调用工作流,为产品未来集成 AI 能力埋下了一颗种子。
2.2 前端演进
前端也从 Qt (WebAssembly) 重构为 Vue。起初是基于一个现有的 Vue 2 项目开发,但随着团队壮大和对现代前端技术的需求日益强烈,后续我推动前端框架升级到了 Vue 3。
2.3 DevOps 基础设施建设
为了提升开发效率和软件质量,我开始着手搭建 DevOps 体系。
- 版本控制与 CI/CD:
- 初期:使用 GitLab + GitLab Runner 实现 CI,从最开始的手动编译,进化到 C++ 自动编译,再到后来的 Docker 镜像自动构建。
- 后期:为了更轻量、更灵活,我将技术栈迁移到了 Gitea + Act Action。兼容 GitHub Actions 的生态,让我可以更方便地使用社区沉淀的各种工具,维护成本也降低了不少。
- 服务器管理:从宝塔面板换成了 1Panel,界面更现代化,用起来更顺手。
- 项目管理:项目管理工具也几经辗转,从禅道到 Redmine,最终选定了 OpenProject。OpenProject 现代化的界面和强大的甘特图功能,能更好地满足我对项目进度的跟踪和管理需求。
2.4 挑战与反思
V1.0 的重构奠定了坚实的基础,但也并非一帆风顺。
- 团队技能成长:技术栈迭代速度很快,对团队成员的学习能力提出了很高的要求。如何让技术更好地驱动业务,而不是成为少数人的“炫技”,是我一直在思考的问题。
- 工程化成熟度:在快速迭代中,单元测试等质量保障体系没有完全跟上,导致一些代码质量债。这提醒我,工程化规范必须尽早建立,否则日后要付出的代价会更高。
第三阶段:V2.0 - 拥抱云原生与前端现代化(正在做)
随着业务的深入,新的挑战又出现了,尤其是在分布式任务调度和前端用户体验上。
3.1 分布式调度优化:从“服务”到“任务”
背景:有三个独立的 Python 算法工具,需要专门的成员开发维护。但由于人力有限,且工具开发同学对并发、高可用等服务端技术不熟悉,导致这些“服务化”的工具成了整个系统的瓶颈。
原方案:算法工具服务化 (Long-Running Service)
- 架构:将算法工具封装成一个个长期运行的 gRPC 服务,和后端一起部署。
- 痛点:这个方案对算法工程师的要求太高了。他们不仅要实现算法,还得头疼并发、多线程、服务健壮性这些复杂的工程问题,有点“赶鸭子上架”。
新方案:任务即容器 (Task-as-Container)
为了解决这个痛点,我调整了思路,决定将任务调度的复杂性从工具本身剥离,由后端统一处理。
- 核心思想:
- 工具标准化与容器化:将算法工具改造成一个纯粹接收命令行参数的程序,连同它的所有依赖,一起打包成标准的 Docker 镜像。这样一来,工具的运行就和环境彻底解耦了。
- 任务驱动的动态实例化:后端接收到请求后,根据任务类型,动态拉取对应的工具镜像,创建一个容器实例。任务配置作为启动参数传入,真正实现了“一个任务,一个容器”。
- “用后即焚”的无状态执行:容器的生命周期和任务完全绑定,任务结束,容器就自动销毁。这保证了资源的即时回收,也避免了状态带来的各种问题。
- 集中式生命周期管理:容器的创建、监控、日志收集和销毁,全部由后端统一搞定。算法工程师彻底从繁琐的运维和工程问题中解放出来。
这个方案极大地简化了算法工具的开发模式,让算法工程师可以真正专注于算法本身。
这一套方案我也用在了我业余时间在开发的一套开源工具上 ArkServerCommander (还没有正式发布)
3.2 前端现代化重构
为了打造更好的用户体验和品牌形象,前端的现代化重构也被提上了日程。当时我评估了两种主流方案。
方案一:基于 Vue.js 生态升级
延续现有的技术栈,在 Vue 生态内做现代化升级。
技术选型 | 主要优势 |
---|---|
Nuxt.js | 企业级 Vue 框架,提供 SSR/SSG,提升 SEO 与首屏性能。 |
Vuetify | 遵循 Material Design 的完备组件库,风格统一专业。 |
Element Plus | 庞大的国内社区,中文文档完善,上手成本低。 |
Naive UI | 主题可定制性强,性能出色,TypeScript 支持友好。 |
Nuxt UI | Nuxt 官方 UI 库,基于 Tailwind CSS,与生态无缝集成。 |
优点:学习曲线平缓,团队成员上手快,能快速见到项目效果。
方案二:采用 Next.js (React) 生态重构
转向业界更流行、生态更庞大的 React 技术栈。
技术选型 | 主要优势 |
---|---|
Next.js | 行业标杆级的 React 框架,拥有最庞大的生态系统,是构建大型、高性能应用的首选。 |
shadcn/ui | 创新的“非组件库”,提供可完全自定义的基础代码,兼具设计美学与极致灵活性。 |
最终决策:这是一个艰难的取舍。React 生态无疑在行业影响力和技术前瞻性上更有优势。但考虑到团队的技术储备和项目交付周期,我认为选择基于 Vue.js 的方案是当前阶段最务实、风险最低的选择。它能在效率、成本和最终效果之间取得最好的平衡。
我在我业余时间在开发的一套开源工具上使用的是第二套方案。
3.3 后端工程化能力提升
为了保障后端服务的高质量、高稳定性和高可维护性,我开始推动更完善的工程化体系建设。
- 编码规范与静态检查:
- 推行统一的 Go 语言编码规范。
- 在 CI/CD 流程中强制集成
go fmt
和go vet
,确保代码风格一致,提前发现潜在问题。
- 单元测试与代码覆盖率:
- 建立了统一的单元测试规范,要求核心业务逻辑的代码覆盖率必须达到 80%。
- 在团队内推广 测试驱动开发(TDD) 的理念,从源头提升代码质量。
- CI/CD 自动化:
- 搭建了从代码提交到编译、测试、镜像构建的全自动化 CI/CD 流水线。
- 在测试环境实现了自动化部署,大大提高了交付效率。
第四阶段:总结与展望
从 MVP 的单体,到 V1.0 的分布式,再到 V2.0 拥抱“任务即容器”的云原生理念,产品的架构演进,也是我团队不断应对挑战、追求技术精进的缩影。
回头看,这一路走来,收获的不仅是技术栈的更新,更是研发思想的成长:
- 从“人治”到“体系”:通过 DevOps 和标准化的工程实践,我逐步摆脱了对个人经验的过度依赖,构建起一套更可靠、更高质量的交付体系。
- 从“服务”到“任务”:通过“任务即容器”的模式,我成功解耦了业务逻辑和底层技术的复杂性,让专业的人可以更专注于专业的事。
- 从“能用”到“好用”:对前后端技术的持续打磨,让我不仅关注功能实现,更在乎系统的可维护性、扩展性以及最终的用户体验。
路还很长。未来,我会在云原生领域继续探索,比如引入服务网格(Service Mesh)来做更精细的流量治理,利用 Serverless 进一步优化资源,并结合 AI 技术,为产品注入更智能的能力。
技术之路,永无止境,持续学习,不断前行。