目前的实现方式:
参考支付宝的异步通知,每个订单的异步通知实行分频率发送: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
楼主,请问你支付解决了吗,我也遇到同样的问题。求帮助呀
|