我不是一个大型 DevOps 人员,但我可以告诉你,我们在 CodePen 正在转向单一仓库,与拥有许多小型仓库的系统相比,它具有很多优势。 对我们来说,我的意思是。 你很可能面临着完全不同的挑战,并在你的公司得出了完全不同的结论。 🤙
在阅读了 Ben Nadel 的“为什么我一直在将微服务合并回 InVision 的单体架构”后,我一直在思考这个问题。 虽然我们的结论相似,但我可以看出他面临着一套完全不同的问题。
微服务解决技术和人员问题
一个 技术问题 是应用程序的一个方面给基础设施带来了过度的负担,这反过来很可能会导致糟糕的用户体验 (UX)。 例如,图像处理需要大量的 CPU。 如果这个 CPU 负载变得太大,它可能会开始剥夺应用程序的其他部分的处理资源。 这会影响系统延迟。 而且,如果情况变得足够糟糕,它可能会开始影响 系统可用性。
另一方面,一个 人员问题 与应用程序本身几乎无关,而与您的团队的组织方式有关。 您在应用程序的任何给定部分工作的人员越多,开发和部署就会变得越慢、越容易出错。 例如,如果您有 30 名工程师都在争夺同一个服务的“持续部署”(CD),您将获得大量的排队; 这意味着,许多工程师 原本可以交付产品 实际上是在等待轮到他们部署。
单一仓库的优势(对我们而言)
- 一枚戒指统治所有。 你
git pull
一个 仓库,你就可以 100% 与其他人保持同步,并拥有完成开发环境所需的一切。 - 没有流浪狗。 在 GitHub 上,没有关于哪里是行动发生的混淆。 你针对单一仓库进行拉取请求。 你在单一仓库上创建问题。 这避免了散乱的活动,这些活动会丢失。
- 齐心协力。 你可以共享代码。 这对于在代码库中的任何地方共享实用程序或组件特别有用。 我们尝试过将共享的组件发布到 npm 以供其他仓库使用,但与将代码集中在一个地方相比,这种工作流程很笨拙。
- 共同成长。 不会有陈旧的被遗忘的仓库,因为它只有一个。 对于我们的小团队来说,拥有几十个仓库意味着其中一些仓库拥有陈旧的过时依赖项、古老的 Node 版本、与其他仓库不一致的 linting 和格式化规则等。
单一仓库的缺点(对我们而言)
- 部署棘手。 我认为我们最初将仓库拆分的根本原因是,这些仓库中的代码需要放到独特的位置。 它们可能代表了某个服务器上的单个 Lambda 或单个服务。 单独的仓库意味着更容易连接到该服务器/服务特有的内容,例如 CI/CD。
是的,我知道这很有争议。
我实际上并不那么在意。 我不会像空气炸锅爱好者和 CrossFit 狂热者那样对这件事太过执着。 这是 Matt Klein 关于 反对 单一仓库的 完整论据。
我只是想说:这对我们来说已经明显有用。 我可以看出其他公司的情况会有所不同。 我可以看出,与承包商合作的公司可能希望将他们的访问权限限制在整个单一仓库以外。 我可以看出 Git 仓库可能会变得笨拙且庞大。 这些目前对我们来说不是 CodePen 的问题,因此单一仓库的优势胜出。
您指出的通过单一仓库获得的利益差异真的很有趣。 我已经将单一仓库用作独立开发人员 3 年多了,我再也不想回到以前了。 对我来说,主要优势是我能够启动新项目的速度。 我有很多想法,但我更喜欢一种不断演变的非常具体的流程,因此每次都设置它,并且质量工程脱节,这对于返回项目来说是一场噩梦。
正如您所提到的,不同类型的项目可能是最难解决的问题。 当我开始使用单一仓库时,我最终编写了自己的 CI/CD 工具,以了解基于结构的文件夹是哪种类型的项目,并根据该结构以不同的方式构建和部署它。 以及了解每个项目在依赖项方面的相互连接方式。 它使用插件系统,因此当我想要涵盖一种新类型的项目时,我可以为它编写一个插件。
使用单一仓库的体验非常棒,在快速创建项目,尤其是在重构方面获得了巨大的收益。 我认为我再也不会回到以前了。 当我更改一个作为另一个项目依赖项的单个模块时,我的工具会注意到这一点,然后自动部署每个模块,这真是太棒了。 它使重构不再那么令人恐惧,因为我永远不需要知道会受到影响的是什么。 关键是要保持良好的测试实践。 我一直在改进这方面。
这是一篇很棒的读物,并提供了独特的视角,尤其是在其他俄勒冈州人那里。
我真的很喜欢使用微服务解决技术问题与使用微服务解决人员问题之间的区别。 我个人认为使用微服务来解决人员问题是最佳路径,而使用微服务来解决技术问题更多的是边缘情况。 但我感觉大多数开发人员的体验与之相反。
单一仓库对我们也很有帮助,一切都变得简单快捷。
我们还通过在构建过程中为每个微服务创建单独的二进制目录,然后使用部署脚本在 CD 期间进行 n 次部署而不是 1 次部署来解决了部署问题。
我很好奇为什么您没有提到依赖项版本控制。 这通常被吹捧为单一仓库的主要优势:无需管理版本(提升版本、更新依赖项等)。 你们在这方面有任何变化吗?
感觉这有时会导致痛苦。 例如,为了在子项目之间共享内容,我们使用了 Lerna。 但它会导致依赖项发生奇怪的冲突。 就像设计系统库中的一个 React 组件使用某个版本的 React,然后 Next.js 中的子项目使用另一个版本的 React,而很难追踪它。 Yarn Workspaces 解决了一些问题。 但总的来说,我不得不说,在一个仓库中执行版本提升和更新确实很方便。