首页 文章 精选 留言 我的

精选列表

搜索[版本兼容],共10000篇文章
优秀的个人博客,低调大师

CosId 2.0.0-RC1 发布,兼容 Spring Boot 3

CosId通用、灵活、高性能分布式 ID 生成器 更新内容(v2.0.0-RC1) 🎉 🎉 🎉 🔨 依赖更新 适配org.springframework.boot:spring-boot-dependencies3.0.0-RC1 代码基线升级到Java 17(Spring boot 3 要求 Java 17) 简介 CosId旨在提供通用、灵活、高性能的分布式 ID 生成器。 SnowflakeId:单机 TPS 性能:409W/sJMH 基准测试, 主要解决时钟回拨问题、机器号分配问题并且提供更加友好、灵活的使用体验。 SegmentId: 每次获取一段 (Step) ID,来降低号段分发器的网络 IO 请求频次提升性能。 IdSegmentDistributor: 号段分发器(号段存储器) RedisIdSegmentDistributor: 基于Redis的号段分发器。 JdbcIdSegmentDistributor: 基于Jdbc的号段分发器,支持各种关系型数据库。 ZookeeperIdSegmentDistributor: 基于Zookeeper的号段分发器。 SegmentChainId(推荐):SegmentChainId(lock-free) 是对SegmentId的增强。性能可达到近似AtomicLong的TPS 性能:12743W+/sJMH 基准测试。 PrefetchWorker维护安全距离 (safeDistance), 并且支持基于饥饿状态的动态safeDistance扩容 / 收缩。 背景(为什么需要分布式 ID) 在软件系统演进过程中,随着业务规模的增长 (TPS / 存储容量),我们需要通过集群化部署来分摊计算、存储压力。 应用服务的无状态设计使其具备了伸缩性。在使用Kubernetes部署时我们只需要一行命令即可完成服务伸缩 (kubectl scale --replicas=5 deployment/order-service)。 但对于有状态的数据库就不那么容易了,此时数据库变成系统的性能瓶颈是显而易见的。 分库分表 从微服务的角度来理解垂直拆分其实就是微服务拆分。以限界上下文来定义服务边界将大服务 / 单体应用拆分成多个自治的粒度更小的服务,因为自治性规范要求,数据库也需要进行业务拆分。 但垂直拆分后的单个微服务依然会面临 TPS / 存储容量 的挑战,所以这里我们重点讨论水平拆分的方式。 数据库分库分表方案是逻辑统一,物理分区自治的方案。其核心设计在于中间层映射方案的设计 (上图Mapping),即分片算法的设计。 几乎所有编程语言都内置实现了散列表 (java:HashMap/csharp:Dictionary/python:dict/go:map...)。分片算法跟散列表高度相似 (hashCode),都得通过key/shardingValue映射到对应的槽位 (slot)。 那么shardingValue从哪里来呢?CosId!! 当然还有很多分布式场景需要分布式 ID,这里不再一一列举。 分布式 ID 方案的核心指标 全局(相同业务)唯一性:唯一性保证是ID的必要条件,假设 ID 不唯一就会产生主键冲突,这点很容易可以理解。 通常所说的全局唯一性并不是指所有业务服务都要唯一,而是相同业务服务不同部署副本唯一。 比如 Order 服务的多个部署副本在生成t_order这张表的Id时是要求全局唯一的。至于t_order_item生成的ID与t_order是否唯一,并不影响唯一性约束,也不会产生什么副作用。 不同业务模块间也是同理。即唯一性主要解决的是 ID 冲突问题。 有序性:有序性保证是面向查询的数据结构算法(除了 Hash 算法)所必须的,是二分查找法(分而治之) 的前提。 MySq-InnoDB B + 树是使用最为广泛的,假设 Id 是无序的,B+ 树 为了维护 ID 的有序性,就会频繁的在索引的中间位置插入而挪动后面节点的位置,甚至导致频繁的页分裂,这对于性能的影响是极大的。那么如果我们能够保证 ID 的有序性这种情况就完全不同了,只需要进行追加写操作。所以 ID 的有序性是非常重要的,也是 ID 设计不可避免的特性。 吞吐量 / 性能 (ops/time):即单位时间(每秒)能产生的 ID 数量。生成 ID 是非常高频的操作,也是最为基本的。假设 ID 生成的性能缓慢,那么不管怎么进行系统优化也无法获得更好的性能。 一般我们会首先生成 ID,然后再执行写入操作,假设 ID 生成缓慢,那么整体性能上限就会受到限制,这一点应该不难理解。 稳定性 (time/op):稳定性指标一般可以采用每个操作的时间进行百分位采样来分析,比如CosId百分位采样P9999=0.208 us/op,即0% ~ 99.99%的单位操作时间小于等于0.208 us/op。 百分位数 WIKI:统计学术语,若将一组数据从小到大排序,并计算相应的累计百分点,则某百分点所对应数据的值,就称为这百分点的百分位数,以 Pk 表示第 k 百分位数。百分位数是用来比较个体在群体中的相对地位量数。 为什么不用平均每个操作的时间:马老师的身价跟你的身价能平均么?平均后的值有意义不? 可以使用最小每个操作的时间、最大每个操作的时间作为参考吗?因为最小、最大值只说明了零界点的情况,虽说可以作为稳定性的参考,但依然不够全面。而且百分位数已经覆盖了这俩个指标。 自治性(依赖):主要是指对外部环境有无依赖,比如号段模式会强依赖第三方存储中间件来获取NexMaxId。自治性还会对可用性造成影响。 可用性:分布式 ID 的可用性主要会受到自治性影响,比如SnowflakeId会受到时钟回拨影响,导致处于短暂时间的不可用状态。而号段模式会受到第三方发号器(NexMaxId)的可用性影响。 可用性 WIKI:在一个给定的时间间隔内,对于一个功能个体来讲,总的可用时间所占的比例。 MTBF:平均故障间隔 MDT:平均修复 / 恢复时间 Availability=MTBF/(MTBF+MDT) 假设 MTBF 为 1 年,MDT 为 1 小时,即Availability=(365*24)/(365*24+1)=0.999885857778792≈99.99%,也就是我们通常所说对可用性 4 个 9。 适应性:是指在面对外部环境变化的自适应能力,这里我们主要说的是面对流量突发时动态伸缩分布式 ID 的性能, SegmentChainId可以基于饥饿状态进行安全距离的动态伸缩。 SnowflakeId常规位分配方案性能恒定 409.6W,虽然可以通过调整位分配方案来获得不同的 TPS 性能,但是位分配方法的变更是破坏性的,一般根据业务场景确定位分配方案后不再变更。 存储空间:还是用 MySq-InnoDB B + 树来举例,普通索引(二级索引)会存储主键值,主键越大占用的内存缓存、磁盘空间也会越大。Page 页存储的数据越少,磁盘 IO 访问的次数会增加。总之在满足业务需求的情况下,尽可能小的存储空间占用在绝大多数场景下都是好的设计原则。 不同分布式 ID 方案核心指标对比 分布式 ID 全局唯一性 有序性 吞吐量 稳定性(1s=1000,000us) 自治性 可用性 适应性 存储空间 UUID/GUID 是 完全无序 3078638(ops/s) P9999=0.325(us/op) 完全自治 100% 否 128-bit SnowflakeId 是 本地单调递增,全局趋势递增 (受全局时钟影响) 4096000(ops/s) P9999=0.244(us/op) 依赖时钟 时钟回拨会导致短暂不可用 否 64-bit SegmentId 是 本地单调递增,全局趋势递增 (受 Step 影响) 29506073(ops/s) P9999=46.624(us/op) 依赖第三方号段分发器 受号段分发器可用性影响 否 64-bit SegmentChainId 是 本地单调递增,全局趋势递增 (受 Step、安全距离影响) 127439148(ops/s) P9999=0.208(us/op) 依赖第三方号段分发器 受号段分发器可用性影响,但因安全距离存在,预留 ID 段,所以高于 SegmentId 是 64-bit 有序性 (要想分而治之・二分查找法,必须要维护我) 刚刚我们已经讨论了 ID 有序性的重要性,所以我们设计 ID 算法时应该尽可能地让 ID 是单调递增的,比如像表的自增主键那样。但是很遗憾,因全局时钟、性能等分布式系统问题,我们通常只能选择局部单调递增、全局趋势递增的组合(就像我们在分布式系统中不得不的选择最终一致性那样)以获得多方面的权衡。下面我们来看一下什么是单调递增与趋势递增。 有序性之单调递增 单调递增:T 表示全局绝对时点,假设有 Tn+1>Tn(绝对时间总是往前进的,这里不考虑相对论、时间机器等),那么必然有 F (Tn+1)>F (Tn),数据库自增主键就属于这一类。 另外需要特别说明的是单调递增跟连续性递增是不同的概念。 连续性递增:F(n+1)=(F(n)+step)即下一次获取的 ID 一定等于当前ID+Step,当Step=1时类似于这样一个序列:1->2->3->4->5。 扩展小知识:数据库的自增主键也不是连续性递增的,相信你一定遇到过这种情况,请思考一下数据库为什么这样设计? 有序性之趋势递增 趋势递增:Tn>Tn-s,那么大概率有 F (Tn)>F (Tn-s)。虽然在一段时间间隔内有乱序,但是整体趋势是递增。从上图上看,是有上升趋势的(趋势线)。 在SnowflakeId中 n-s 受到全局时钟同步影响。 在号段模式 (SegmentId) 中 n-s 受到号段可用区间 (Step) 影响。 分布式 ID 分配方案 UUID/GUID 不依赖任何第三方中间件 性能高 完全无序 空间占用大,需要占用 128 位存储空间。 UUID 最大的缺陷是随机的、无序的,当用于主键时会导致数据库的主键索引效率低下(为了维护索引树,频繁的索引中间位置插入数据,而不是追加写)。这也是 UUID 不适用于数据库主键的最为重要的原因。 SnowflakeId SnowflakeId使用Long(64-bit)位分区来生成 ID 的一种分布式 ID 算法。 通用的位分配方案为:timestamp(41-bit)+machineId(10-bit)+sequence(12-bit)=63-bit。 41-bittimestamp=(1L<<41)/(1000/3600/365),约可以存储 69 年的时间戳,即可以使用的绝对时间为EPOCH+69 年,一般我们需要自定义EPOCH为产品开发时间,另外还可以通过压缩其他区域的分配位数,来增加时间戳位数来延长可用时间。 10-bitmachineId=(1L<<10)=1024,即相同业务可以部署 1024 个副本 (在 Kubernetes 概念里没有主从副本之分,这里直接沿用 Kubernetes 的定义)。一般情况下没有必要使用这么多位,所以会根据部署规模需要重新定义。 12-bitsequence=(1L<<12)*1000=4096000,即单机每秒可生成约 409W 的 ID,全局同业务集群可产生4096000*1024=419430W=41.9亿(TPS)。 从SnowflakeId设计上可以看出: timestamp在高位,单实例SnowflakeId是会保证时钟总是向前的(校验本机时钟回拨),所以是本机单调递增的。受全局时钟同步 / 时钟回拨影响SnowflakeId是全局趋势递增的。 SnowflakeId不对任何第三方中间件有强依赖关系,并且性能也非常高。 位分配方案可以按照业务系统需要灵活配置,来达到最优使用效果。 强依赖本机时钟,潜在的时钟回拨问题会导致 ID 重复、处于短暂的不可用状态。 machineId需要手动设置,实际部署时如果采用手动分配machineId,会非常低效。 SnowflakeId 之机器号分配问题 在SnowflakeId中根据业务设计的位分配方案确定了基本上就不再有变更了,也很少需要维护。但是machineId总是需要配置的,而且集群中是不能重复的,否则分区原则就会被破坏而导致 ID 唯一性原则破坏,当集群规模较大时machineId的维护工作是非常繁琐,低效的。 有一点需要特别说明的,SnowflakeId的MachineId是逻辑上的概念,而不是物理概念。 想象一下假设MachineId是物理上的,那么意味着一台机器拥有只能拥有一个MachineId,那会产生什么问题呢? 目前CosId提供了以下五种MachineId分配器。 ManualMachineIdDistributor: 手动配置machineId,一般只有在集群规模非常小的时候才有可能使用,不推荐。 StatefulSetMachineIdDistributor: 使用Kubernetes的StatefulSet提供的稳定的标识 ID(HOSTNAME=service-01)作为机器号。 RedisMachineIdDistributor: 使用Redis作为机器号的分发存储,同时还会存储MachineId的上一次时间戳,用于启动时时钟回拨的检查。 JdbcMachineIdDistributor: 使用关系型数据库作为机器号的分发存储,同时还会存储MachineId的上一次时间戳,用于启动时时钟回拨的检查。 ZookeeperMachineIdDistributor: 使用ZooKeeper作为机器号的分发存储,同时还会存储MachineId的上一次时间戳,用于启动时时钟回拨的检查。 SnowflakeId 之时钟回拨问题 时钟回拨的致命问题是会导致 ID 重复、冲突(这一点不难理解),ID 重复显然是不能被容忍的。 在SnowflakeId算法中,按照MachineId分区 ID,我们不难理解的是不同MachineId是不可能产生相同 ID 的。所以我们解决的时钟回拨问题是指当前MachineId的时钟回拨问题,而不是所有集群节点的时钟回拨问题。 MachineId时钟回拨问题大体可以分为俩种情况: 运行时时钟回拨:即在运行时获取的当前时间戳比上一次获取的时间戳小。这个场景的时钟回拨是很容易处理的,一般SnowflakeId代码实现时都会存储lastTimestamp用于运行时时钟回拨的检查,并抛出时钟回拨异常。 时钟回拨时直接抛出异常是不太好地实践,因为下游使用方几乎没有其他处理方案(噢,我还能怎么办呢,等吧),时钟同步是唯一的选择,当只有一种选择时就不要再让用户选择了。 ClockSyncSnowflakeId是SnowflakeId的包装器,当发生时钟回拨时会使用ClockBackwardsSynchronizer主动等待时钟同步来重新生成 ID,提供更加友好的使用体验。 启动时时钟回拨:即在启动服务实例时获取的当前时钟比上次关闭服务时小。此时的lastTimestamp是无法存储在进程内存中的。当获取的外部存储的机器状态大于当前时钟时钟时,会使用ClockBackwardsSynchronizer主动同步时钟。 LocalMachineStateStorage:使用本地文件存储MachineState(机器号、最近一次时间戳)。因为使用的是本地文件所以只有当实例的部署环境是稳定的,LocalMachineStateStorage才适用。 RedisMachineIdDistributor:将MachineState存储在Redis分布式缓存中,这样可以保证总是可以获取到上次服务实例停机时机器状态。 SnowflakeId 之 JavaScript 数值溢出问题 JavaScript的Number.MAX_SAFE_INTEGER只有 53-bit,如果直接将 63 位的SnowflakeId返回给前端,那么会产生值溢出的情况(所以这里我们应该知道后端传给前端的long值溢出问题,迟早会出现,只不过 SnowflakeId 出现得更快而已)。 很显然溢出是不能被接受的,一般可以使用以下俩种处理方案: 将生成的 63-bitSnowflakeId转换为String类型。 直接将long转换成String。 使用SnowflakeFriendlyId将SnowflakeId转换成比较友好的字符串表示:{timestamp}-{machineId}-{sequence} -> 20210623131730192-1-0 自定义SnowflakeId位分配来缩短SnowflakeId的位数(53-bit)使ID提供给前端时不溢出 使用SafeJavaScriptSnowflakeId(JavaScript安全的SnowflakeId) 号段模式(SegmentId) 从上面的设计图中,不难看出号段模式基本设计思路是通过每次获取一定长度(Step)的可用 ID(Id 段 / 号段),来降低网络 IO 请求次数,提升性能。 强依赖第三方号段分发器,可用性受到第三方分发器影响。 每次号段用完时获取NextMaxId需要进行网络 IO 请求,此时的性能会比较低。 单实例 ID 单调递增,全局趋势递增。 从设计图中不难看出Instance 1每次获取的NextMaxId,一定比上一次大,意味着下一次的号段一定比上一次大,所以从单实例上来看是单调递增的。 多实例各自持有的不同的号段,意味着同一时刻不同实例生成的 ID 是乱序的,但是整体趋势的递增的,所以全局趋势递增。 ID 乱序程度受到 Step 长度以及集群规模影响(从趋势递增图中不难看出)。 假设集群中只有一个实例时号段模式就是单调递增的。 Step越小,乱序程度越小。当Step=1时,将无限接近单调递增。需要注意的是这里是无限接近而非等于单调递增,具体原因你可以思考一下这样一个场景: 号段分发器 T1 时刻给Instance 1分发了ID=1,T2 时刻给Instance 2分发了ID=2。因为机器性能、网络等原因,Instance 2网络 IO 写请求先于Instance 1到达。那么这个时候对于数据库来说,ID 依然是乱序的。 号段链模式(SegmentChainId) 分布式 ID (CosId) 之号段链模式性能 (1.2 亿 /s) 解析 SegmentChainId是SegmentId增强版,相比于SegmentId有以下优势: 稳定性:SegmentId的稳定性问题(P9999=46.624 (us/op))主要是因为号段用完之后同步进行NextMaxId的获取导致的(会产生网络 IO)。 SegmentChainId(P9999=0.208 (us/op))引入了新的角色PrefetchWorker用以维护和保证安全距离,理想情况下使得获取 ID 的线程几乎完全不需要进行同步的等待NextMaxId获取,性能可达到近似AtomicLong的TPS 性能:12743W+/sJMH 基准测试。 适应性:从SegmentId介绍中我们知道了影响ID 乱序的因素有俩个:集群规模、Step大小。集群规模是我们不能控制的,但是Step是可以调节的。 Step应该近可能小才能使得ID 单调递增的可能性增大。 Step太小会影响吞吐量,那么我们如何合理设置Step呢?答案是我们无法准确预估所有时点的吞吐量需求,那么最好的办法是吞吐量需求高时,Step 自动增大,吞吐量低时 Step 自动收缩。 SegmentChainId引入了饥饿状态的概念,PrefetchWorker会根据饥饿状态检测当前安全距离是否需要膨胀或者收缩,以便获得吞吐量与有序性之间的权衡,这便是SegmentChainId的自适应性。 集成 CosIdPlugin(MyBatis 插件) Kotlin DSL implementation("me.ahoo.cosid:cosid-mybatis:${cosidVersion}") public class Order { @CosId(value = "order") private Long orderId; private Long userId; public Long getOrderId() { return orderId; } public void setOrderId(Long orderId) { this.orderId = orderId; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } } ShardingSphere 插件 CosIdKeyGenerateAlgorithm、CosIdModShardingAlgorithm、CosIdIntervalShardingAlgorithm已合并至ShardingSphere官方,未来cosid-shardingsphere模块的维护可能会以官方为主。 Kotlin DSL implementation("me.ahoo.cosid:cosid-shardingsphere:${cosidVersion}") CosIdKeyGenerateAlgorithm (分布式主键) spring: shardingsphere: rules: sharding: key-generators: cosid: type: COSID props: id-name: __share__ 基于间隔的时间范围分片算法 易用性:支持多种数据类型 (Long/LocalDateTime/DATE/String/SnowflakeId),而官方实现是先转换成字符串再转换成LocalDateTime,转换成功率受时间格式化字符影响。 性能:相比于org.apache.shardingsphere.sharding.algorithm.sharding.datetime.IntervalShardingAlgorithm性能高出1200~4000倍。 PreciseShardingValue RangeShardingValue CosIdIntervalShardingAlgorithm type: COSID_INTERVAL SnowflakeIntervalShardingAlgorithm type: COSID_INTERVAL_SNOWFLAKE spring: shardingsphere: rules: sharding: sharding-algorithms: alg-name: type: COSID_INTERVAL_{type_suffix} props: logic-name-prefix: logic-name-prefix id-name: cosid-name datetime-lower: 2021-12-08 22:00:00 datetime-upper: 2022-12-01 00:00:00 sharding-suffix-pattern: yyyyMM datetime-interval-unit: MONTHS datetime-interval-amount: 1 取模分片算法 性能:相比于org.apache.shardingsphere.sharding.algorithm.sharding.mod.ModShardingAlgorithm性能高出1200~4000倍。并且稳定性更高,不会出现严重的性能退化。 PreciseShardingValue RangeShardingValue spring: shardingsphere: rules: sharding: sharding-algorithms: alg-name: type: COSID_MOD props: mod: 4 logic-name-prefix: t_table_ 性能测试报告 SegmentChainId - 吞吐量 (ops/s) SegmentChainId - 每次操作耗时的百分位数 (us/op) 百分位数,统计学术语,若将一组数据从小到大排序,并计算相应的累计百分点,则某百分点所对应数据的值,就称为这百分点的百分位数,以 Pk 表示第 k 百分位数。百分位数是用来比较个体在群体中的相对地位量数。

