解决高频热点账户问题通常需要从以下几个方面入手:
1. "账户异常检测":
- "技术手段":利用大数据分析、机器学习等技术,对账户行为进行实时监控,发现异常行为模式。
- "规则设置":根据业务特点,设置合理的账户行为规则,如登录频率、交易金额、IP地址等。
2. "安全措施加强":
- "多因素认证":采用多因素认证(MFA)来提高账户安全性。
- "密码策略":实施强密码策略,定期更换密码,并禁止使用弱密码。
- "安全通知":对账户异常行为及时发送安全通知,提醒用户关注。
3. "用户教育":
- "安全意识培训":定期对用户进行网络安全意识培训,提高用户的安全防范能力。
- "风险提示":在用户登录、交易等环节,提供风险提示,增强用户的风险识别能力。
4. "账户管理优化":
- "账户分级管理":根据用户的风险等级,实施不同的账户管理策略。
- "权限控制":对账户的权限进行严格控制,避免权限滥用。
5. "技术支持":
- "系统升级":定期对系统进行升级,修复已知的安全漏洞。
- "安全防护":部署防火墙、入侵检测系统等安全设备,提高系统的安全性。
6. "应急响应":
相关内容:
金融账户系统的特点是并发量大、响应快、交易金额大,热点账户问题突出。一个合格的账户系统既要解决上述问题,又必须绝对保证资金安全。
记账分录
充值
借方:三方支付待清算账户(+)贷方:个人余额账户(+)三方支付的待清算账户是热点账户,频繁的增加余额。提现
借方:个人余额账户(-)贷方:三方支付资产账户(-)三方支付的资产账户是热点账户,频繁的减少余额。服务费收款
借方:个人账户(-)贷方:商户服务费账户(+)商户服务费账户就是热点账户,会频繁增加余额。服务费付款
借方:商户服务费账户(-)贷方:个人账户(+)商户服务费账户就是热点账户,会频繁减少余额。记账时,所有涉及的账户余额都要做update更新,高并发情况下,当出现上述类型的热点账户时,由于数据库的行级锁,对同一账户的更新余额操作由并行变成串行,单个请求的响应时间变长,从而拖垮整个记账服务。解决思路
把热点账户按照金额变动方向分为三种账户:- 加频账户(余额增加频繁)
- 减频账户(余额扣减频繁)
- 双频账户(余额增加扣减均频繁)
加频账户
采用准实时更新余额,先将金额变动插入临时表中,由定时任务按照一定频率汇总发生额,并更新账户余额,而后删除临时记录。当加频账户减钱余额不足时,主动去汇总发生额。需要考虑主动汇总发生额和定时任务处理的并发情况,在该定时任务执行时设置redis锁,防止并发。主动汇总时会去判断这个redis锁是否存在,如存在证明定时任务正在执行,无需主动汇总,可能是真的余额不足。主动汇总同样会设置redis锁,定时任务同样会判断。减频账户
将减频账户拆分多个子账户,减频子账户设置金额报警,如果某个减频子账户余额不足触发报警,会对该子账户做资金归集,将其他子账户余额归集到该子账户(每个子账户设置可归集金额限制)。如在交易过程中发现该子账户余额不足,转向使用其他子账户记账。由于拆分子账户,余额查询时需要汇总各个子账户余额返回。记录主账户流水需要记账后余额,这里需要异步计算汇总。当减频账户加钱时,需要平均分配入账到不同的子账户。双频账户
将双频账户拆分多个子账户。加钱时,准实时更新余额,先将子账户金额变动插入临时表中,由定时任务按一定频率汇总发生额,将汇总的发生额更新进对应的子账户,并删除金额变动记录。减钱按照之前减频账户的逻辑执行。记账死锁问题
高并发情况下,当多个账户之前互相转账时,可能会出现死锁问题。A账户和B账户双方转账请求并发,账户系统对每个转账请求都会更新A、B余额,这两个更新需要在一个事务里,正常流程线程1先更新A,再更新B,线程2先更新B,再更新A,线程1更新完A后会等待B的锁,不提交事务,线程2更新完B后会等待A的锁,不提交事务,这样两个线程互相等待锁,造成死锁。思路
解决死锁的最好办法就是避免死锁,避免死锁要从产生死锁的条件入手:- 互斥:共享资源X和Y只能被一个线程占用
- 占有且等待:线程T1已经取得共享资源X,在等待共享资源Y的时候,不释放共享资源X
- 不可抢占:其他线程不能强行抢占T1占有的资源
- 循环等待:线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源,就是循环等待
破坏占用且等待
只需要同时申请资源就可以,同时申请这个操作是一个临界区,需要一个Java类来管理这个临界区,同时申请资源apply()和同时释放资源free()。通过增加一个 Allocator 账号管理员对象,并且将其设置为单例,每次进行转账的时候,我们都先通过 Allocator 分配账号,如果分配账号成功,则进行转账,如果失败则重新获取,可以设置一个失败次数或是超时时间,达到失败次数或超时时间则转账失败。破坏不可抢占条件
对于不可抢占,可以获取了部分资源,再进一步获取其他资源时如果获取不到时,把已经获取的资源一起释放掉。java.util.concurrent中的Lock接口,提供了如下三种设计思想都可以解决死锁的不可抢占条件:- 能够响应中断:线程处于阻塞状态时可以接收中断信号。我们便可以给阻塞的线程发送中断信号,唤醒线程,线程便有机会释放它曾经拥有的锁。这样便可破坏不可抢占条件。
- 支持超时:如果线程在一段时间之内没有获取到锁,不是进入阻塞状态,而是返回一个错误,那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。
- 非阻塞获取锁:如果尝试获取锁失败,并不进入阻塞状态,而是直接返回,那这个线程也有机会释放曾经持有的锁。这样也可以破坏不可抢占条件。
破坏循环等待条件
对于循环等待,可以将需要获取的锁资源排序,按照顺序获取,这样就不会多个线程交叉获取相同的资源导致死锁,而是在获取相同的资源时就等待,直到它释放。比如根据账号的主键 id 进行排序,从小到大的获取锁,这样就可以避免循环等待。