支付系统0X00: 支付系统预研

2017-11-21  本文已影响1035人  daydaygo

date: 2017-11-19 17:12:16
title: 支付系统0X00: 支付系统预研

最近在写支付系统, 之前公司写了一版, 量级比较小, 纯同步, 应用层就简单的 api + task, 项目结构也简单:

├── lib
├── pay-lib
├── pay-gateway
└── pay-task

虽然当时在开发的时候, 也参考了不少资料, 并出了一份设计文档(之前的 blog - 支付系统设计), 但是当时并没有好好阅读源码, 所以有点浅尝辄止. 这次重拾支付系统, 自然是想做得 更好一点, 不然也就同 rango 说的那样了:

无法进入一个拥有大规模并发请求的项目中得到历练,不坚持提升自己,那也只能在小公司混日子了。

这次的技术预研花了不少时间, 一方面是由于现在开源出来的系统, 都是基于 java 的, 自己确实 java 水平有限. java 的语法看了不止 4 遍(学校里的 java 课, 慕课网 java 视频教程, 实验楼 上面的 java 学习路径, 以及 <算法> 这本书是用 java 实现的), 不过离开学校之后就再没有用 java 写过项目. 有一次看 java 同事改请求地址在改动 xml 文件, 当时我还特别纳闷, 毕竟 php 的逻辑是 什么都可以 php 文件来处理, 最典型的是直接在 php 文件中写 html. 所以为了能看这些开源系统的源码轻松一点, 花了不少时间 继续 熟悉 java 的语法, 并快速看了几个主流框架的简单例子, 差不多能看懂大部分 黑话(各种词汇缩写) 的程度为止. 另一方面就比较客观了, 量变到质变, 没有足够的积累就是做不到想要的程度.

blog 的脉络:

教程: java SSH 项目使用 dubbo 进行服务化改造

龙果学院 - Dubbo视频教程(Dubbo项目实战): http://www.roncoo.com/course/view/f614343765bc4aac8597c6d8b38f06fd

拿项目中比较常见的用户注册登录功能来说, 如果量级比较小, 注册登录只是整个项目中的一个模块(module), php 各类大型框架(laravel, yii, thinkphp 等) 也都是这样设计, 而且开箱即用, 功能全面. 这方面可以参考 laravel 框架, 功能点很全面, 包括 认证(authentication)/授权(authorization)/密码安全(password)/流量控制(rate limit) 等.

当然, 如果量级比较大, 就需要一个单独的用户(账户)系统了. 独立出来的好处很明显, 比如统一登录, 这样可以踢人下线, 比如安全和风控. 独立出来作为单独的系统, 其实就很接近现在流行的 微服务设计.

回到正题, 罗列一下简单思路(恕我 java 水平有限, 欢迎指正):

更近一步, 基础部分(user-common)可以做的更彻底:

当然少不了服务化的基础设施:

dubbo architecture zookeeper service

一点个人观点: 要深入一个工具可能需要与时间长跑, 但是, 先用起来吧, 体验一下技术的畅快.

这里举一个之前开发 tcp server 的例子, 当时服务注册发现这块使用的 etcd, 我这里只需要在 server 启动的时候, 发一条 http 给 etcd 注册一下即可:

use Swoole\Server;

$s = new Server("0.0.0.0", 9501); // 这就是下面的 gameServer
$s->set([
    'work_num' => 1,
    'task_work_num' => 1,
]);
$s->on('connect', function (Server $s, $fd) {
    echo "connect| $fd \n";
});
$s->on('start', function (Server $s) {
    // server 启动时注册到注册中心
    // curl -vvv http://10.0.1.48:2379/v2/keys/gameServerList/$zoneId/$nodeId -XPUT -d value="x.x.x.x:9501"

    // 获取 gameServer
    // curl http://10.0.1.48:2379/v2/keys/gameServerList/1/1
});
...
$s->start();

是不是 hin简单?

此亦无他, 唯手生尔.

roncoo-pay: 龙果开源支付系统源码解读

龙果支付系统视频教程: http://www.roncoo.com/course/view/a09d8badbce04bd380f56034f8e68be0

首先参考的源码是 龙果支付系统:

核心支付流程

下面是代码结构:

├── LICENSE
├── README.md
├── UPDATELOG.md
├── database.sql
├── pom.xml
├── roncoo-pay-app-notify
├── roncoo-pay-app-order-polling
├── roncoo-pay-app-reconciliation
├── roncoo-pay-app-settlement
├── roncoo-pay-common-core
├── roncoo-pay-service
├── roncoo-pay-web-boss
├── roncoo-pay-web-gateway
├── roncoo-pay-web-merchant
└── roncoo-pay-web-sample-shop

