前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >订单支付[通俗易懂]

订单支付[通俗易懂]

作者头像
全栈程序员站长
发布于 2022-08-18 05:58:56
发布于 2022-08-18 05:58:56
1.4K0
举报

大家好,又见面了,我是你们的朋友全栈君。

目录

前言

支付系统的作用

核心流程

架构图

代码流程

线程池中处理发送消息到MQ、持久化的数据库

支付成功后,消息分发流程图

​订单作为消费者消费消息

测试



前言

文章中的图片和在摘录不是来自一篇文章,所以细节不是完全对应。可借鉴的是开发的思路:

  1. 从整体的功能模块的使用;
  2. 到核心流程;
  3. 到系统实现的架构;
  4. 再到代码流程(可以采用序列图)。

前两点是业务需求,后两点是功能实现。

支付系统的作用

https://www.cnblogs.com/veblen/p/10992167.html

核心流程

http://www.woshipm.com/pd/1392102.html

订单支付:

用户支付完订单后,需要获取订单的支付信息,包括支付流水号、支付时间等。支付完订单接着就是等商家发货,但在发货过程中,根据平台业务模式的不同,可能会涉及到订单的拆分。

架构图

https://blog.csdn.net/egworkspace/article/details/78900438?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

跟着标注的序号,可以跟踪到一个支付请求是如何发起的(Sequence Diagram就免了),流程描述如下:

  1. Submit a pay task,当客户端需要发起支付的时候,起始是向支付任务队列里面加入了一个新的支付任务,这个过程是异步实现的。先根据客户端提交的参数,构造好一个新的支付任务;
  2. Offer a task,开启一个异步任务,做的事情就是向MQ中添加一个新的支付任务,等待被消费;
  3. Pay task description,一旦异步任务被成功创建,将会把第一步构造好的支付任务信息直接return给客户端;
  4. Poll a task,与此同时,支付任务的消费者将新的支付任务poll下来进行执行;
  5. Send a pay request,这一步需要根据实际情况而定。并不是所有的支付请求都要先经过第三方支付平台,比如支付宝;而对于微信,则还需要凭支付参数申请一个prepay_id,再经由客户端发起支付;
  6. Response,没什么好说的,第三方渠道返回的支付必要参数;
  7. Cache result,至此,一个支付任务可以算是完成了,可以将任务的执行结果(无论成功与否)缓存在Redis中,随时等待客户端的回访;
  8. Query result,客户端在提交支付任务后,间隔一定时间后(建议2~3s),发起一个结果查询的请求;
  9. Query,直接进Redis查找结果;
  10. Synchronize,这是一个异步的操作,将支付任务的执行结果“顺便”同步到MongoDB中,并删除Redis中缓存的任务执行结果。持久化到MongoDB主要是为后续的容错,重试,数据分析等提供落地的数据源;
  11. Return,由Redis返回给应用服务器
  12. Return payment,应用服务器再将最终的支付对象返回给客户端。

让我们更深入一点,我们来看三张Class Diagram:

① 先说说支付任务(PayTask)部分。PayTask和Payment两个都是MongoDB中的Document对象,但在任务执行期间,PayTask是用Redis进行缓存的,方便客户端随时发起Query,任务执行成功后,会生成Payment对象,最终PayTask和Payment都会持久化到MongoDB中。在PayService中,有对支付任务的一些基本操作,包括任务提交,取消,重试,构建等等。

② 再说说任务的执行(runner)。这部分和RabbitMQ紧密相关,一旦一个支付任务形成了,就会放入任务执行队列中,由消费者取出执行。在TaskRunner中,有两个基本的接口方法:run(task)、retry(task),分别是执行任务和重试任务。在AbstractPayTaskRunner中已经封装好了这两个方法,继承AbstractPayTaskRunner需要实现doTask方法,从返回值可以看出,这个过程是异步化的。关于Retry机制,用户可以设置重试与否,一旦设置了TaskInfo.needRetry=true(不出意外,默认就是允许重试),就启用了Retry机制。还可以设置重试的次数(TaskInfo.retryTimes),默认三次,分别间隔1s,2s,3s,间隔时间以公差为1的等差数列组成。当然不会让用户无限重试,系统内置有一个最大重试次数,最大重试次数内置为5次。

为什么是5次?

你感受一下,1s,2s,3s,4s,5s,整个请求链条就被拉长到了15s,这对客户端简直就是灾难了!!

代码流程

