gibber
V2EX  ›  Java

请教下微服务间大批量数据获取一般是如何处理的

  •  
  •   gibber · Oct 17, 2024 · 9120 views
    This topic created in 750 days ago, the information mentioned may be changed or developed.
    比如 a 服务需要从 b 服务获取几十万的数据处理后生成自己的业务数据,如果 b 服务直接从数据库中一次性查出来返回,对内存的压力就很大。
    现在的方案是使用分页,每次最多 1 万条记录,获取一批处理一批,把整个业务处理的时间拉长了。
    想知道还有没有更好的办法
    46 replies  •  2024-11-06 16:57:26 +08:00
    ZGame
    ZGame
    Oct 17, 2024
    1
    1.内存压力大?一个作业才几十万数据。。 如果怕影响 a 库业务性能,直接给 a 库做一个从库,从从库里拉数据。
    2.走 cdc 那种从日志里读取,这种时效性会好点。我是感觉没必要
    csys
    csys
    Oct 17, 2024 via Android
    2
    1.
    b 服务把数据保存成文件
    a 服务下载文件后进行处理

    2. kafka/cdc
    securityCoding
    securityCoding
    Oct 17, 2024
    3
    单独落离线表,明令禁止直接从线上业务表捞数据
    ymz
    ymz
    Oct 17, 2024
    4
    kafka
    m2276699
    m2276699
    Oct 17, 2024❤️1
    5
    数据源之间冗余
    xiaohupro
    xiaohupro
    Oct 17, 2024
    6
    时间线拉长应该是由于同步导致的吧,查一万处理一万。可以把查处来的数据立马丢给 Kafka 或者 Rabbit MQ 这类消息队列,A 服务监听队列,只要有数据就一直处理,这样应该会分批同步处理快一些。
    sagaxu
    sagaxu
    Oct 17, 2024
    7
    这是两个步骤

    1. b 服务从 db 获取几十万条数据
    2. a 服务从 b 服务获取完整数据

    第二个步骤在分页之后,从 1 次 rpc 变成几十次,内网 rpc 的开销是毫秒级的,几十次 rpc 增加几十毫秒,不会显著拉长处理时间。

    那问题就出在第一步,db 端分页之后,几十次小量查询,开销远大于单次全量。这种情况就不建议分页,而是分批,b 服务一次查询分批读取,写入文件或者消息队列等暂存设施,返回给 a 的是数据的指向,a 自己再分批读取
    ymmud
    ymmud
    Oct 17, 2024
    8
    才几十万条,服务之间类似于流式处理直接拉过去就行了
    SmartTom
    SmartTom
    Oct 17, 2024
    9
    a 服务直接做多数据源直连 b 服务数据库/doge
    povsister
    povsister
    Oct 17, 2024 via iPhone
    10
    你这种 case 如果数据量持续上升,应该用 spark 这种离线作业,或者压根不应该拆分服务。
    Wh1t3zZ
    Wh1t3zZ
    Oct 17, 2024
    11
    流式数据处理
    Plutooo
    Plutooo
    Oct 17, 2024
    12
    把 B 服务当成直接从数据库查不也是存在一样的问题么,还是说担心 B 服务的内存占用
    landerwong99
    landerwong99
    Oct 17, 2024
    13
    要么就离线近源处理,来个服务直接调 B 库的只读库,
    要么就流式处理,使用 kafka 之类的。
    ZZ74
    ZZ74
    Oct 17, 2024
    14
    搞那么麻烦干啥,导出文件写入共享目录,调用接口通知 喂 数据我放到 xx 目录下的 x 文件里了
    lifei6671
    lifei6671
    Oct 17, 2024
    15
    一般情况下是通过下面方式实现的:
    1 、建立只读线下备库,通过从库的方式从线上库实时同步数据,不能用于线上系统读,只能用于线下业务大批量读。
    2 、建立只读从库,和主库实时同步,只能进行线上系统只读。
    3 、通过 binlog 实时建立分析宽表,一般用来汇总各个业务方数据,建立大宽表,支持线下业务分析已经大批量查询等。
    kaf
    kaf
    Oct 17, 2024
    16
    流格式数据
    8355
    8355
    Oct 17, 2024
    17
    有 id 能排序的话 传起始 id 过来就行了 where id > xx limit 10000 order by id asc
    8355
    8355
    Oct 17, 2024
    18
    其实数据没这么大,我的的业务天天导入 300m 的 csv ,200w 左右。
    只要不是一两百个字段带 text 的宽表数据 不会特别大的。
    fengpan567
    fengpan567
    Oct 17, 2024
    19
    没条件搞数据同步服务的,直接让对方生成一个 csv 上传到 oss ,你每天去捞当天的文件同步就行了
    print1024
    print1024
    Oct 17, 2024
    20
    如果数据库 id 是有序的话可以先排序,然后切分数据,如 1000 条一次,多线程处理,也就这样了,用中间件其实没太大必要
    cccssss
    cccssss
    Oct 17, 2024
    21
    直接读 b 库
    不让读的话只能说又想马儿跑又不给马儿吃草
    InkAndBanner
    InkAndBanner
    Oct 17, 2024
    22
    oss or 离线数仓,如果在线去拉的话 就算可行,ab 服务的 io 会不会被占满导致其他接口、服务不可用?
    bthulu
    bthulu
    Oct 17, 2024
    23
    获取一批处理一批, 怎么就把业务处理时间拉长了?
    你一次获取, 不还是要处理这么多?
    newaccount
    newaccount
    Oct 17, 2024
    24
    要么时间换空间,要么空间换时间
    你这又嫌内存占用大又嫌处理时间长的
    就算让 a 直接读 b 库,那内存占用无非是从 b 服务器转移到 a 服务器
    masterclock
    masterclock
    Oct 17, 2024
    25
    看看能不能让 a 不依赖 b ,数据分别进 a 、b 服务
    如果 a 强依赖 b ,那就别微服务了,把 a 整合进 b ,或者 a 的这一部分功能整合到 b
    kchenzhi
    kchenzhi
    Oct 17, 2024
    26
    这事我有经验。
    1 、不要在 responseBody 里返回, 那样内存一定会爆。
    2 、不要分页查询,两个原因:①不同分页的查询不在一个事务中,会有数据一致性的问题。②当查询到靠后的分页时,耗时直线上升,性能太差。
    kchenzhi
    kchenzhi
    Oct 17, 2024
    27
    3 、如果能让 a 直接读库,那是一种解决方案。但如果 b 里有些处理逻辑比较复杂,那你得在 a 中重新实现一遍,重复工作量且代码冗余,不合适。

    我们最终采取的方案是:访问数据源时使用游标,一行行读取数据后,通过 http outputstream ,用流式返回。
    R4rvZ6agNVWr56V0
    R4rvZ6agNVWr56V0
    Oct 17, 2024
    28
    时间换空间:小批次分批执行
    空间换时间:增加内存,大批量执行
    中间方案:放在共享存储(例如 nfs ),mmap 读文件,增加消费者进程消费
    clf
    clf
    Oct 17, 2024
    29
    数据表做数据冗余吧。
    gibber
    gibber
    OP
    Oct 17, 2024
    30
    @xiaohupro 就是一次查询改为多次查询后比较耗时,不太想引入额外的中间件来处理
    gibber
    gibber
    OP
    Oct 17, 2024
    31
    @kchenzhi a 服务本地数据源的话是会使用流式查询的,倒是不清楚微服务调用也能使用流式处理的方式,感觉可以参考,谢谢
    molicloud
    molicloud
    Oct 17, 2024
    32
    直接在 b 服务处理数据,再通知或调用 a 服务
    vacuitym
    vacuitym
    Oct 17, 2024
    33
    定时生成文件给下载地址(这感觉很像对账单)
    asAnotherJack
    asAnotherJack
    Oct 17, 2024
    34
    @kchenzhi #26 `当查询到靠后的分页时,耗时直线上升,性能太差。`
    盲猜是不是用的 limit offset 做的分页
    gibber
    gibber
    OP
    Oct 17, 2024
    35
    @molicloud b 服务只负责从数据库查询数据,不处理具体业务
    notwaste
    notwaste
    Oct 17, 2024
    36
    b 服务查出来往 kafka 里面丢,a 服务消费处理
    macttt
    macttt
    Oct 17, 2024
    37
    A 服务提交一个任务给 B 服务,B 服务收到任务后推送数据给 A 服务。两个服务之间的数据完备性检查,你可以使用类似于 TCP 传输的形式。A 服务不用管 B 服务怎么实现的,只需要接收数据就行了,B 服务则需要让 A 服务记录数据完整性的元数据。
    snickers
    snickers
    Oct 17, 2024
    38
    不建议走接口 ,ETL 转换调度
    molicloud
    molicloud
    Oct 17, 2024
    39
    @gibber #35 在新建一个 b-analysis 服务,也连和 b 相同的数据库
    siweipancc
    siweipancc
    Oct 19, 2024 via iPhone
    40
    不要分页,用游标依次写到队列里
    kchenzhi
    kchenzhi
    Oct 22, 2024
    41
    @asAnotherJack
    请问是这种方式吗:LIMIT row_count OFFSET offset
    我们就是用这种, 仍然是直线上升哦,
    每页 5000 行,翻到 1000 页后,对比起第一页的查询速度已经差了好几个数量级了。

    请问是有什么优化技巧我没用上么?
    asAnotherJack
    asAnotherJack
    Oct 22, 2024
    42
    @kchenzhi #41 用 lastId + pageSize 的方式,where id > lastId order by id limit pageSize
    kchenzhi
    kchenzhi
    Oct 23, 2024
    43
    @asAnotherJack 这个方案我们也用过, 可以是可以,但是有两个问题:
    1 、对调用方有了一些入侵。
    2 、多分页拉取的数据可能会跨事务,导致数据一致性被破坏。

    所以最后选择的是游标查询加流式传输,一次查询解决问题。
    suolong00
    suolong00
    Oct 24, 2024
    44
    没人说用消息中间件吗,b 服务器使用多线程查询几十万的数据,写到消息队列中,a 去消费就行了,可以多线程插入
    gibber
    gibber
    OP
    Oct 24, 2024
    45
    @suolong00 主要不想为这一个功能去引入一个中间件
    Plutooo
    Plutooo
    Nov 6, 2024
    46
    @kchenzhi 你好,可以请教一下 http outputstream 流式返回主要是通过什么实现吗,是 rpc 有类似的实现么
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4489 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 85ms · UTC 09:24 · PVG 17:24 · LAX 01:24 · JFK 04:24
    ♥ Do have faith in what you're doing.