支付系统就该这么设计(万能通用),稳的一批!

支付永远是一个公司的核心领域,因为这是一个有交易属性公司的命脉。那么,支付系统到底长什么样,又是怎么运行交互的呢?抛开带有支付牌照的金融公司的支付架构,下述链路和系统组成基本上符合绝大多数支付场景。其实整体可以看成是交易核心+支付核心 两个大系统。交易系统关联了业务场景和底层支付,而支付系统完成了调用支付工具到对账清算等一系列相关操作。下面我们就来一起看下各个系统的核心组成和交互。

1. 支付系统总览

核心系统交互

图片

业务图谱

图片

2. 核心系统解析

交易核心

交易核心把公司的业务系统和底层支付关联起来,让业务系统专注于业务,不比关心底层支付。

交易核心

图片

基础交易类型抽象

图片

多表聚合 & 订单关联

图片

支付核心

支付核心主要负责将多种支付类型进行抽象,变成 充值提现退款转账四种支付形态。同时,还要负责集成多种支付工具,对支付指令进行编排等等。

支付核心总览

图片

支付行为编排

其目的,是实现 插件式开发支付规则可配置的 灵活开发方式。

图片

异常处理

异常处理包括了 重复支付、部分支付、金额不一致、其他异常等异常场景。

图片

渠道网关

图片

资金核算

图片

3. 服务治理

平台统一上下文

通过确定系统边界、业务建模拆分之后,整个支付平台被拆分几十个服务,而如何保障在服务间流转业务信息不被丢失,是我们需要考虑的问题。平台统一上下文的要素信息(唯一业务标识码),在整个支付平台链路中全程传递,被用来解决这个问题。

图片

数据一致性治理

大型的支付公司,内部都有非常严格和完备的数据一致性方案,比如采用业务侵入性非常大的分布式事务等,以牺牲开发效率来提升数据的稳定,是非常有必要的。而业务公司,如果不采用分布式事务又有哪些应对策略呢?

CAS校验

图片

幂等 & 异常补偿

图片

对账

图片

准实时对账

图片

DB拆分

图片

异步化

支付是整个交易链路的核心环节,那么,怎么兼顾支付系统的稳定性和执行效率呢?是异步化。

消息异步化

图片

外部支付调用异步化

图片

在外部支付中,经常需要服务方与第三方支付交互,获取预支付凭证,如上图所示。

这种同步调用的情况下,由于需要跨外部网络,响应的 RT 会非常长,可能会出现跨秒的情况。由于是同步调用,会阻塞整个支付链路。一旦 RT 很长且 QPS 比较大的情况下,服务会整体 hold 住,甚至会出现拒绝服务的情况。

图片

因此,可以拆分获取凭证的操作,通过独立网关渠道前置服务,将获取的方式异步化,从前置网关获取内部凭证,然后由前置网关去异步调用第三方。

异步并行化

图片

资金核算异步化

图片

热点账户账务单独处理

图片

记账事务切分

图片

4. 生产实践

性能压测

构建压测模型,模拟现实真实场景;压测数据进影子库,正常业务无侵入;单机性能和集权链路都不能忽视;识别系统稳定性和容量配比。。。

图片

稳定性治理

图片

核心链路分离

图片

服务依赖降级

