近期偶刷到一篇文章,讲 java 的 http 异步调用,但实际上服务端还是连的同步服务。
想到之前遇到的一个问题,诚心求教: 有个业务通过 MQ 消息队列交互,请求和响应分别通过 MQ 进行消息传递,异步传递,时间间隔小于 1 秒。 前端希望该业务通过 http 接口调用,那么有什么方式可以实现呢? 我们因为有个产品有这块功能,所以当时就通过产品实现了 http 同步转 MQ 异步,但希望了解下有哪些开源方案呢?最好是基于 springboot 的方案。
感谢!
1
nulIptr 2022-09-06 18:59:10 +08:00
问题过于小白
mq 主要用来解耦,异步 /广播这些都是解耦带来的好处。 你这用一个 http 请求相当于又回去了,mq 还有啥用呢。 举个例子,前端界面有个导出报表的功能,报表导出又耗资源又耗时,所以就做成点完按钮发个导出的消息,导出服务作为消费者可以在有资源的时候执行导出,然后导出完了再发个导出完成的消息, 再有个邮件推送服务可以消费导出完成的这个消息,给用户发个 email 附上下载链接啥的。这时候业务就完了,当然具体实现复杂多了。 如果照你说的,业务实际上进行的很快,导出 1 秒就完事了,那不如不发 mq ,直接内存里面构造好数据直接返回了 |
2
lchqfnu OP @nulIptr 有些架构是变不了的,是现有的,比如 MQ 的异步消息机制。需要利用现有的东西,实现目标的机制,比如案例中的 http 接口。
|
3
CEBBCAT 2022-09-06 19:20:56 +08:00
不好意思,问题可能有一点点多,因为我现在的确有点困惑。
1. 开头提到的「 Java 的 HTTP 异步调用」和后面的问题是什么关系呢?也有一点没懂“服务端还是连的同步服务”的意思。 2. “前端希望该业务通过 http 接口调用,那么有什么方式可以实现呢?”听起来有点奇怪,前后端最常见的就是通过 HTTP 接口调用来完成吧?你是指前端希望通过阻塞式接口来获取响应吗? 3. “我们因为有个产品有这块功能”是说你们开发过一个 toC 的软件恰好可以帮自己解决这个问题?但听起来好像也不太对。因为后面又在问有没有开源方案。 假如说你是想问如何实现 [通过阻塞式 HTTP 接口服务异步式业务并返回业务结果] 的话,我觉得其实只要以“有结果后再 return”为中心来设计就可以了。比如你可以通过在服务端轮训、监听事件等等方式来实现结果的获取 |
4
lchqfnu OP @CEBBCAT
感谢回复。 1 、前后没有必然联系,java 的 http 异步调用提到的是非非阻塞式调用,实质上调用的服务是普通的 http 接口。 2 、问题场景是前后端希望是标准 restful 接口,但后端接口实现了 MQ 消息发送,以及发送后 MQ 异步响应消息监听,获取结果后加工成前端要的结构 http 同步返回。 3 、提到某产品是指的公司采购的产品,实现了 2 的功能,实现逻辑不明。 4 、springboot 提供了 jms 组件可以比较方便的监听消息队列,以及操作队列管理群发送队列消息,但是将发送消息和监听结合起来形成一个后端服务,没想到合适的方式。 |
5
q1angch0u 2022-09-06 19:44:23 +08:00 via iPhone
当时有个分布式服务,处理方式是使用了 redis 的 pubsub ,http 写 mq 的时候生成一个 uuid 为 key ,生成一个锁为 value ,之后把 uuid 透传下去。mq 处理完之后调用服务的 callback 接口,写入结果。callback 接口通过 uuid 获取锁,unlock 之后拿内容返回就行了。
|
6
q1angch0u 2022-09-06 19:45:45 +08:00 via iPhone 1
上边儿说的有误。当时有个分布式服务,处理方式是使用了 redis 的 pubsub ,http 写 mq 的时候生成一个 uuid 为 key ,生成一个锁为 value ,之后把 uuid 透传下去。mq 处理完之后写入 pubsub 。callback 接口通过 uuid 获取锁,unlock 之后拿内容返回就行了。
|
7
FrankAdler 2022-09-06 19:51:29 +08:00 via iPhone
不如试试 websocket ,请求响应分开
|
8
lchqfnu OP @q1angch0u 有意使用 redis 这种方式尝试一下,不过听起来也挺复杂的,主要是监听以后这个 callback ,这种异步方式平时没做过。老哥有 github 么,学习一下。
|
9
yazinnnn 2022-09-06 20:40:53 +08:00
guava 的 cache map 配合 CountDownLatch 不是很容易么...
只是是同步阻塞方案,性能比较差 |
10
mango88 2022-09-06 21:26:17 +08:00 1
各大网站 web 端的扫码登录 跟你提到的场景类似,你可以研究一下
|
11
lchqfnu OP @mango88 之前看过知乎的扫码登录好像是轮询,就是选择二维码登录以后,页面在一定时间内间隔轮询结果,超时后停止然后显示二维码失效过期。
或也有其他种类。 |
12
yazinnnn 2022-09-06 21:52:50 +08:00 1
https://gist.github.com/yazinnnn/14d8946a0e1278a2a269a3453a98e7ef
一个用 webflux 和 guava 的简单反应式实现, 可以根据你的业务自行修改 |
13
yazinnnn 2022-09-06 22:00:11 +08:00
业务超时 2 秒, rpc 响应时间 1-2.5 秒, 2000 链接同时请求,rps 在 800 以上, 能满足一般业务需求了
wrk -t 6 -c2000 -d10s http://localhost:8080/async Running 10s test @ http://localhost:8080/async 6 threads and 2000 connections Thread Stats Avg Stdev Max +/- Stdev Latency 10.10ms 43.17ms 1.31s 99.89% Req/Sec 504.96 501.88 1.42k 72.29% 8939 requests in 10.05s, 717.49KB read Socket errors: connect 0, read 0, write 0, timeout 7988 Requests/sec: 889.10 Transfer/sec: 71.36KB |
14
szzadkk 2022-09-07 09:35:20 +08:00
dubbo 里面好像有这种异步转同步的方案,可以参考下
|
15
lchqfnu OP @yazinnnn kotlin 虽然没有太看懂,但是看起来这个 demo 实现的是一个非阻塞式异步响应,关于响应这块,还是没明白如何结合监听的方式去应答。
|
16
lchqfnu OP @yazinnnn webflux 看起来功能好强大,但需要时间学习。不晓得 webflux 是否能够实现监听队列消息后响应给前端;或者说是否可以在 mq listener 中往 mono 或者什么的里面设置返回内容,然后 webflux 会从 mono 里把返回内容响应给前端。
|
18
lchqfnu OP |
20
258 2022-09-07 15:01:41 +08:00
前端使用长轮询方案,当 http 请求时不立即返回,hold 住链接。等 mq 消息过来之后,将消息返回给前端。也可以使用 websocket 长链接
|
21
ymy3232 2022-09-07 17:40:32 +08:00 1
你想要的应该是这个 https://docs.spring.io/spring-framework/docs/5.3.22/reference/html/web.html#mvc-ann-async
1.6.1 DeferredResult |