是否选择Monorepo?

ops/2025/3/20 12:43:52/

最近去新的团队,看到使用Monorepo的方式管理代码。感觉好像和微服务有些冲突,但最终确实是生成一个一个的应用,好像也没影响到微服务啊。这两天又想了一下,确实是有一些冲突的。

Monorepo介绍

Monorepo 是一种项目代码管理方式,指单个仓库中管理多个项目,有助于简化代码共享、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性。Monorepo 提倡了开放、透明、共享的组织文化,这种方法已经被很多大型公司广泛使用,如 Google、Facebook 和 Microsoft 等。

Monorepo 演进

阶段一:单仓库巨石应用, 一个 Git 仓库维护着项目代码,随着迭代业务复杂度的提升,项目代码会变得越来越多,越来越复杂,大量代码构建效率也会降低,最终导致了单体巨石应用,这种代码管理方式称之为 Monolith。

阶段二:多仓库多模块应用,于是将项目拆解成多个业务模块,并在多个 Git 仓库管理,模块解耦,降低了巨石应用的复杂度,每个模块都可以独立编码、测试、发版,代码管理变得简化,构建效率也得以提升,这种代码管理方式称之为 MultiRepo。

阶段三:单仓库多模块应用,随着业务复杂度的提升,模块仓库越来越多,MultiRepo这种方式虽然从业务上解耦了,但增加了项目工程管理的难度,随着模块仓库达到一定数量级,会有几个问题:跨仓库代码难共享;分散在单仓库的模块依赖管理复杂(底层模块升级后,其他上层依赖需要及时更新,否则有问题);增加了构建耗时。于是将多个项目集成到一个仓库下,共享工程配置,同时又快捷地共享模块代码,成为趋势,这种代码管理方式称之为 MonoRepo。

在这里插入图片描述

冲突

对于公司当前的场景,使用Go语言,微服务化部署的情况下,我是建议选择Multi-repo方案的。因为Mono-repo的优势不是很明显:

  1. Go语言没什么复杂的工程配置
  2. 一般也不需要共享模块代码,功能层面可以通过rpc调用,一些通用逻辑可以维护SDK即可。而且即使用mon-repo,如何确保所有人员知道已经有这块逻辑了呢?
类型Monorepo微服务冲突表现
架构理念差异倾向于将多个项目或模块集中在一个仓库管理,在一定程度上有相对集中的架构思维,代码库是统一的整体,不同部分关联性强,变更可能影响多个模块。强调服务的独立性、自治性,每个服务有自己独立的代码库、运行环境、技术栈等,追求高内聚、低耦合,以实现快速迭代、独立部署。Monorepo 可能使微服务之间的边界模糊,服务独立性难以保证。因为都在一个仓库,不同微服务代码容易相互依赖、牵一发而动全身,违背微服务低耦合原则,增加服务间的耦合度,使微服务架构优势难以发挥。
开发与维护效率虽然集中管理便于工具建设、提升项目可见性,但仓库规模大,代码量大、结构复杂。新成员理解项目全貌和业务逻辑困难,学习成本高。而且修改一处代码,可能影响多个服务,测试和验证范围广,耗时费力。每个服务相对简单,开发人员可专注特定服务功能开发维护,新成员易上手。单个服务修改、测试和部署相对独立,效率高。在 Monorepo 管理微服务,开发过程中开发、测试和部署的效率优势可能被削弱,不同微服务开发进度和节奏受影响,开发周期变长。
技术选型灵活性仓库内所有项目使用统一开发流程、工具链和版本控制,技术选型要考虑整体兼容性和一致性,为保证整体稳定,引入新技术、框架或工具时需谨慎评估,限制技术创新和新技术引入速度。各服务可根据自身业务需求和特点自由选择合适技术栈,技术选型灵活,能快速响应业务变化和技术发展。在 Monorepo 管理微服务,微服务对新技术灵活选型的优势受限,不利于微服务根据业务特性选择最优技术方案,可能导致部分服务性能、功能实现受影响。
部署和运维复杂度由于所有服务在一个仓库,部署时需要整体考虑依赖关系、环境配置等,流程复杂。一个小改动可能需重新部署整个仓库相关服务,运维难度大,故障排查困难,定位问题耗时久。各服务独立部署,可根据自身状态和需求灵活部署,一个服务故障不影响其他服务,运维相对简单,故障排查定位范围小。Monorepo 的部署和运维方式与微服务独立、灵活的部署运维理念冲突,导致在 Monorepo 中部署和运维微服务时,复杂度增加,难以实现微服务快速部署、高效运维的优势。

