V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Hanggi
V2EX  ›  程序员

目前哪种服务端架构模式最优?

  •  1
     
  •   Hanggi · 2020-04-21 17:05:26 +08:00 · 6282 次点击
    这是一个创建于 1675 天前的主题,其中的信息可能已经有所发展或是发生改变。

    传统服务端项目都是使用一种分层架构模式(这里用 MCV 举例):

    .
    ├── Model
    │   ├── Model_A
    │   ├── Model_B
    │   └── Model_C
    ├── Controller
    │   ├── Controller_A
    │   ├── Controller_B
    │   └── Controller_C
    └── View
        ├── View_A
        ├── View_B
        └── View_C
    

    这种架构方式会有很多变种,但是大体结构相似,就是相同层级的文件会放在同一目录里。

    最近,越来越多的项目使用一种以功能为边界的架构模式:

    .
    ├── A
    │   ├── Model
    │   ├── Controller
    │   └── View
    ├── B
    │   ├── Model
    │   ├── Controller
    │   └── View
    └── C
        ├── Model
        ├── Controller
        └── View
    

    有种说法说这种架构模式方便日后微服务化。

    如果主要以开发效率、维护成本、可扩展性等,这些核心需求来考虑,哪种架构模式更好更具发展性呢?

    58 条回复    2020-04-22 20:02:28 +08:00
    lhx2008
        1
    lhx2008  
       2020-04-21 17:07:45 +08:00 via Android
    有啥区别,只是文件夹不同而已。。
    hantsy
        2
    hantsy  
       2020-04-21 17:08:23 +08:00
    小项目用 1 就可以了。

    大一点的项目必须用 2 结构,不同的 Domain 分开,也方便以后拆分。
    ben1024
        3
    ben1024  
       2020-04-21 17:14:27 +08:00
    看迭代和人力交互
    1.迭代速度快,人力交互略差,扩展性略差
    2.迭代速度慢,人力交互方便,内部通信成本增加,扩展性好
    hantsy
        4
    hantsy  
       2020-04-21 17:16:29 +08:00
    1 。不同的 Domain 之前, 一些本来有 Entity 耦合的情况,使用 ContextMapping 概念,用一些 Ref 代替
    2 。Domain 之间调用切换到 Message Broker,或者 REST API 等。
    Hanggi
        5
    Hanggi  
    OP
       2020-04-21 17:19:26 +08:00
    @lhx2008
    怎么说呢,感觉主要是依赖方式不同。

    1. 的话是一种网状依赖,相互之间的依赖关系不明确。
    而 2. 会把重度依赖的放一起,轻度依赖的分开来。

    不知道这么说对不对。
    huijiewei
        6
    huijiewei  
       2020-04-21 17:19:36 +08:00
    用结构 2 吧

    小项目就打包成一个
    大项目就分开打包

    更加灵活
    gemini767
        7
    gemini767  
       2020-04-21 17:20:13 +08:00
    个人认为没啥区别,团队统一好了

    大应用拆应用
    opengps
        8
    opengps  
       2020-04-21 17:22:18 +08:00
    小系统选 1,大系统选 2,2 可以轻松的吧每一个业务板块单独拆出来
    janda
        9
    janda  
       2020-04-21 17:23:27 +08:00
    第二种挺像 微服务中这样的的了!每个都是完全独立的
    kaiser1992
        10
    kaiser1992  
       2020-04-21 17:26:14 +08:00
    DDD ?
    Hanggi
        11
    Hanggi  
    OP
       2020-04-21 17:28:52 +08:00 via iPhone
    @janda 实际操作中很难做到完全独立,比如 A 里的一个表跟 B 里的一个表有一对多的关系。那就会有一条依赖从 A 伸进 B 。
    这种情况,一般怎么处理呢,到时候要拆的时候怎么拆呢?
    index90
        12
    index90  
       2020-04-21 17:29:52 +08:00
    感觉没有区别啊
    Hanggi
        13
    Hanggi  
    OP
       2020-04-21 17:33:17 +08:00 via iPhone
    @index90 一种区别是,
    1 。开发的时候你要在多个文件夹里跳来跳去,特别是文件数量超多的时候,会很烦。
    2 。的话,所有相关联文件可能都在附近。
    rioshikelong121
        14
    rioshikelong121  
       2020-04-21 17:38:59 +08:00
    前端也是这样的吧。小项目第一种,比较大的项目第二种。
    index90
        15
    index90  
       2020-04-21 17:57:59 +08:00
    @Hanggi 所以为什么你不分成多个 repo,而要堆在一起?
    xcstream
        16
    xcstream  
       2020-04-21 17:59:55 +08:00
    混合 A 和 B 的模式
    Hanggi
        17
    Hanggi  
    OP
       2020-04-21 18:07:44 +08:00 via iPhone
    @index90 一个项目啊,比如 A 是用户模块,B 是文章模块,C 是视频模块,类似这么分,同一个项目怎么可能分在不同的 repo 呢。
    lower
        18
    lower  
       2020-04-21 18:22:13 +08:00   ❤️ 2
    把两者结合一下:D


    ├── A
    │ ├── Model
    │ │ ├──Model_A1
    │ │ ├──Model_A2
    │ │ └──Model_A3
    │ ├── Controller
    │ │ ├──Controller_A1
    │ │ ├──Controller_A2
    │ │ └──Controller_A3
    │ └── View
    │ ├──View_A1
    │ ├──View_A2
    │ └──View_A3
    ├── B
    │ ├── Model
    │ │ ├──Model_B1
    │ │ ├──Model_B2
    │ │ └──Model_B3
    │ ├── Controller
    │ │ ├──Controller_B1
    │ │ ├──Controller_B2
    │ │ └──Controller_B3
    │ └── View
    │ ├──View_B1
    │ ├──View_B2
    │ └──View_B3
    └── C
    ├── Model
    ├── Controller
    └── View
    noobsheldon
        19
    noobsheldon  
       2020-04-21 19:19:16 +08:00   ❤️ 1
    @lower 这不就是 Django 的结构吗
    Kirsk
        20
    Kirsk  
       2020-04-21 19:31:50 +08:00
    从 service 开始按模块分
    看业务有可能分两层 service
    底下就是作为基础层 model
    其实用 API 服务化的思维去做服务端我觉得比较合适
    view 已经弱化了
    这么分的理由是业务共性的东西会逐渐下沉形成比较稳定的层级或功能,service 层之上根据业务来
    huijiewei
        21
    huijiewei  
       2020-04-21 22:00:48 +08:00
    @Hanggi 项目不大就把所有模块集中到一起,项目大了考虑分离就去除依赖,使用 RPC 或者微服务
    wangyzj
        22
    wangyzj  
       2020-04-21 22:03:29 +08:00
    “服务端架构模式”??????
    wizardoz
        23
    wizardoz  
       2020-04-21 22:08:35 +08:00
    我只想说第一种很无脑
    0x49
        24
    0x49  
       2020-04-21 22:09:50 +08:00
    果断第二种
    janda
        25
    janda  
       2020-04-21 22:20:20 +08:00
    @Hanggi 这样每个项目之间进行通讯、需要一个注册中心、把多个集中在一起!这样就相当于 N 个模块、变成一个项目了!不过这样操作成本比较大、维护也比较麻烦的!大项目用这种比较好、小项目用你的 A 方法就行了
    siganushka
        26
    siganushka  
       2020-04-21 22:21:00 +08:00
    Symfony Bundles 了解一下
    mitu9527
        27
    mitu9527  
       2020-04-21 22:26:23 +08:00
    哪里有什么最优解决方案,只有最合适的解决方案。选择适合当下的方案,然后当需求变化时,改成适合新需求的方案。
    Hanggi
        28
    Hanggi  
    OP
       2020-04-21 22:38:01 +08:00
    @mitu9527 但是项目都是从小规模做起,到最后变多大往往也是无法预计的,到时候再重构不是成本更高吗?
    Samuelcc
        29
    Samuelcc  
       2020-04-21 22:49:02 +08:00 via Android
    个人喜欢第二种,通过 package private 的方式解耦各个模块,不会互相耦合,方便拆分和重构,也适合按照功能查找代码。
    mitu9527
        30
    mitu9527  
       2020-04-21 23:00:50 +08:00
    @Hanggi 就因为没办法预计,才应该选择最适合当下的。别人的也不见得适合你,就拿微服务来说吧,真正适合的公司就没多少家,服务数量都没上来就开始准备拆分,明显考虑的太早了。Keep It Simple 。
    xuanbg
        31
    xuanbg  
       2020-04-21 23:10:40 +08:00
    无脑选 2 就行。第一种非常容易写着写着就不清不楚地黏糊在一起了
    abcbuzhiming
        32
    abcbuzhiming  
       2020-04-21 23:32:56 +08:00
    @xuanbg 选 2 要面对一个预先规定功能边界问题,然而在经常变动的需求下就慢慢的这个边界就模糊了,然后你就发现照样糊在一起
    nvkou
        33
    nvkou  
       2020-04-21 23:40:05 +08:00 via Android
    后端不是已经没有 view 了吗。重点应该都在路由和业务了吧。
    wweir
        34
    wweir  
       2020-04-21 23:50:07 +08:00
    2, 不过拆分了 repo 。
    整个使的是微服务的套路
    uxstone
        35
    uxstone  
       2020-04-21 23:50:57 +08:00
    没有最优

    如果不对需求严加把控,最终都会变成💩山。
    limingjie138
        36
    limingjie138  
       2020-04-22 00:16:23 +08:00 via Android
    个人开发我选择了 1,但后来项目越堆越大,再开其他项目需要共用实体类的时候我就超级头痛,快点但蠢新建一个 project 把 enter 完整的 copy 过去。后悔当时不应该为了自己开发快选 1 。有没有大佬能救救我 1 的方案导致的实体不能多 project 共用的问题
    huijiewei
        37
    huijiewei  
       2020-04-22 00:21:13 +08:00   ❤️ 1
    @limingjie138 你这个问题,最简单地办法就是引入 RabbitMQ 独立事件机制,把关联做成事件关联
    zhuzhibin
        38
    zhuzhibin  
       2020-04-22 00:23:46 +08:00
    有区别吧 第二种是按照模块组织 最上层可以抽成通用的壳子 业务按照 modules 来组织 期望这些 module 都是独立可拆分的 这种做法比较难的就是业务解耦了 模块之间不要耦合太严重,否则没啥收益了
    imycc
        39
    imycc  
       2020-04-22 00:43:28 +08:00
    flask 的 blueprint 就是 2 这样的设计思路,每个模块之间各自处理内部的业务,在功能拆分还有迭代上会舒服一些。

    不过即使用了 2 的结构,如果在开发时候 ABC 互相引用,到时候拆微服务也拆不开。
    zclHIT
        40
    zclHIT  
       2020-04-22 01:17:32 +08:00 via iPhone
    来吧拥抱 DDD
    realpg
        41
    realpg  
       2020-04-22 01:29:17 +08:00
    抛开项目需求谈架构都是扯
    hacson
        42
    hacson  
       2020-04-22 01:36:59 +08:00 via iPhone
    我来问个题外话,楼主你这个树形结构的图是怎么生成的?有时候分享 ppt 这种图还蛮清晰明了的
    JaguarJack
        43
    JaguarJack  
       2020-04-22 08:10:05 +08:00 via iPhone
    我和楼主同样的 两个模块之间耦合数据层( Model )该怎么办?需要连表的情况下,该如何处理呢?希望求得一知半解
    Leigg
        44
    Leigg  
       2020-04-22 08:18:56 +08:00 via Android
    这个叫代码结构
    oneisall8955
        45
    oneisall8955  
       2020-04-22 08:59:36 +08:00 via Android
    毫无疑问选 B
    AngryMagikarp
        46
    AngryMagikarp  
       2020-04-22 09:05:49 +08:00
    这只是代码组织方式而已,前端客户端都可以用。

    没有完美的方式,只有最合适的方式,抛开需求谈这个没什么意义。
    edk24
        47
    edk24  
       2020-04-22 09:09:38 +08:00
    我怀疑你在说 tp3 和 tp5 哈哈哈
    Jrue0011
        48
    Jrue0011  
       2020-04-22 09:10:31 +08:00
    初期一个就行了,后期再拆分,遇到困难再想解决方案。。。
    robot1
        49
    robot1  
       2020-04-22 09:58:31 +08:00
    点链接之前脑子里闪现了分布式 无状态 高可用 一致性 ,点进来原来是代码放哪个文件夹。。。。。
    Orenoid
        50
    Orenoid  
       2020-04-22 10:00:37 +08:00
    业务划分得清楚,A 也可以重构成 B 。业务互相耦合,用 B 一样给写成 A 。
    Muyiafan
        51
    Muyiafan  
       2020-04-22 10:04:23 +08:00
    这不就是个文件目录吗? 怎么成服务器架构模式了!
    Hanggi
        52
    Hanggi  
    OP
       2020-04-22 10:41:05 +08:00
    @Muyiafan
    @robot1
    @Leigg
    @wangyzj

    好多人都在纠结为什么叫架构模式,可能翻译的不准确,但是我们平时经常说的 MVC 、微服务都是架构模式,贴个维基百科链接:
    https://zh.wikipedia.org/wiki/%E6%9E%B6%E6%9E%84%E6%A8%A1%E5%BC%8F

    当你改变你的目录结构、代码组织方式、依赖管理方式等这些细节的时候,其实你已经悄然改变了你的架构模式。
    baiyi
        53
    baiyi  
       2020-04-22 10:57:21 +08:00
    目录结构是跟着架构走的,还是得看实际需求,所以也谈不上哪种最优
    xianxiaobo
        54
    xianxiaobo  
       2020-04-22 16:09:43 +08:00
    混起来用,以 B 为主,A 为辅。
    zypy333
        55
    zypy333  
       2020-04-22 16:15:49 +08:00
    @Hanggi 单回复你那个多表关联下的模块拆分问题,我正好前阵子看过一个房产平台微服务视频,里面提了,说这种跨模块的,最好把关联表放到被依赖关系较小的那个库里,比如说用户表被很多模块依赖,那用户-房产关联表,就放到房产模块的库里
    charlie21
        56
    charlie21  
       2020-04-22 17:47:07 +08:00
    前者不就是后者的细节展开图嘛 ...
    xuanbg
        57
    xuanbg  
       2020-04-22 20:00:47 +08:00
    @abcbuzhiming 功能边界肯定要划分清楚的呀。

    我在带团队的过程中一直强调,把代码写对地方比写对代码更重要。代码写错了很快就能发现并修复问题,写错了地方则不然,当时是没问题你好我好大家好,但会让你在后面一直吃屎。。。同时也会在合并分支时产生大量的冲突。

    事实上只要在写代码之前稍微思考一下再动手,就很容易解决功能边界的问题,也就能把代码写对地方了。
    xuanbg
        58
    xuanbg  
       2020-04-22 20:02:28 +08:00
    @JaguarJack A 和 B 之外搞个 Common 就行,AB 都依赖 C
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   968 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 21:55 · PVG 05:55 · LAX 13:55 · JFK 16:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.