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

微服务下跨服务的数据查询如何处理?

  •  1
     
  •   Canon1014 · 2021-06-23 17:55:26 +08:00 · 3100 次点击
    这是一个创建于 1260 天前的主题,其中的信息可能已经有所发展或是发生改变。

    公司最近在搞新项目( Java ),能力有限只能来请教 V 友了。

    知道微服务下服务间的数据库是隔离的,所以不能使用 join 、in 等操作,那么遇到跨服务的联查时应该怎么办?

    就例如我们的用户表只有用户服务可以查询,在一些排行榜或者记录表都会有 user_id ,前台显示需要用户的昵称,传统项目直接联查就可以了,但是微服务有点不知所措。

    原本计划是:插入数据库的同时异步的将处理好的数据写入 ES 或者 MongoDB,查询时直接就可以得到想要的数据,但是考虑到工作量暴增还可能遇到数据不一致的问题,相关资料看得少生怕走错方向。

    实在能力有限所以求各位分享一下可以落地的方案。

    26 条回复    2021-06-26 13:01:53 +08:00
    zjyl1994
        1
    zjyl1994  
       2021-06-23 17:59:23 +08:00   ❤️ 2
    通过 rpc 调用取用户服务拉昵称之类的拼装到一起,这应该有个胶水层来做,我们公司是前端用 node 做的。
    RainCats
        2
    RainCats  
       2021-06-23 18:00:51 +08:00   ❤️ 1
    通过 openfeign 之类的远程调用查一下呗
    Canon1014
        3
    Canon1014  
    OP
       2021-06-23 18:01:38 +08:00
    @zjyl1994 #1 感谢回复,胶水层是不是不做业务逻辑就只作为数据的处理呢
    Canon1014
        4
    Canon1014  
    OP
       2021-06-23 18:04:50 +08:00
    @RainCats #2 感谢回复,远程调用懂得,调用后不久得到了两份数据,并不是想要的数据格式,demo 尝试过手动去合并成一份数据,但是想了解下有没有更高级的方式
    ikas
        5
    ikas  
       2021-06-23 18:18:15 +08:00   ❤️ 1
    user_id 对应的 name 这种一般不要求试试的,都是可以加载到缓存中的,比如 redis 集群中,这样服务就直接读了.
    其他的数据,就直接到其他服务查了
    keepeye
        6
    keepeye  
       2021-06-23 18:23:29 +08:00   ❤️ 2
    不矛盾啊,先查排行榜,再按照 user_id 批量拉取用户头像昵称,前端自己组装数据即可,任何情况都不推荐 join 查询
    zjyl1994
        7
    zjyl1994  
       2021-06-23 18:32:55 +08:00   ❤️ 1
    @Canon1014 对,只负责去各个服务拉数据然后变形成前端要的样式
    Canon1014
        8
    Canon1014  
    OP
       2021-06-23 18:47:31 +08:00 via Android
    @ikas 感谢回复,所以还是需要手动合并一下
    Canon1014
        9
    Canon1014  
    OP
       2021-06-23 18:48:06 +08:00 via Android
    @keepeye 了解了,感谢
    Canon1014
        10
    Canon1014  
    OP
       2021-06-23 18:48:42 +08:00 via Android
    @zjyl1994 了解
    dqzcwxb
        11
    dqzcwxb  
       2021-06-23 18:51:51 +08:00   ❤️ 1
    @keepeye #6 任何情况不推荐 join+1
    nodododo
        12
    nodododo  
       2021-06-23 18:55:59 +08:00   ❤️ 1
    我们都是查了业务数据 带上用户 id 一次性批量查出用户数据,然后组装
    Canon1014
        13
    Canon1014  
    OP
       2021-06-23 20:38:25 +08:00
    @nodododo #12 了解了 感谢回复
    anonydmer
        14
    anonydmer  
       2021-06-24 09:26:39 +08:00   ❤️ 1
    业界各种方案都有用的;以排行榜服务和用户服务为例:

    1. 客户端自己根据 user_id 再查,这样排行榜业务不需要依赖和调用用户服务;不过这种如果追求极致的客户端体验的话可能不会用,毕竟如果数据查询多客户端查会体验差
    2. 排行榜微服务接口在接口层依赖用户服务,调用用户服务接口,封装到排行榜接口之后返回;(微服务的一大优势就是用户服务可以把相关接口优化到极致,即使服务器端同步调用性能也够)
    3. 排行榜和用户服务之上再来个胶水层,专门做数据组装,常用 nodejs 之类的做
    4. 还有一种也是微服务中常用的,冗余;比如排行榜可以把自己依赖的用户名做一份冗余存到自己数据库中;但是此时要注意和用户服务的同步问题;一种做法是不敏感的数据本地缓存定时更新;另外更标准的做法是使用消息队列来监听用户服务发布的事件做本地实时更新

    @Canon1014
    telan233
        15
    telan233  
       2021-06-24 09:41:37 +08:00   ❤️ 1
    确实微服务都是需要从不同服务去获取到数据,然后再组装到一起的。

    我司涉及到搜索的才走 ES,mysql binlog 同步延迟的问题一般都能接受,因为是商品搜索的场景 延迟 1 秒还是能接收的。

    我司就是 Java spring cloud 做的微服务,拆分很多模块(商品、订单、支付、权限、账户(财务)、用户中心),方便起见可以自己封装一个 CopyUtil,进行数据的 Copy,可以简化到处都是 vo.setXXXXX( dto.getXXXX ) 的问题。

    然后是组装数据的性能损耗,因为都已经微服务化了,所以机器的横向扩展还是很容易的。不行就部署多个服务。

    不得不说 spring 还是太吃内存了,吃机器怪兽。
    Canon1014
        16
    Canon1014  
    OP
       2021-06-24 09:54:09 +08:00
    @anonydmer #14 感谢回复,老哥有心了,讲解的很到位
    Canon1014
        17
    Canon1014  
    OP
       2021-06-24 10:01:10 +08:00
    @telan233 #15 感谢回复,大致了解了,我目前最担心的确实在数据组装的性能上
    telan233
        18
    telan233  
       2021-06-24 10:20:26 +08:00
    @Canon1014 其实还好,因为本来很多业务逻辑都靠数据库分担了( join ),这会造成数据库的压力。但是微服务的查询一般都是直接查 id (主键),包括 = id 、in ( id,id,id ) 大部分都是这种场景,所以我个人感觉数据库的压力反而没这么大了。总之 利大于弊 吧
    anonydmer
        19
    anonydmer  
       2021-06-24 10:31:00 +08:00
    @Canon1014 性能问题不大,比如用户服务完全可以把根据 id 查的接口通过一系列手段如缓存优化到极致;实际应用中排行榜服务还可以使用并行调用、本地缓存等手段进一步提升获取数据的性能
    Kyle18Tang
        20
    Kyle18Tang  
       2021-06-24 11:52:51 +08:00
    那如果需要对用户信息进行搜索怎么做比较好呢
    Canon1014
        21
    Canon1014  
    OP
       2021-06-24 12:01:40 +08:00
    @Kyle18Tang #20 我这边想的是:假设按照用户名搜索,先带着用户名的条件去用户服务查找符合的数据(叫他 A 好了),然后再查询排行榜服务( B ),排行榜服务里有 `user_id` 然后在 B 数据中查找 `user_id` 在 A 中的数据。就是感觉性能很差,必须搭配缓存
    stanjia
        22
    stanjia  
       2021-06-24 13:18:25 +08:00   ❤️ 1
    您好, Graphql
    Canon1014
        23
    Canon1014  
    OP
       2021-06-24 13:34:48 +08:00
    @stanjia #22 感谢回复,有看到类似的文章正在研究
    xuanbg
        24
    xuanbg  
       2021-06-24 18:57:03 +08:00
    跨服务不联查,只能正常批量查。需要联查不要拆数据库。
    keppelfei
        25
    keppelfei  
       2021-06-25 09:57:35 +08:00
    按用户名搜索一般会走两步,第一步放在客户端,比方说搜索张三。要支持模糊搜索,输入个三,此时调用用户模块服务,通过模糊查询返回给客户端用户信息,包括用户名字、id 。此时通过 id 精准查询排行榜服务。

    当然如果能做用户信息缓存到 redis 那就没必要这么麻烦了。
    mghio
        26
    mghio  
       2021-06-26 13:01:53 +08:00
    上层应该有个聚合服务的包一下数据给到前端
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3182 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 13:27 · PVG 21:27 · LAX 05:27 · JFK 08:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.