微服务之间,如何处理常量、DTO 冗余问题?

49 天前
 justdoit123
我们的微服务(都是 python3),每个服务单独一个 repo 。在写一些跨服务的代码的时候,会遇到常量代码共享的问题。


比如,某个实体某字段的 flag 。这样的常量,在本服务的代码里,肯定是定义了一堆这个字段的 flag 。但是,到了另一个服务的时候,没有这些定义。以往都是在别的服务就地再写一遍。


我感觉这种做法实在是很不方便,而且很脏。

我的想法是,应该把这些没有什么逻辑的“常量”代码(不限于常量,还有各种数据封装的 class )放在一个 repo 里,单独发包,让其它服务引用。至于是每个服务单独有一个常量库,还是所有服务共享一个常量库,则可以视情况而定。

想请教各位,这种做法如何?以及有没有更好的实践。感谢!
3975 次点击
所在节点    程序员
29 条回复
kuanat
48 天前
如果是同一个语言的微服务,最起码还可以直接引入代码。如果是不同语言的项目混用,那几乎就只有 dsl 代码生成这一条路了。

抽象出来 common 包存放数据结构之类的定义,这个思路是对的。我大概几年前也经历过类似改造,尽管项目本身不大,但这个过程挺痛苦的,因为这个改造看的其实是自动化的水平。

我印象当时选定的方案是 git submodules ,因为这个功能在之前的工作流中几乎用不到,还专门开会做团队培训……然后是几个人花了几天抽象了一个公共数据结构定义,写了个 common 包,准备一个一个微服务重构。

这个过程中发现的各种不一致的 bug 就不提了,最大的障碍是没人敢直接用新实现替代旧的版本,尽管初期改的几个包都是挑的代码少的软柿子。而且 submodules 方案也增加了开发人员的心智负担,因为一般的特性分支工作流,需要经常在维护旧代码和开发新功能上来回切换,用 submodules 就要注意每个分支和 common 依赖版本的对应。最后是自动化运维的部门出了大力,在生产环境做了个流量镜像,复制了一部分请求到新版本部署的测试服务器上,然后看执行结果和原版是否一致。

在这之后又增加了一个人为规定,就是所有项目 repo 都必须包含构建脚本,其实就是几个 hooks 检查 submodules 是否更新或者版本对应正确。因为我们用的是特性分支工作流,只要核心的 master/dev/staging 几个分支提前做好与 common 分支的对应(技术上是对应到 commit ),common 的更新就可以通过特性分支简单合并到每个项目中,实现由上至下的传播,开发人员只要知道在当前项目的哪个分支上工作即可,不需要关心依赖的手动更新。

这样改完了效果还是挺明显的,没有各种重复、不一致的定义,ide 补全也可用。只是增加管理成本,特别是负责 common 维护的。因为基础数据结构的改变,可能影响 API ,还可能影响 ABI ,即便是结构体增加一个字段,都有可能不兼容。同时 common 的改动要伴随所有微服务模块的改动,测试一定要跟得上才行。

至于常量的部分,我认为需要根据常量本身来区分。如果是那种界面上的文字肯定是放到直接使用的包比较好,剩下大部分常量,比如服务器地址这些,我认为还是在环境变量中设置比较好。体现到项目中就是 dotenv 这种,环境不同设置也不同。这个方案需要额外处理两个细节,一个是如何集中管理或者持久化,二是一些类似密钥的不适合用明文的要如何处理。

对于单语言项目,简化处理可以用公共 constant 包,对于多语言项目来说,一般是集中定义,然后通过 sed 之类的工具在源码级别上做替换。
mightofcode
48 天前
人生苦短 没什么好办法
sivl6p
48 天前
我现在就在服务转单体,计划减少 1/3 人员
xuanbg
48 天前
抽象出来 common 包看着挺好,但实际并不美。最主要的问题是没人用,嫌麻烦。
qxmqh
48 天前
@justdoit123 这就是技术债,很多公司客户数量还没有服务多,就乱搞微服务,前几年都这样,现在都得重新搞单体。
pengtao2001
48 天前
https://breeze1203.github.io/2025/09/15/%E8%87%AA%E5%BB%BA%E4%BB%93%E5%BA%93nexus/ 刚好遇到包混乱问题,我觉得楼主也可以考虑这种
justdoit123
48 天前
@kuanat 非常感谢老哥的经历分享!

我们的 common 库(基本等于工具库)也有类似你说的不一致问题。

1. 改动不兼容。依赖的地方迁移不干净。后来要求,尽量不做不兼容改动。实在要兼容,旧的别动,写个新的。扩展到本主题的常量、DTO 代码,也是这样的道理。不过这种事情,就怕人偷懒。一偷懒,埋下运行时的雷。

2. 这个 common 库,在各个业务 repo 里是以 git tag 的形式进行版本依赖声明的。类似你说的 ”对应的 commit“。但是因为各种“时过境迁”的原因,大家不得不共用一个测试环境。测试环境的代码,经常是开发分支合并在一起的。还有很多细节没必要展开来说。 总之最终导致,这个 common 库的 git tag 不对,在测试环境未必会暴露出来。基建支撑不足的弊端就体现在这里了。现在只能用千叮咛万嘱咐的方式,告诉大家。改了 common ,第一时间去升级依赖。

后续把常量代码也迁移到 common 库后,这样的问题依然会发生。不过,总比现在会好一些。现在的维护心智负担更大。
justdoit123
48 天前
@qxmqh 我们现在是有业务开发的时候。尽量做一些清理工作。太多太多功能了,其实可以不要的。这些僵尸功能不清除,要合并单体也是够麻烦的。

我们核心的功能是个人数据同步、社区、会员三个业务模块。但是却附着大量产品经理们的“快速实验功能”。
whoosy
47 天前
再拆出来一个 common ,后果就是越拆越大

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1161025

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX