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

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

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

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

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

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

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