目前的实现方式:
参考支付宝的异步通知,每个订单的异步通知实行分频率发送:15s 3m 10m 30m 30m 1h 2h 6h 15h
脚本每秒请求数据库获取到时间需要发送的通知,返回成功则结束,失败则按下一个时间写入数据库,等待发送
目前的方式虽然实现了但是 1 、每秒请求有点儿浪费资源; 2 、通知方式不稳定; 3 、无法承受大数据量等等
现在想改为使用队列的方式实现,但是不知道如何实现通知返回失败,往队列里写下一次通知?
方案 1 :到下一次发送通知时间时,写入队列,队列实时处理,但不知道该如何实现到指定时间写队列
方案 2 :队列里延迟,也找到了可以实现这个延迟的队列 beanstalk,但是无法实现分布式,单台的方式公司运维不给弄,他建议用 kafka,但是 kafka 好像不可以延迟
想请教大家,异步通知是实现方案,或者上面的问题怎么解决?
![]() | 1 pubby 2016-09-28 13:52:52 +08:00 benstalk 支持分布式的 类似 memcache ,客户端可以同时连几个 beanstalk 服务器 beanstalkd 的队列数据也可以写入磁盘 log 的 但是,如果一个挂掉,磁盘又出故障无法恢复的话,会丢失一部分队列数据 |
2 klgd OP @pubby 看介绍说支持分布式,我安装了 php 扩展 https://github.com/nil-zhang/php-beanstalk/, phpinfo 里也看到有 beanstalk 扩展了,但是按照示例执行,始终返回 false ,不知道哪里的问题,而且扩展都是好几年前的了 |
![]() | 3 moro 2016-09-28 14:20:19 +08:00 可以用 golang 写服务来处理,自身包含队列,异步发送通知。 |
![]() | 5 pubby 2016-09-28 14:22:56 +08:00 |
6 xss 2016-09-28 14:28:46 +08:00 rabbitmq 不可以? |
![]() | 8 moro 2016-09-28 14:38:05 +08:00 用 redis 的有序集合,按时间排序,每次把需要处理的事务插入进去。 处理部分每秒读取一次有序集合,只取出当前时间的进行处理就可以了。 |
![]() | 9 moro 2016-09-28 14:39:19 +08:00 分布式的话可以在 redis 使用 lua 脚本来保证一致性。 |
![]() | 10 pubby 2016-09-28 14:54:06 +08:00 |
11 klgd OP |
![]() | 12 TangMonk 2016-09-28 15:28:04 +08:00 rabbitmq 有个插件可以延迟发送 |
![]() | 13 moro 2016-09-28 15:31:45 +08:00 redis 每秒请求无压力,都是内存的。 |
![]() | 14 fansgentle 2016-09-28 15:36:33 +08:00 Python 平台的话 Celery 就很赞 ... |
![]() | 15 pubby 2016-09-28 16:20:57 +08:00 @klgd 看了一下,这个库在 pool 上 reserve() job 的时候也有问题 它是随机找一个 server 获取的,如果队列很空的话,可能会长时间饿死状态。 put 也是随机找一个 server 写入 可以改变一下应用方案: 1. 生产者 put 的时候可以向所有 pool 里面随机挑选一个写入(内部已经实现) 2. 每个消费者脚本只连一台 beanstalkd 进行任务处理。任务忙,可以多启动几个消费者连接同一台 beanstalkd 。 |
![]() | 16 accacc 2016-09-28 18:24:42 +08:00 使用 redis 的 zset 结构做队列 score 写入时间戳 按照小于当前时间的出队 |
![]() | 17 hankwh 2016-09-28 18:58:12 +08:00 异步通知不好实现的话,你提供查询订单结果的接口就可以了,让接入方主动查询 |
18 klgd OP @pubby 嗯,今天在试用时发现这个问题了,不过还没来得及思考如何和业务需求结合 @hankwh 查询接口有提供 @accacc redis 的排序功能?这个思路也不错,回头我想想怎么具体实现 @fansgentle python 不会啊 |
19 youxiaer 2016-09-28 19:41:03 +08:00 beanstalk 做这个很合适 |
![]() | 20 sherlocktheplant 2016-09-28 19:50:29 +08:00 rabbitmq 好像可以实现你的功能 也支持分布式部署 |
![]() | 21 cszchen 2016-09-28 20:32:36 +08:00 可以用 php-resque ,本身是一个队列,支持定时执行。 |
![]() | 22 pubby 2016-09-28 20:49:40 +08:00 印象中 rabbitmq 貌似没有 message 的优先级,几年前用过,至少 php 的 amqp 扩展没有支持优先级设置。 rabbitmq 比较强大,能做消息系统 beanstalk 只能做队列 |
23 julyclyde 2016-09-29 11:50:14 +08:00 用什么队列其实是无所谓的 轻负载的情况下,队列长度基本保持在 0 ,也就是收到之后立刻就能处理 当队列积压的情况下,虽然没及时确认,导致支付网关假确认,但你也没更好的办法了 所以其实没啥需要担心的 |
![]() | 24 jerray 2016-09-29 12:08:33 +08:00 延迟发送用 RabbitMQ 可以实现,并不需要任何 RabbitMQ 扩展。 方案: 比如说你有一个 Exchange EA ,一个队列 QA ,通过 EA 进来的消息会被分发到 QA 上, Consumer 监听着队列 QA ,一旦有消息就会被消费。 然后创建一个 15s 消息超时的延时队列 QA_deferred_15s ,设置参数 x-message-ttl 为 15000 , x-dead-letter-exchange 为 EA 。 QA 的 Consumer 消费队列消息时,如果认为需要延时重试,则把这条消息发送到 QA_deferred_15s 中。由于设置了 x-message-ttl 参数, 15 秒后, QA_deferred_15s 中的这条消息会超时。由于 x-dead-letter-exchange 设置为了 EA ,超时的消息会被发送到 EA ,再由 EA 分发给 QA 。 依次类推,创建其他延时队列。大致流程就是这样: Publisher -> EA -> QA -> Consumer Consumer -> QA_deferred_15s -> message timeout -> EA Consumer -> QA_deferred_3m -> message timeout -> EA Consumer -> QA_deferred_10m -> message timeout -> EA ... 需要在 Consumer 中改写消息,以便下次需要重试时能知道把消息丢进哪个延时队列。 |
26 inputnames 2017-12-13 09:21:55 +08:00 楼主,请问你支付解决了吗,我也遇到同样的问题。求帮助呀 |