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

大佬们,你们公司普通业务里 mq 有做消息可靠性吗?怎么做的

  •  
  •   WillingXyz · 2021-03-24 16:56:51 +08:00 · 6703 次点击
    这是一个创建于 1340 天前的主题,其中的信息可能已经有所发展或是发生改变。
    普通业务 比如 修改内容后发送 mq 同步到 es 。
    经历的公司里都不管消息是否发送成功,失败就失败了
    32 条回复    2021-03-26 10:03:39 +08:00
    Jooooooooo
        1
    Jooooooooo  
       2021-03-24 17:02:12 +08:00
    那是很明显数据不重要, 丢一些没关系.

    一般这种如果要求一定成功会用失败补偿 /延迟校验 /双通道发送之类的方法减少数据丢失的可能.
    joApioVVx4M4X6Rf
        2
    joApioVVx4M4X6Rf  
       2021-03-24 17:04:56 +08:00
    纳尼? rabbitmq 有持久化啊
    vitoliu
        3
    vitoliu  
       2021-03-24 17:12:52 +08:00
    写入重试,打好日志。
    再写一个分时段同步 db 数据到 es 的工具。
    MQ 出问题了直接调接口补数据。
    WillingXyz
        4
    WillingXyz  
    OP
       2021-03-24 17:15:23 +08:00
    @v2exblog 是发送的时候,异步发送
    WillingXyz
        5
    WillingXyz  
    OP
       2021-03-24 17:16:57 +08:00
    @Jooooooooo 怎么衡量重不重要呢?比如一些数据同步到 es 失败就搜索不到,感觉也挺重要
    Jooooooooo
        6
    Jooooooooo  
       2021-03-24 17:21:52 +08:00
    @WillingXyz 指标定义可以用是否会产生资金损失 /是否会产生客诉 /是否会对目标用户产生负面影响等方面评估, 然后做这些容灾也是需要花钱的, ROI 就得你们自己评估了. 是丢了这些数据造成的损失大, 还是做这些容灾手段付出的成本大.
    securityCoding
        7
    securityCoding  
       2021-03-24 17:45:01 +08:00   ❤️ 5
    有做的,订单类业务 mq 丢失后续业务流程全部挂了 ,说说我用的方案吧
    rocketmq 用的比较多,拿 rocketmq 来说吧
    1. producer client 设置自动重试 3 次,注意发送重试是立即重试(循环),默认 timeOut 是 3 秒
    2. producer.send(Message msg,SendCallback sendCallback) 这种是异步发送,但是有 callback 业务可以实时感知发送结果
    2. callback 记录日志 ,并捕捉 callback 异常消息持久化至 db(拼接好完整的重试消息 body)
    3. 定时器每隔 5 秒扫描一遍待重试的消息,超过最大次数(3)则发送至告警平台人工介入
    securityCoding
        8
    securityCoding  
       2021-03-24 17:50:09 +08:00
    还有一种方案是 rmq 的事务消息 , 落库前发送一条事务消息 , rmq 会自动来询问注册的回调 listener 消息是否可以发送 , 事务状态一直是 waitting 的话 rmq 会周期性的来回调 listener ,只是时间周期是固定的
    timethinker
        9
    timethinker  
       2021-03-24 18:01:38 +08:00
    一般涉及到消息发送都基本上是异步流程了,建议在一个本地事务中将需要发送的消息写入到一个“消息发送表”内,另一个线程定时扫描这张表,然后将消息发送出去,发送完成就可以删掉或标记为已处理,发送失败记录失败次数和异常等原因。
    wmhack
        10
    wmhack  
       2021-03-24 20:25:39 +08:00
    @securityCoding 2. 后面两步,是不是可以简化成:只记录日志,日志里包含重试消息的 body,然后用钉钉告警出来呢?
    securityCoding
        11
    securityCoding  
       2021-03-24 20:35:41 +08:00
    @wmhack 可以的 , 无非是自动与手动的区别.
    我的场景是电商订单 , 尽可能的希望这种异常场景程序能自愈而不是直接人工介入
    misaka19000
        12
    misaka19000  
       2021-03-24 20:50:00 +08:00
    同步失败重做啊
    tedzhou1221
        13
    tedzhou1221  
       2021-03-24 20:50:22 +08:00
    上市公司项目,MQ 都只用来发短信、微信。服务调用基本都是同步。这样都能活得下出,消息可不可靠不影响,哈哈
    neoblackcap
        14
    neoblackcap  
       2021-03-24 23:05:40 +08:00
    mq 不能保证其可靠性,但是这消息又很重要,那么就应该实现分布式事务。
    一步出错就回滚,日志记录错误。然后慢慢修正错误提高性能
    xiang0818
        15
    xiang0818  
       2021-03-24 23:18:32 +08:00
    消息重试了解下
    Ptu2sha
        16
    Ptu2sha  
       2021-03-24 23:24:28 +08:00
    只要的肯定加确认和重试 都失败进入日志 后期处理
    xuanbg
        17
    xuanbg  
       2021-03-25 03:19:30 +08:00
    死信队列用起来
    fuxiuyin
        18
    fuxiuyin  
       2021-03-25 03:48:34 +08:00 via iPhone
    我觉得这个问题应该分成三个,一个是发送者发送到消息队列可不可靠,一个是消息队列发送给接收者可不可靠,第三个是接收者接收了之后处理的可不可靠。第二个问题不用担心,可以简单相信消息队列保证了“至少一次”。第一个问题简单解决就是发送者先写一个数据库,然后一个线程发,或者发送者弄成全异步的,通过 Task 来 track 一条消息。第三个问题就直接接收者全处理完了再给 mq 回 ack,或者接收者先写个 db 回个 ack 再慢慢处理。这个问题的重点在于不要让消息 lose track,一直能够 track 到就不怕细小的问题,因为随时可以有人来查看恢复。比如,发送流程都很好,接收者成功收到以后挂了,然后消息丢了就不好办了。mq 是一个异步和解耦组件,异步了就要在发送者和接收者都保存一些信息。同步状态下只发送端保存,接收端挂了就挂了,发送端保存了还知道接收者处理哪条消息的时候挂了,于是重来就行了。多说一句,其实点对点的发送接收做异步的话也不一定非得用 mq 啦,可以学异步 rpc 那样发 promise 。发送端发个 promise 就走,接收端把 promise 放到监听对列。发送端啥时候闲了,或者 promise 太多了,或者其他线程,去发 promise 的实际内容,接收端等哪个 promise 好了就处理好的那个。
    fuxiuyin
        19
    fuxiuyin  
       2021-03-25 03:54:58 +08:00 via iPhone
    @fuxiuyin 发出去了发现最后那个少了一点,要求接收端给回应的话,就是两边互发 promise 。发送端发个 promise,接收端收到以后回个结果的 promise,然后两边异步等 promise,balanala 。
    codingadog
        20
    codingadog  
       2021-03-25 06:39:18 +08:00 via Android
    codingadog
        21
    codingadog  
       2021-03-25 06:39:56 +08:00 via Android
    @v2exblog 不好意思,错误地 @了
    dbpe
        22
    dbpe  
       2021-03-25 09:16:28 +08:00
    说到补偿..我想知道..有没有一种可能(其实就是业务 Bug).就是 mq 端认为消息已达,但实际上数据库并没有变更...这种如何发现?(我听闻大公司有类似数据校验组?那么是不是类似这种去做的?
    supermoonie
        23
    supermoonie  
       2021-03-25 09:39:03 +08:00 via iPhone
    先入库,状态为待处理,生产者发送消息,消费者处理消息,消费者远程调用更新状态为已完成。定时任务查询未完成记录,并再次发送消息。消费者做幂等处理。
    winnie2012
        24
    winnie2012  
       2021-03-25 10:27:16 +08:00
    同步写消息表,异步读取 消息表 binlog,做消息消费。
    CoderGeek
        25
    CoderGeek  
       2021-03-25 11:39:12 +08:00
    我们都是事务消息
    brucedone
        26
    brucedone  
       2021-03-25 11:48:57 +08:00   ❤️ 2
    生产者 -> 超时重传,最大重试次数

    消息队列 -> 多点节,多副本,高可用

    消费者 -> ACK,使用唯一 ID,另外是消息幂等性
    demobin
        27
    demobin  
       2021-03-25 14:07:44 +08:00
    durable
    retry
    confirm
    mannual ack
    db
    batch job
    xxxyh
        28
    xxxyh  
       2021-03-25 15:20:30 +08:00
    26 楼加 1,生产者:重试加 ack,broker:多副本,消费者:db 持久化位移之后提交位移,如果是写 es 的话只保证不丢,不保证不重复,如果消费者的任务是写 mysql 的话,和位移的持久化放到一个事务,可以保证恰好一次
    xx6412223
        29
    xx6412223  
       2021-03-25 15:25:27 +08:00
    把 mq 当作一个服务,调用失败的话就报错呗,
    mq 有死信队列
    消费者发送 ack 。

    够用了
    bthulu
        30
    bthulu  
       2021-03-25 16:10:45 +08:00
    @xx6412223 这样不行的, 调用成功并不是代表真的成功了. 死信队列局限性很大的, 大多数网络异常, 死信队列都无能为力. 最简单的, 你先死循环发数据, 然后本地网络适配器里禁用网络再启用网络, 你会发现禁用瞬间, rabbitmq 并不能立即发现网络失效, 数据能照常发送. 要过一段时间, 通常是十几秒到几十秒, rabbitmq 才发现网络失效抛出异常. 那么这个十几秒到几十秒之间发出去的数据, rabbitmq 客户端认为发出去了, 而服务器并不会收到, 如何进死信队列?
    对 rabbitmq 来说, 只有服务端 ack 了的才算成功了, 服务 nack 的算发送失败,
    还有一种情况是, 长时间既未收到服务端 ack 信号又未收到服务端 nack 信号, 这种数据有可能发送成功了, 也有可能发送失败了.
    如果要求一条不丢, 那么在收到服务器 ack 信号时标记这条数据发出去了. 再新起一个守护线程, 定期将已发送但尚未未标记发送成功的数据重发一次.
    useben
        31
    useben  
       2021-03-25 21:54:17 +08:00
    一句话总结
    重试+重试队列+mq 持久化+ack+confirm+幂等性+打 log+定时补偿
    cheng6563
        32
    cheng6563  
       2021-03-26 10:03:39 +08:00
    发出去的同时往 db 存一个
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2684 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 03:46 · PVG 11:46 · LAX 19:46 · JFK 22:46
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.