没啥可说的, 不过列举一下, 以后设计的时候可以参考: config(配置); BaseDao(数据模型基类); 接口公共返回值/分页等请求相关; 数据库枚举类型(enum); 业务异常(BizException); 工具助手类(Util)

这里有个细节: 数据库里的字段用的 string 数据类型, 使用类来存储枚举类型

核心业务实现, 包括 account(账户, 支付系统中标识交易实体, 参与交易和结算) / notify(异步通知商户) / permission(权限管理) / reconciliation(对账) / trade(交易) / user(用户信息/支付方式, 产品信息) 模块

每个模块按照如下方式组织代码: dao(数据层) + entity(实体, 和数据模型对比) + enums(类型枚举) + exception(异常) + service(具体业务实现) + util(工具助手类) + vo()

从 db (startInitFromDB()) 中读取数据(status 状态 / notifyTime 通知次数), 使用 线程池(threadPool) 和 队列(notifyQueue) 完成异步通知, 最后会写到数据库(notifyPersist)
需要注意的是, 最后数据库落库并不是直接更新, 先将数据写入到 ActiveMQ, 再由 db 来消费

和上面类似, 线程池 + 队列 来查询支付结果
这里的区别是: 订单支付后添加消息到 ActiveMQ, app-order-polling 设置了 PollingMessageListener 来订阅这个消息, 从而触发上面的查询

这个项目比较简单, 因为对账流程是固定的: 判断是否对账 -> 获取对账数据 -> 解析 -> 对账流程
值得借鉴的是: 对账的每个步骤都抽象成相应的 xxxBiz 类来处理; 解析这一步定义了 ParserInterface, 确保对账流程使用的格式一致

对账流程

这个项目也比较简单, 维护了 SettThreadPool 来处理结算任务, 按照 每日/自动 2个维度进行处理

结算流程

基础的MVC, 项目并没有实现复杂的路由功能, 只包含 单个支付渠道/多个支付渠道

也是基础的MVC, 包含 权限管理 + 支付/对账/清算等支付功能的可视化

下单并对接支付系统

订单 / 支付 / 结算

龙果支付系统数据库

XxPay开源支付系统源码解读

XxPay官网:http://www.xxpay.org

另一个参考的开源支付系统时 XxPay支付系统

PS: 此系统还在保持更新, 感兴趣的同学可以加群提 feature, 很可能就加到之后的发版计划了哦

XxPay 支付系统在业务上只包含核心的支付流程, 准确说业务功能实现简单, 但是在系统架构实现上提供了更多选择:

而且开发上也引入了 docker 来解决环境问题, 用一句话来总结的话: 更加现代化. 推荐阅读源码.

xxpay-master
├── xxpay4dubbo -- spring-boot-dubbo架构实现
|    ├── xxpay4dubbo-api -- 接口定义
|    ├── xxpay4dubbo-service -- 服务生产者
|    ├── xxpay4dubbo-web -- 服务消费者
├── xxpay4spring-cloud -- spring-cloud架构实现
|    ├── xxpay-config -- 配置中心
|    ├── xxpay-gateway -- API网关
|    ├── xxpay-server -- 服务注册中心
|    ├── xxpay-service -- 服务生产者
|    └── xxpay-web -- 服务消费者
├── xxpay4spring-boot -- spring-boot架构实现
├── xxpay-common -- 公共模块
├── xxpay-dal -- 数据持久层
├── xxpay-mgr -- 运营管理平台
├── xxpay-shop -- 演示商城

对应的数据层也非常简单:

image

基于老熊的支付系统设计

凤凰牌老熊 - 现代支付系统设计 - 基于微服务的实践: http://blog.lixf.cn/

老熊的博客里面干货很多, 还建立了金融产品技术群长期分享干货, 强烈推荐.

php 自研支付系统设计

综合来看, 实现微服务化, 是 php 自研支付系统设计的正确方向.

常规的 web/api/task/mysql/redis 就不赘述, 你不应该只停留在这个水平

基础设施

更多准备工作可以参考: 重构中的内部准备工作

更多技术要求:

系统设计

支付产品:

账户&账务:

风控:

核心业务流程:

备注: 隔天问题, 由于双方记录的时间可能隔天, 导致对账日切文件差异, 可以通过对比多天数据进行消除

写在最后

写这篇 blog 的初衷, 多少有点来自于现在开源支付系统 java 一家独大, 但就提供服务而言(服务器领域), php 都应该有一席之地才对. 有个说法对一个语言了解的越多, 就越清楚这个语言擅长(适合)干什么, 所以我认为 php 也完全可以写出很好的支付系统.

题外话, 关于语言的选择, 可以参看 鸟哥的这篇 blog: 关于语言的选择-选易用的

上一篇 下一篇

猜你喜欢

热点阅读