优秀的个人博客,低调大师

PaySDK v2.1.0 发布,轻松兼容各大 Swoole 框架

PaySDK 是 PHP 集成支付 SDK ,集成了支付宝、微信支付的支付接口和其它相关接口的操作。可以轻松嵌入支持 PHP >= 5.4 的任何系统中,2.0 版现已支持 Swoole 协程环境。 我们有完善的在线技术文档:http://doc.yurunsoft.com/PaySDK API 文档:https://apidoc.gitee.com/yurunsoft/PaySDK 大家在开发中肯定会对接各种各样的支付平台,我个人精力有限,欢迎各位来提交 PR (码云/Github),一起完善 PaySDK ,让它能够支持更多的支付平台,更加好用。 更新日志(v2.1.0) 优化 Swoole 环境下使用体验,支持 PSR-7 标准的 Request 和 Response Swoole 协程环境支持 在WorkerStart事件中加入: \Yurun\Util\YurunHttp::setDefaultHandler('Yurun\Util\YurunHttp\Handler\Swoole'); 在支付、退款异步通知中,需要赋值Swoole的Request和Response对象,或者遵循 PSR-7 标准的对象即可。 imi 框架中使用 imi 是基于 PHP Swoole 的高性能协程应用开发框架,它支持 HttpApi、WebSocket、TCP、UDP 服务的开发。 在 Swoole 的加持下,相比 php-fpm 请求响应能力,I/O密集型场景处理能力,有着本质上的提升。 imi 框架拥有丰富的功能组件,可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。可以使企业 IT 研发团队的效率大大提升,更加专注于开发创新产品。 https://www.imiphp.com/ /** * 这是一个在控制器中的动作方法 * @Action */ public function test() { $payNotify = new class extends \Yurun\PaySDK\Weixin\Notify\Pay { /** * 后续执行操作 * @return void */ protected function __exec() { } }; $context = RequestContext::getContext(); // 下面两行很关键 $payNotify->swooleRequest = $context['request']; $payNotify->swooleResponse = $context['response']; $sdk->notify($payNotify); // 这句话必须填写 $context['response'] = $payNotify->swooleResponse; } 其它框架(Swoole 对象) $payNotify = new class extends \Yurun\PaySDK\Weixin\Notify\Pay { /** * 后续执行操作 * @return void */ protected function __exec() { } }; // 下面两行很关键,$request、$response 从 request 中获取 // 或者查阅如何从你使用的框架中获取 $payNotify->swooleRequest = $request; $payNotify->swooleResponse = $response; $sdk->notify($payNotify); 其它框架(PSR-7 对象) $payNotify = new class extends \Yurun\PaySDK\Weixin\Notify\Pay { /** * 后续执行操作 * @return void */ protected function __exec() { } }; // 目前主流 Swoole 基本都支持 PSR-7 标准的对象 // 所以可以直接传入,如何获取请查阅对应框架的文档 $payNotify->swooleRequest = $request; $payNotify->swooleResponse = $response; $sdk->notify($payNotify); // 处理完成后需要将 $response 从控制器返回或者赋值给上下文 // 不同框架的操作不同,请自行查阅对应框架的文档 return $payNotify->swooleResponse; 支持的支付接口 支付宝 即时到账-电脑网站支付(老) 即时到账-手机网站支付(老) 当面付 手机网站支付 电脑网站支付 APP支付服务端 单笔转账到支付宝账户 海外支付(电脑网站、手机网站、APP、扫码) 海关报关 其它辅助交易接口(退款、查询等) 微信支付 刷卡支付 公众号支付 扫码支付 APP支付 H5支付 小程序支付 企业付款到零钱 企业付款到银行卡 海外支付(刷卡、公众号、扫码、APP) 海关报关 其它辅助交易接口(退款、查询等) 安装 在您的composer.json中加入配置: { "require": { "yurunsoft/pay-sdk": "~2.1" } } 然后执行composer update命令。 代码示例 支付宝即时到账 // SDK实例化,传入公共配置 $pay = new \Yurun\PaySDK\Alipay\SDK($params); // 支付接口 $request = new \Yurun\PaySDK\Alipay\Params\Pay\Request; $request->notify_url = ''; // 支付后通知地址(作为支付成功回调,这个可靠) $request->return_url = ''; // 支付后跳转返回地址 $request->businessParams->seller_id = $GLOBALS['PAY_CONFIG']['appid']; // 卖家支付宝用户号 $request->businessParams->out_trade_no = 'test' . mt_rand(10000000,99999999); // 商户订单号 $request->businessParams->total_fee = 0.01; // 价格 $request->businessParams->subject = '测试商品'; // 商品标题 // 跳转到支付宝页面 $pay->redirectExecute($request); 支付宝手机网站支付 // SDK实例化,传入公共配置 $pay = new \Yurun\PaySDK\AlipayApp\SDK($params); // 支付接口 $request = new \Yurun\PaySDK\AlipayApp\Wap\Params\Pay\Request; $request->notify_url = ''; // 支付后通知地址(作为支付成功回调,这个可靠) $request->return_url = ''; // 支付后跳转返回地址 $request->businessParams->out_trade_no = 'test' . mt_rand(10000000,99999999); // 商户订单号 $request->businessParams->total_amount = 0.01; // 价格 $request->businessParams->subject = '小米手机9黑色陶瓷尊享版'; // 商品标题 // 跳转到支付宝页面 $pay->redirectExecute($request); 微信H5支付 // SDK实例化,传入公共配置 $pay = new \Yurun\PaySDK\Weixin\SDK($params); // 支付接口 $request = new \Yurun\PaySDK\Weixin\H5\Params\Pay\Request; $request->body = 'test'; // 商品描述 $request->out_trade_no = 'test' . mt_rand(10000000,99999999); // 订单号 $request->total_fee = 1; // 订单总金额,单位为:分 $request->spbill_create_ip = '127.0.0.1'; // 客户端ip $request->notify_url = ''; // 异步通知地址 // 调用接口 $result = $pay->execute($request); if($pay->checkResult()) { // 跳转支付界面 header('Location: ' . $result['mweb_url']); } else { var_dump($pay->getErrorCode() . ':' . $pay->getError()); } exit;

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册