微服务之间,如何处理常量、DTO 冗余问题? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
justdoit123
V2EX    程序员

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

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


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


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

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

    想请教各位,这种做法如何?以及有没有更好的实践。感谢!
    第 1 条附言    17 天前
    微服务是既定现状,至少已经快 8 年了。要变成单体,感觉工作量太大。公司也降本了,平时业务开发已经压的比较紧。基本不太可能改变微服务的现状。
    29 条回复    2025-09-23 21:21:41 +08:00
    Maboroshii
        1
    Maboroshii  
       17 天前
    protobuf 和 grpc 呗
    kapr1k0rn
        2
    kapr1k0rn  
       17 天前
    monorepo
    qxmqh
        3
    qxmqh  
       17 天前   3
    换成单体。
    pxiphx891
        4
    pxiphx891  
       17 天前
    没写过 python ,不过 java 一直是这样的,打一个单独的包,所有人依赖这个包
    pigspy
        5
    pigspy  
       17 天前
    服务不多的情况下直接用 monorepo
    MIUIOS
        6
    MIUIOS  
       17 天前
    参考 java 暴露出 dto do vo 这些单独一个包,其他模块随便引入
    NoKey
        7
    NoKey  
       17 天前
    团队执行力强(盖的住成本)的话,搞公共包,内网搭 maven 仓,拉下来就能用,不过这需要额外的人力去维护这一套;一般的团队,重复写就重复写,要么就是相互复制,除了消耗人力,又不会怎么样
    justdoit123
        8
    justdoit123  
    OP
       17 天前
    @Maboroshii grpc 可以上。但是需要共享的代码,不局限于 protobuf 描述的数据。
    justdoit123
        9
    justdoit123  
    OP
       17 天前
    monorepo 倒是也可以。但是我感觉组员有时候写得很野,跨服务乱引用。综合来看,不太适用我们。
    justdoit123
        10
    justdoit123  
    OP
       17 天前
    综合上面的回答,可能适合的方案还是服务的“常量”代码抽成一个包。
    blackmatch
        11
    blackmatch  
       17 天前
    1.抽成一个公共包,各个服务引入调用即可。
    2.做一个配置中心服务,所有服务统一读取同一份配置,做好更新和兜底策略。好处是修改配置不用发版,在配置中心改一下就可以了。
    patrickpu
        12
    patrickpu  
       17 天前
    需要一个 common 的基础包
    iyaozhen
        13
    iyaozhen  
       17 天前
    一般是吧这些和 idl 绑定,idl (比如 pb 描述)生成这个仓库,各方来引用

    不过怎么说呢,没必要强行微服务。特别是 python 。python 4 个服务一个分 1c 。还不如一起在 4c 的机器性能好
    sampeng
        14
    sampeng  
       17 天前 via iPhone
    你这就属于,想用微服务规范和隔离开发,但又已经看到微服务最大的蛋疼。
    最好 code reviewer ,你说的问题都不是问题。monorepo 又不是想怎么写怎么写
    justdoit123
        15
    justdoit123  
    OP
       17 天前
    @iyaozhen 微服务是既定现状,前人拆分的,至少已经快 8 年了,暂时没资源去改回单体。
    Rickkkkkkk
        16
    Rickkkkkkk  
       17 天前
    common 包用起来其实没那么方便,远远不如代码里直接写一个 const 来的简单。
    justdoit123
        17
    justdoit123  
    OP
       17 天前
    @sampeng 几乎没有 code review 。

    说得难听点,现在最好的 "code review" 就是测试 + 一上生产环境就挂掉。没埋雷,半夜爆炸就不错。

    所以,我才想多引入一下非人工的花销来尽量保证稳定。比如:

    1. type hint 。有点作用。
    2. 写 DTO 而不是一个 dict 满天飞。不然回头维护的时候很慢热,记不住 key ,经常导致 KeyError 。也算有点作用。
    3. 常量共享而不是用到就“手抄”一遍,这种手抄还会抄错。


    不怕各位笑话。我们还有一个“运行时的常量共享方案”是这样的:每个服务提供一个接口返回本服务的一些常量定义,然后服务启动的时候,去请求一遍这些常量定义。 我感觉是很难用。运行时、纯动态,你写代码的时候,根本不知道自己引用的值存不存在。IDE 也无法给你补全。
    midsolo
        18
    midsolo  
       17 天前
    抽出来打一个 common 包,每个服务引入即可。

    common/
    ├── inner/
    │ ├── dto
    │ ├── vo
    │ └── ...
    ├── outer/
    │ ├── dto
    │ ├── vo
    │ └── ...
    └──
    183shl
        19
    183shl  
       17 天前 via iPhone
    我的偏好是只把用到的或可能用到的再写一遍,可以硬编码的就直接写再放个注释。费点力气但是感觉体验很好。如果复用很强的再抽到 common ,因为不喜欢跳来跳去
    justdoit123
        20
    justdoit123  
    OP
       17 天前   1
    @183shl 这个方案的阻力就在这里。

    我们其实有一个 common 库,里面放了一堆 utils 、架构 base 之类的代码。之前的 leader 强调,这里面不允许放入任何业务逻辑相关的代码。所以以前常量也没放这里。

    团队的人会觉得改这里面的代码,还要去升版本,很麻烦。

    有时候就直接在业务 repo 里,也写个 xxx utils 。


    我觉得你说的最后一句是有道理的,复用很强的再抽到 common 。这样就比较平衡。偶尔一两次的依赖,就直接抄一遍。依赖次数多了,再抽到 common 。很明显一定会被依赖很多次的,一开始就直接写 common 里。
    kuanat
        21
    kuanat  
       17 天前   1
    如果是同一个语言的微服务,最起码还可以直接引入代码。如果是不同语言的项目混用,那几乎就只有 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
        22
    mightofcode  
       17 天前
    人生苦短 没什么好办法
    sivl6p
        23
    sivl6p  
       16 天前
    我现在就在服务转单体,计划减少 1/3 人员
    xuanbg
        24
    xuanbg  
       16 天前
    抽象出来 common 包看着挺好,但实际并不美。最主要的问题是没人用,嫌麻烦。
    qxmqh
        25
    qxmqh  
       16 天前
    @justdoit123 这就是技术债,很多公司客户数量还没有服务多,就乱搞微服务,前几年都这样,现在都得重新搞单体。
    pengtao2001
        26
    pengtao2001  
       16 天前
    https://breeze1203.github.io/2025/09/15/%E8%87%AA%E5%BB%BA%E4%BB%93%E5%BA%93nexus/ 刚好遇到包混乱问题,我觉得楼主也可以考虑这种
    justdoit123
        27
    justdoit123  
    OP
       16 天前
    @kuanat 非常感谢老哥的经历分享!

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

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

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

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

    我们核心的功能是个人数据同步、社区、会员三个业务模块。但是却附着大量产品经理们的“快速实验功能”。
    whoosy
        29
    whoosy  
       16 天前
    再拆出来一个 common ,后果就是越拆越大
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1234 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 17:01 PVG 01:01 LAX 10:01 JFK 13:01
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86