图片

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: A*算法是一种常用于寻找最短路径的算法。下面给出一个万能通用的Matlab代码实现: ```matlab function shortestPath = A_star(startNode, goalNode, adjacencyMatrix, heuristic) numNodes = size(adjacencyMatrix, 1); % 获取节点数量 openSet = startNode; % 初始化开放集合 gScore = Inf(numNodes, 1); % 初始化gScore gScore(startNode) = 0; % 设置起始节点的gScore为0 fScore = Inf(numNodes, 1); % 初始化fScore fScore(startNode) = heuristic(startNode, goalNode); % 设置起始节点的fScore为启发式函数值 cameFrom = zeros(numNodes, 1); % 初始化cameFrom数组 while ~isempty(openSet) [~, current] = min(fScore(openSet)); % 从开放集合中选择fScore最小的节点作为当前节点 if current == goalNode shortestPath = reconstructPath(cameFrom, current); % 如果当前节点为目标节点,则重构路径并返回 return; end openSet(openSet == current) = []; % 从开放集合中移除当前节点 neighbors = find(adjacencyMatrix(current,:) > 0); % 获取当前节点的邻居节点 for i = 1:length(neighbors) neighbor = neighbors(i); tentativeGScore = gScore(current) + adjacencyMatrix(current, neighbor); % 从当前节点到邻居节点的距离 if tentativeGScore < gScore(neighbor) cameFrom(neighbor) = current; % 更新邻居节点的cameFrom gScore(neighbor) = tentativeGScore; % 更新邻居节点的gScore fScore(neighbor) = gScore(neighbor) + heuristic(neighbor, goalNode); % 更新邻居节点的fScore if ~ismember(neighbor, openSet) openSet(end+1) = neighbor; % 如果邻居节点不在开放集合中,则将其加入 end end end end error("No path found."); % 如果无法到达目标节点,则抛出错误 end function path = reconstructPath(cameFrom, current) path = current; while cameFrom(current) ~= 0 current = cameFrom(current); path = [current; path]; % 在路径之前添加上一个节点 end end ``` 上述代码实现了A*算法的最短路径搜索。其中,`startNode`表示起始节点的索引,`goalNode`表示目标节点的索引,`adjacencyMatrix`表示节点间的邻接矩阵,`heuristic`表示启发式函数。函数输出为一个表示最短路径的向量,即从起始节点到目标节点的节点索引序列。 这个代码适用于任何可以表示为图的最短路径问题,只需提供相应的起始节点、目标节点、邻接矩阵和启发式函数即可。 ### 回答2: A*算法是一种用于寻找最短路径的启发式搜索算法,在许多应用中被广泛使用。下面我将给出一个使用MATLAB实现的通用A*算法代码: ```matlab function path = AStar(start, goal, heuristic, cost) openSet = start; % 初始化openSet队列,包含起点 closedSet = []; % 初始化closedSet队列,不包含任何节点 gScore = inf(size(cost)); % 初始化gScore为无穷大 gScore(start) = 0; % 起点的gScore为0 fScore = inf(size(cost)); % 初始化fScore为无穷大 fScore(start) = heuristic(start, goal); % 起点的fScore为启发式函数的值 while ~isempty(openSet) [~, current] = min(fScore(openSet)); % 在openSet中找到fScore最小的节点作为当前节点 current = openSet(current); if current == goal % 当前节点为目标节点 path = reconstructPath(cameFrom, current); return; end openSet(openSet == current) = []; % 将当前节点从openSet中删除 closedSet = [closedSet, current]; % 添加当前节点到closedSet for neighbor = find(cost(current, :)) % 遍历当前节点的邻居节点 if ismember(neighbor, closedSet) % 跳过已经在closedSet中的节点 continue; end tentativeGScore = gScore(current) + cost(current, neighbor); % 计算从起点到邻居节点的临时gScore if ~ismember(neighbor, openSet) % 如果邻居节点不在openSet中 openSet = [openSet, neighbor]; % 将邻居节点添加到openSet elseif tentativeGScore >= gScore(neighbor) % 如果临时gScore不小于邻居节点的gScore continue; % 跳过当前循环 end cameFrom(neighbor) = current; % 更新邻居节点的cameFrom指针 gScore(neighbor) = tentativeGScore; % 更新邻居节点的gScore fScore(neighbor) = gScore(neighbor) + heuristic(neighbor, goal); % 更新邻居节点的fScore end end error("No path found!"); % 如果循环结束时仍未找到路径,抛出错误异常 end function path = reconstructPath(cameFrom, current) path(1) = current; % 从目标节点出发 while cameFrom(current) ~= 0 % 当前节点存在指向的前驱节点 current = cameFrom(current); % 回溯节点 path = [current, path]; % 添加到路径中 end end ``` 上述代码实现了一个基本的A*算法,其中使用了启发式函数(heuristic)和代价函数(cost)来评估节点的值。在代码中,我们首先初始化openSet队列,然后在每一次迭代中选择fScore最小的节点作为当前节点,然后通过遍历当前节点的邻居节点来更新节点的gScore和fScore。最后,如果找到了路径,我们通过回溯(reconstructPath)来生成最短路径。 这段代码可以根据具体的应用场景进行一定的修改和优化。 ### 回答3: A*算法是一种常用的图搜索算法,可以用于求解最短路径问题。下面是一个用MATLAB实现的通用的A*算法代码: ```matlab function path = Astar(graph, start, goal) % 初始化起点和终点节点 startNode = Node(start, [], 0, heuristic(start, goal)); goalNode = Node(goal, [], inf, inf); % 初始化开启列表和关闭列表 openList = PriorityList(); closeList = {}; % 将起点节点加入开启列表 openList.add(startNode); % 当开启列表不为空时,继续搜索 while ~openList.isEmpty() % 从开启列表中获取最佳节点 currentNode = openList.removeFirst(); % 将当前节点加入关闭列表 closeList{end+1} = currentNode; % 如果当前节点是目标节点,则找到最短路径 if currentNode == goalNode path = reconstructPath(currentNode); return; end % 获取当前节点的所有相邻节点 neighbors = getNeighbors(graph, currentNode); for i = 1:length(neighbors) neighbor = neighbors(i); % 跳过已经在关闭列表中的节点 if isNodeInList(neighbor, closeList) continue; end % 计算从起点到这个相邻节点的已知最短路径 tentative_gScore = currentNode.gScore + getDistance(currentNode, neighbor); % 判断这个相邻节点是否已经在开启列表 if ~openList.contains(neighbor) openList.add(neighbor); elseif tentative_gScore >= neighbor.gScore continue; end % 更新相邻节点的父节点和路径代价 neighbor.parent = currentNode; neighbor.gScore = tentative_gScore; neighbor.fScore = neighbor.gScore + heuristic(neighbor.position, goal); end end % 若无法找到最短路径,返回空 path = []; end function path = reconstructPath(lastNode) path = []; while ~isempty(lastNode) path = [lastNode.position path]; lastNode = lastNode.parent; end end function neighbors = getNeighbors(graph, node) neighbors = []; for i = 1:size(graph, 1) if graph(node.position, i) ~= 0 neighbors = [neighbors Node(i)]; end end end function distance = getDistance(nodeA, nodeB) distance = graph(nodeA.position, nodeB.position); end function h = heuristic(position, goal) h = abs(position - goal); end classdef Node < handle properties position parent gScore fScore end methods function obj = Node(position, parent, gScore, fScore) obj.position = position; obj.parent = parent; obj.gScore = gScore; obj.fScore = fScore; end function result = eq(obj, other) result = obj.position == other.position; end end end classdef PriorityList < handle properties list end methods function obj = PriorityList() obj.list = {}; end function add(obj, item) for i = 1:length(obj.list) if item.fScore < obj.list{i}.fScore obj.list = [obj.list(1:i-1) item obj.list(i:end)]; return; end end obj.list{end+1} = item; end function removeFirst(obj) if ~isempty(obj.list) obj.list = obj.list(2:end); end end function result = isEmpty(obj) result = isempty(obj.list); end function result = contains(obj, item) result = false; for i = 1:length(obj.list) if obj.list{i} == item result = true; return; end end end end end ``` 以上代码实现了A*算法的一个通用版本,可以通过修改图的邻接矩阵、起点和终点来解决不同的最短路径问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值