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

微服务下 服务拆分后 查询问题

  •  
  •   glacial · 2020-10-05 23:12:12 +08:00 · 6110 次点击
    这是一个创建于 1270 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如我有一个用户服务, 一个订单服务.

    当我查询订单列表的时候要带出 创建订单的用户名 但是我只有用户的 id, 这个时候就需要转换了。

    想了一下有两个办法

    1.直接远程调用户服务接口 一个一个的转换 但是这样效率也太低了

    2.还是远程调用户服务接口,不同的是传一批要转换的 id ,这样只用调一次就够了, 不过在大数据量下就不太好了

    有没有好的解决办法.

    还有一个问题 当我想跟据 用户名 模糊查询 相关订单的时候 好像处理起来好麻烦, 本来一条 sql 搞定的事.

    42 条回复    2020-10-08 18:31:32 +08:00
    sagaxu
        1
    sagaxu  
       2020-10-05 23:22:00 +08:00 via Android
    冗余
    FreeEx
        2
    FreeEx  
       2020-10-05 23:22:14 +08:00 via iPhone
    网关缓存用户 id 和用户名称,返回的时候修改原先的结构体加上用户名。
    chenqh
        3
    chenqh  
       2020-10-05 23:22:35 +08:00
    我估计下面会有人推荐用专门的东西来查询这种 sql join 的操作
    qq960826
        4
    qq960826  
       2020-10-05 23:38:24 +08:00
    看情况,可以两者都提供,
    w4ngzhen
        5
    w4ngzhen  
       2020-10-06 00:25:55 +08:00 via iPhone
    根据用户名模糊查询,我觉得可以有一个用户服务接口,根据用户名模糊查询得到一批满足条件的用户 id,然后拿着这批 userIds 去订单服务查 where user_id in 的。事实上,无论你的查询条件入口有多么的复杂,你总是可以将这些条件最终转换为你订单表中的字段的。当然这样的缺点是与数据库的通讯会增多,但是你的接口能够更加纯粹。
    w4ngzhen
        6
    w4ngzhen  
       2020-10-06 00:29:21 +08:00 via iPhone
    接上,这样做还有一个好处是,如果某天你的查询条件增加了比如要根据用户的等级巴拉巴拉之类的来查询。那么你需要做的只是根据用户等级来得到 userIds,然后同上处理。你的 sql 不会有任何修改。
    lihongming
        7
    lihongming  
       2020-10-06 07:59:57 +08:00 via iPhone
    个人认为,微服务是天然为云服务而生的。在云时代,一切都可以无限横向扩展,以前的很多优化思路都不再适用甚至完全相反了。

    具体到楼主的例子,比如你获取了一个 1w 条记录订单列表,需要获取每个订单的用户信息,那你就发起 1w 个并发请求到用户信息服务里去查不就完了吗?

    以前我们 join 完了再返回数据是因为数据库 IO 是性能瓶颈,所以要减少查询请求次数。但当你有 1w 台服务器同时为你服务,每台服务器只查一条数据的时候,这还是瓶颈吗?

    当然,超大型服务可能还是要考虑服务器数量限制问题,毕竟服务器不是真的无限。但对一般的互联网企业来说,云平台的服务器跟无限的差不多。而且你只需为使用的时间付费,1 台服务器用 1w 秒与 1w 台服务器用 1 秒的价格是一样的。
    dongisking
        8
    dongisking  
       2020-10-06 08:06:26 +08:00 via Android
    @lihongming 这 1w 次请求里耗时挺久的吧?
    lihongming
        9
    lihongming  
       2020-10-06 08:20:37 +08:00 via iPhone
    @dongisking 没具体测试过,但我一直这么用云,主观感觉速度还是很快的,页面都是秒开。

    而且用户再多也是那么快,反正是横向扩展的,用户多少与我无关。无需考虑这些问题可以有效减少开发时间。

    当然实际应用不会有 1w 个并发,一般也就几十个。我说 1w 的例子是为了让事情变得更明显,传统思路是时候改变一下了。
    hocgin
        10
    hocgin  
       2020-10-06 08:28:33 +08:00 via iPhone
    如果是根据 id 查名称之类的话,可以考虑一下我这个做法。https://github.com/hocgin/spring-boot-starters-project/tree/master/spring-boot-named
    lpts007
        12
    lpts007  
       2020-10-06 08:51:27 +08:00
    @lihongming 你们多少台服务器啊
    reus
        13
    reus  
       2020-10-06 08:57:21 +08:00 via Android   ❤️ 1
    @lihongming 你的钱也能无线横向扩展吗?说得好像用云不要钱似的。带宽,内存,都要真金白银换的,价格也不是线性变化的,尤其是大带宽,贵得很
    est
        14
    est  
       2020-10-06 09:09:29 +08:00 via Android   ❤️ 2
    拆服务的颗粒度应该以部门或者业务组为单位。除此之外都是瞎 jb 拆。订单和用户分别属于两个领导管吗?是的话就按他们职能拆,不是就别拆了,都一个人一个部门了,你那个体量还不值得去拆。
    blessyou
        15
    blessyou  
       2020-10-06 09:20:52 +08:00
    还是 2 吧,当你有多个用户服务在不同地域的服务器上部署,1 会慢的离谱,网络耗时贼多。
    winnie2012
        16
    winnie2012  
       2020-10-06 09:26:51 +08:00
    用户名最简单了,不会变,就冗余到订单表,这样查询就一条 SQL 。
    要是昵称什么的,昵称修改时需要更新订单表的昵称数据。
    glacial
        17
    glacial  
    OP
       2020-10-06 09:59:05 +08:00
    @winnie2012 冗余就会涉及到更新, 当我很多个业务表都要关联用户表的时候 , 用户名变更会 产生更新很多个业务表的需求,一但数据量变大 这种更新也会是一种灾难
    glacial
        18
    glacial  
    OP
       2020-10-06 10:10:46 +08:00
    @hocgin aop 加注解
    liuzhaowei55
        19
    liuzhaowei55  
       2020-10-06 10:19:31 +08:00 via Android
    @reus 那想过没,可能是你的系统还不到需要使用微服务的时候。
    liuzhaowei55
        20
    liuzhaowei55  
       2020-10-06 10:25:31 +08:00 via Android
    1,2 两个方案完全不冲突,如果是单次数据量大更应该使用方案 2,如果超大不只你这个模块需要处理这么大数据,其他模块也是存在一样的压力,不用担心很多的,系统的升级都是从实际生产中慢慢演变的,不是一蹴而就的,能直接拿来参考的模型不多
    qiukun
        21
    qiukun  
       2020-10-06 10:34:22 +08:00 via iPhone
    @est 中西结合
    simonlu9
        22
    simonlu9  
       2020-10-06 11:36:10 +08:00
    只能说冗余比较好,之前碰到过一个上传 excel 校验,不知道要调多少 rpc,最后不得不折服丢掉 rpc 改消息队列通知
    wangyzj
        23
    wangyzj  
       2020-10-06 15:03:28 +08:00
    方案 2, 你一次这种查询订单也不会太多
    des
        24
    des  
       2020-10-06 15:27:02 +08:00
    冗余的话,假如用户修改用户名,下次要带上年龄 /或者其他的怎么搞
    Leigg
        25
    Leigg  
       2020-10-06 15:50:34 +08:00 via Android
    当然是第二种了,批量查询,你再多不可能一次性几万个,分页是常用手段。
    hpeng
        26
    hpeng  
       2020-10-06 15:57:51 +08:00 via iPhone
    批量查,接口按需分页,内存组装数据。
    kur0d3s
        27
    kur0d3s  
       2020-10-06 16:05:51 +08:00
    1. 回调事件 把冗余存在本服务内
    2. 搜索引擎 es 之类的 做数据聚合
    latteczy
        28
    latteczy  
       2020-10-06 16:09:03 +08:00
    > 还有一个问题 当我想跟据 用户名 模糊查询 相关订单的时候 好像处理起来好麻烦, 本来一条 sql 搞定的事.
    用户名是会变的,只能实时去查吧。
    xuanbg
        29
    xuanbg  
       2020-10-06 16:29:56 +08:00
    订单列表里面的用户名就是个伪需求。业务部门关心具体某个订单是阿猫还是阿狗?

    好吧,真有这种需求的话,聚合查询才是正道。
    menyakun
        30
    menyakun  
       2020-10-06 17:04:44 +08:00
    从微服务的角度,用户管理和订单管理两个模块分开来的确蛮合理的。
    Jooooooooo
        31
    Jooooooooo  
       2020-10-06 17:09:26 +08:00
    api 层聚合
    winglight2016
        32
    winglight2016  
       2020-10-06 17:38:17 +08:00
    这个问题类似于 mongodb 这种 nosql 数据库的 document 设计。凡是选择冗余方案都要考虑更新问题,反之就要考虑关联查询的问题。

    仅仅考虑 lz 提出的 case,个人建议用户 id 可以作为数组参数一次性请求当前页面所有用户的用户名,或者使用具有唯一性的名称( tb 订单似乎就是这么搞的)
    lihongming
        33
    lihongming  
       2020-10-06 23:30:53 +08:00 via iPhone
    @lpts007 具体不知道,我用 AWS,理论上至少有几万台吧
    lihongming
        34
    lihongming  
       2020-10-06 23:32:59 +08:00 via iPhone
    @reus 带宽什么的仍然是传统思路,serverless 才是真正的云思路。了解一下,你会爱上它的。
    clf
        35
    clf  
       2020-10-07 01:42:14 +08:00 via Android
    1 和 2 皆可。
    个人认为这样的场景不存在短时间内进行大量数据处理的需求。(可能是我没遇到)
    用户名等字段在系统里是作为一个属性存储的,而不是唯一 id 。属性字段往往是给人看的,那么必然不会出现单页面需要显示大量数据的情况。
    另外,属性字段可能被用于数据分析,此时数据量是十分巨大的,但数据分析不需要和前端显示一样需要在短时间内完成数据转换。完全有充足的时间进行多次调用。
    MarioLuo
        36
    MarioLuo  
       2020-10-07 03:50:49 +08:00 via Android
    第二种方式批量获取用户信息,第一种和循环里执行 sql 没有区别应当禁止

    用户名模糊查询问题, 用户名变动少可直接冗余,考虑到匹配用户相当多时,不建议先查模糊用户服务的到大量用户 id 。

    如果后续订单查询中增加了大量用户相关的查询条件,可考虑使用 es 等数据聚合仓库,冗余了多个服务的数据
    xx6412223
        37
    xx6412223  
       2020-10-07 09:48:57 +08:00
    有些楼层论调真是清奇,好像无限只要 hardware 够就能解决所有问题一样。。。
    lihongming
        38
    lihongming  
       2020-10-08 00:22:51 +08:00 via iPhone
    @xx6412223 我就是你说的有些楼层。如果我不小心伤到了你的经验,那我只能说声抱歉,然后继续用我的“无限”方案了。毕竟我说的是实战经验,不能因为你不高兴就把系统推了重做不是吗?

    我的观点总结起来就一句话——Microservice 依赖于 Serverless 。

    不过系统设计最核心的一句话是“一切设计都是妥协”,没有什么绝对正确的方案,就看你的案例适不适合。所以我希望你的观点是在充分了解 Serverless 的原理及其计费方式的情况下产生的,那样至少你明白我方案的利弊,否则咱俩的对话就毫无意义了
    MarioLuo
        39
    MarioLuo  
       2020-10-08 01:25:52 +08:00 via Android
    @lihongming 不赞成楼主观点,列表页或者导出上万条数据,假设单个 10ms 那么顺序调用总 10s 吧,如果并发执行那不是更复杂了吗,还不如批量组装。总的来说能简单的掉用一次,没有必要调用多次
    lihongming
        40
    lihongming  
       2020-10-08 07:36:35 +08:00
    @MarioLuo 唉!我觉得我的中文确实退化了,解释了好几遍都没说清楚我的观点。现在完整说一遍吧。

    首先呢,楼主是确定使用了微服务架构,这是基本前提。

    其次呢,我认为用户和订单分在两个服务里是合理设计,至少是一种常见设计。

    有了以上两个前提,我才说,这种场景应该使用 Serverless 云计算。因为云计算可以无限横向扩展,让成千上万台服务器同时为你服务,从而抵消微服务带来的性能损耗,并且不增加服务器成本。

    大体就是这样吧,如果还有没说清楚的欢迎帮我细化。

    微服务的好处是解耦,并不是追求性能。

    Serverless 的好处除了无限横向扩展,还可以降低开发难度,因为程序员基本不用考虑性能瓶颈了。
    lower
        41
    lower  
       2020-10-08 14:41:53 +08:00
    赞同 #27 楼,都微服务了,搜索引擎服务 往上加啊
    iyangyuan
        42
    iyangyuan  
       2020-10-08 18:31:32 +08:00 via iPhone
    一般有分页,就算是批量,数据量也不会太多,去掉重复的没多少,不会一页显示几万条吧?实在不行还可以压缩数据
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1186 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 18:26 · PVG 02:26 · LAX 11:26 · JFK 14:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.