USSD应用短码生成、过期与失效架构优化方案咨询
USSD支付短码系统优化建议
需求概述
- 用户与药房从业者通话后生成4/5位数字短码,用于支付流程(系统通过短码匹配对应支付金额)
- 短码规则:72小时自动过期,或使用后立即失效
- 设计目标:降低用户输入错误,保证短码唯一、高效生成与生命周期管理
当前实现方案
- 采用二次剩余算法生成4位随机唯一短码
- 短码及关联用户数据存储于Redis,设置72小时过期时间,未新增MySQL表或字段
- 分配短码前检查Redis确保唯一性
- 短码一经使用立即从Redis移除
当前短码生成代码(中文注释)
import random import math def is_prime(n): """判断一个数是否为质数""" if n < 2: return False for i in range(2, int(math.sqrt(n)) + 1): if n % i == 0: return False return True def generate_random_prime(): """生成一个1000到9999之间的随机质数""" while True: prime_number = random.randint(1000, 9999) if is_prime(prime_number): return prime_number def generate_quadratic_residue(prime_number): """生成一个模质数的随机二次剩余""" while True: quadratic_residue = random.randint(1, prime_number - 1) if (quadratic_residue ** 2 % prime_number != 1): return quadratic_residue def generate_unique_code(): """使用二次剩余生成唯一4位短码""" prime = generate_random_prime() quadratic_residue = generate_quadratic_residue(prime) code = str(quadratic_residue).zfill(4) return code
架构优化建议
一、短码生成效率与唯一性优化
替换二次剩余算法,提升生成速度
当前算法依赖随机质数生成,循环判断质数的逻辑在高并发场景下会出现性能瓶颈。推荐两种更高效的方案:- 预生成短码池:提前批量生成所有可用的4/5位数字短码(4位共9000个,5位共90000个),存入Redis列表中,分配时直接从列表头部弹出。通过Celery定时任务定期补充已耗尽的短码池,避免实时计算开销。
- 定制化短码生成器:基于时间戳+自增序列实现简化版生成逻辑,比如取最近N位时间戳与自增数拼接后取模,确保在4/5位范围内且唯一,适合高并发场景下的快速生成。
解决并发竞态问题
当前“检查Redis→生成短码→存入Redis”的流程存在并发冲突风险,高并发下可能出现重复短码。建议改用Redis的SETNX命令:将短码作为键,关联的用户/金额数据作为值,同时设置72小时过期时间。若SETNX返回成功则分配完成,失败则重新获取新短码,一步完成唯一性校验与存储,彻底避免竞态。
二、短码生命周期管理优化
强化过期清理机制
Redis的过期清理是惰性删除+定期扫描,可能存在过期短码未及时清理的情况。补充两个兜底方案:- 通过Celery定时任务每日扫描Redis中的短码键,主动删除已过期的条目,释放内存空间。
- 新增MySQL归档表
ussd_payment_codes,记录短码的code、user_id、amount、expire_time、used_time、status等字段,当支付状态变更(已支付/取消)时,通过RabbitMQ发送事件,触发Celery异步删除Redis中对应短码,同时更新归档表状态。
使用后的联动处理
短码使用后除了移除Redis数据,还需:- 将短码使用记录同步到MySQL归档表,用于后续对账、审计和业务分析。
- 通过RabbitMQ发送消息通知药房端系统更新订单状态,实现支付流程闭环。
三、扩展性与容错优化
支持短码位数动态切换
在配置文件中增加短码位数开关(4位/5位),生成逻辑根据配置动态调整范围,无需修改核心代码,适配用户量增长后的需求变化。增加重试与容错机制
当短码生成或存储失败时,通过Celery异步重试(设置最大重试次数),避免用户端收到错误提示;同时记录失败日志,便于排查问题。
内容的提问来源于stack exchange,提问作者Jean-José GBETO
相关产品推荐
相关产品推荐