一旦选择Monorepo,后续拆分就比较困难了。

  1. 如果你的服务引用了别的服务的功能,后续别人升级了,你怎么办?需要改成RPC调用,但前提是别的团队需要提供这个接口。
  2. 如果你的服务引用了一些纯功能性函数,如stringToint,后续更新了怎么办?这种要么不再关注,要么大家抽取一个公共SDK。
  3. 如果别人引用了你的服务的功能,你升级了,你需要创建RPC接口,通知使用这个接口的团队,改为调用RPC接口。

在项目刚开始时的一些设计,不建议使用未在实战中用过的方案,可以选择保守一些方案,因为这个方案是在大家接受范围之内的。

资料

  1. 带你了解更全面的 Monorepo - 优劣、踩坑、选型

http://www.ppmy.cn/ops/167283.html

相关文章

Freeze-Omni:冻结 LLM,实现语音对话

写在前面:语音LLM 大型语言模型(LLM)的强大能力,为构建智能语音对话系统提供了无限可能。然而,将 LLM 与语音模态结合,并非易事。直接微调 LLM,容易导致灾难性遗忘,丧失其原有的知识和能力;而训练数据不足,又难以充分发挥 LLM 的潜力。 如何才能在保留 LLM 强大能力…

深入解析 C++ Vector:全面掌握 STL 核心容器的原理与高效实践

一、Vector 的核心概念与特性 Vector 是 C 标准库中最常用的动态数组容器,其底层基于连续内存存储元素,兼具数组的高效访问与动态扩容的灵活性。以下是其核心特性: 1.1 核心特性对比 特性普通数组Vector 容器内存分配静态固定动态增长访问效…

Pycharm接入DeepSeek,提升自动化脚本的写作效率

一.效果展示: 二.实施步骤: 1.DeepSeek官网创建API key: 创建成功后,会生成一个API key: 2. PyCharm工具,打开文件->设置->插件,搜索“Continue”,点击安装 3.安装完成后&…

关于前端指令

在前端开发中,指令(Directives)通常指在框架中使用的一种特殊的语法或机制,用于扩展 HTML 的功能。常见的指令主要存在于前端框架中,如 Vue.js、Angular 等。下面我们将分别介绍 Vue.js 和 Angular 中的常用指令&#…

危化品经营单位考试:心理调适与知识巩固双管齐下​

危化品经营单位考试不仅是对知识的考验,更是对心理素质的挑战。在备考过程中,我们要做到心理调适与知识巩固双管齐下。​ 备考期间,压力是不可避免的。随着考试日期的临近,很多考生会出现焦虑、紧张等情绪。这时候,心…

【计算机网络】2物理层

物理层任务:实现相邻节点之间比特(或)的传输 1.通信基础 1.1.基本概念 1.1.1.信源,信宿,信道,数据,信号 数据通信系统主要划分为信源、信道、信宿三部分。 信源:产生和发送数据的源头。 信宿:接收数据的终点。 信道:信号的传输介质。 数据和信号都有模拟或数字…

今天你学C++了吗?——二叉搜索树

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

【2025】基于Springboot + vue实现的毕业设计选题系统

项目描述 本系统包含管理员、学生、教师三个角色。 管理员角色: 用户管理:管理系统中所有用户的信息,包括添加、删除和修改用户。 配置管理:管理系统配置参数,如上传图片的路径等。 权限管理:分配和管理…