创建支付

线程池中处理发送消息到MQ、持久化的数据库

支付成功后,消息分发流程图

订单作为消费者消费消息

测试

在测试程序中调用sendMessage

因为发送消息是在线程池中,当测试程序(主程序)停止运行,线程池也就停止运行,所以,为了让主程序不停止,在方法末尾加上:System.in.read();

System.in.read()可以实现输入字符,返回字符的Unicode码,但是缺点是只能输入一个字符 System.in.read() 返回的是输入数值的 ASKII 码(一个 int 整数)。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/134795.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月3,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
瞧瞧别人家的接口重试,那叫一个优雅!
记得五年前的一个深夜,某个电商平台的订单退款接口突发异常,因为银行系统网络抖动,退款请求连续失败。
苏三说技术
2025/03/11
1350
瞧瞧别人家的接口重试,那叫一个优雅!
redis 队列_Redis之延迟队列的实现
延迟队列,顾名思义它是一种带有延迟功能的消息队列。那么,是在什么场景下我才需要这样的队列呢?
Java架构师必看
2021/08/23
6130
【MQ我可以讲一个小时】
引入消息中间件也会带来很多问题,先说说消息丢失,生产者往消息队列发送消息,消息队列往消费者发送消息,会有丢消息的可能,消息队列也有可能丢消息,通常MQ存盘时都会先写入操作系统的缓存页中,然后再由操作系统异步的将消息写入硬盘,这个中间有个时间差,就可能会造成消息丢失,如果服务挂了,缓存中还没有来得及写入硬盘的消息就会发生消息丢失。不同的消息中间件对于消息丢失也有不同的解决方案,先说说最容易丢失消息的kafka吧。生产者发消息给Kafka Broker:消息写入Leader后,Follower是主动与Leader进行同步,然后发ack告诉生产者收到消息了,这个过程kafka提供了一个参数,request.required.acks属性来确认消息的生产,0表示不进行消息接收是否成功的确认,发生网络抖动消息丢了,生产者不校验ACK自然就不知道丢了。1表示当Leader接收成功时确认,只要Leader存活就可以保证不丢失,保证了吞吐量,但是如果leader挂了,恰好选了一个没有ACK的follower,那也丢了。-1或者all表示Leader和Follower都接收成功时确认,可以最大限度保证消息不丢失,但是吞吐量低,降低了kafka的性能。一般在不涉及金额的情况下,均衡考虑可以使用1,保证消息的发送和性能的一个平衡。Kafka Broker 消息同步和持久化:Kafka通过多分区多副本机制,可以最大限度保证数据不会丢失,如果数据已经写入系统缓存中,但是还没来得及刷入磁盘,这个时候机器宕机,或者没电了,那就丢消息了,当然这种情况很极端。Kafka Broker 将消息传递给消费者:如果消费这边配置的是自动提交,万一消费到数据还没处理完,就自动提交offset了,但是此时消费者直接宕机了,未处理完的数据丢失了,下次也消费不到了。所以为了避免这种情况,需要将配置改为,先消费处理数据,然后手动提交,这样消息处理失败,也不会提交成功,没有丢消息。
Java廖志伟
2022/03/07
4820
【MQ我可以讲一个小时】
万字长文讲透 RocketMQ 的消费逻辑
RocketMQ 是笔者非常喜欢的消息队列,4.9.X 版本是目前使用最广泛的版本,但它的消费逻辑相对较重,很多同学学习起来没有头绪。
勇哥java实战
2023/09/04
1.4K0
万字长文讲透 RocketMQ 的消费逻辑
rebbitMQ【rebbitMQ入门到精通】
消息中间件基于队列模型实现异步/同步传输数据 作用:可以实现支撑高并发、异步解耦、流量削峰、降低耦合度。
高大北
2022/09/07
4420
rebbitMQ【rebbitMQ入门到精通】
7.Android常用第三方支付
移动支付 用户使用移动的终端完成对所购买商品或者服务的支付功能;分为近场支付(蓝牙支付,刷卡,滴卡),和远程支付(网上支付,短信支付) app支付模块 常见的支付厂商-->常见的支付方式 支付宝:阿
六月的雨
2018/05/14
1.8K0
解决支付订单,重复提交问题!
如图是一个简化的下单流程,首先是提交订单,然后是支付。支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互,支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。
良月柒
2021/10/14
2.1K0
IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列
消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一。
JackJiang
2018/09/26
3.7K0
分布式服务 API 的幂等设计方案 & Spring Boot + Redis 拦截器实现实例
假如你有个服务提供一个接口,结果这个服务部署在了5台机器上,接着有个接口就是付款接口。
一个会写诗的程序员
2021/04/02
8480
服务端防止订单重复支付
上图是一个简化的下单流程,首先是提交订单,然后是支付。支付的话,一般是走支付网关(支付中心),然后支付中心与第三方支付渠道(微信、支付宝、银联)交互,支付成功以后,异步通知支付中心,支付中心更新自身支付订单状态,再通知业务应用,各业务再更新各自订单状态。
Ant丶
2022/03/01
7030
服务端防止订单重复支付
面试官:生产环境中使用RocketMQ常见问题
然后关于3这个环节,通常MQ存盘时都会先写入操作系统的缓存page cache中,然后再由操作系统异步的将消息写入硬盘。这个中间有个时间差,就可能会造成消息丢失。如果服务挂了,缓存中还没有来得及写入硬盘的消息就会丢失。
程序员子龙
2023/11/26
1.3K0
RocketMQ
系统的耦合性越高,容错性就越低。以电商应用为例,用户创建订单后,如果耦合调用库存系统、物流系统、支付系统,任何一个子系统出了故障或者因为升级等原因暂时不可用,都会造成下单操作异常,影响用户使用体验。
JokerDJ
2023/11/27
1.8K0
RocketMQ
订单视角看支付
支付是指为清偿商品交换和劳务活动所引起的债权债务,货币债权从付款人向收付人的转移的过程。支付能力是电商产品的核心能力之一,作为订单同学,有必要了解关联域支付的流程以及基本概念,同时支付领域的很多设计思路与资损防控经验对订单域的系统设计也很有借鉴意义。本文将从支付系统的历史、基本概念、系统设计、资损防控与订单与支付交互等方面予以介绍。
得物技术
2024/02/28
4110
订单视角看支付
聊聊 RocketMQ 4.X 消费逻辑
RocketMQ 是笔者非常喜欢的消息队列,4.9.X 版本是目前使用最广泛的版本,但它的消费逻辑相对较重,很多同学学习起来没有头绪。
勇哥java实战
2023/06/05
1K0
Redis安装与使用[通俗易懂]
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/111891.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/11
3080
大写的服,看完这篇你还不懂RocketMQ算我输
Apache RocketMQ 是一款 低延迟、高并发、高可用、高可靠的分布式消息中间件。消息队列 RocketMQ 可为分布式应用系统提供异步解耦和削峰填谷的能力,同时也具备互联网应用所需的海量消息堆积、高吞吐、可靠重试等特性。
猿天地
2020/09/22
6930
大写的服,看完这篇你还不懂RocketMQ算我输
Redis的三种延迟队列 - Java技术债务
在现代分布式系统设计中,延迟队列作为一种重要的数据结构,广泛应用于消息延迟处理、任务调度、缓存失效、订单超时处理等场景。Redis,作为一个高性能的键值对存储系统,凭借其丰富的数据结构、原子操作、发布/订阅模式以及Lua脚本支持,成为了实现延迟队列的理想选择。
Java技术债务
2024/07/10
5180
Android 支付宝支付开发流程
项目中要用到支付功能,需要支付宝支付、微信支付、银联支付,所以打算总结一下,方便以后的查阅,也方便大家, 用到的地方避免再次被坑。 今天我们就主要介绍一下支付宝支付,其他支付也给出了对应的连接。
网罗开发
2021/01/29
1K0
Android 支付宝支付开发流程
RabbitMQ面试热点
消息发送的几种模式 4种交换器类型 Direct Exchange: 直连交换器 小结:直连交换器发送消息会根据路由和交换机的绑定关系发送到队列 如果交换器名称为"",将使用默认交换器 默认交换器不会绑定任何队列,mq会直接把route_key当做queue名称去查找 ​ Fanout Exchange: 分发交换器(扇出交换器) 小结: 分发交换器发送消息会分发至所有和其有绑定的队列中,这样消息会被多个消费者
用户1880875
2021/08/26
7980
消息队列核心知识点_rocketmq
(1) 如果对消息队列功能和性能都没有很高的要求,只需一个开箱即用易维护的产品,建议使用RabbitMQ。
Java架构师必看
2021/03/22
6550
相关推荐
瞧瞧别人家的接口重试,那叫一个优雅!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档