@yanglfyangl
2018-07-31T07:45:14.000000Z
字数 3395
阅读 455
可能出现的问题:
1 . 数据可能被篡改。
1. 如果接口中直接传钱数,就可能在某种情况下被截获和修改。2. 或本来不属于某个用户的订单,因为被截获,导致TA来支付,导致的一系列问题。
2 . 接口不幂等,重复扣/加钱或豆。
1. 比如扣款请求已经被服务器端正确处理,但服务器端的返回结果由于网络等原因被掉丢了,导致客户端无法得知处理结果。这时候客户端重试了,导致了扣款两次。2. 如果流程更长,特别是有写统计数据的地方(比如总钱数,当前可用钱数。。。),也容易造成类似的问题。
3 . 状态不同步/消息不一致造成的各种问题。
1. 比如因为网络原因,服务A没有把支付完成的消息实时反馈给服务B。2. 或服务器A通知了,但服务器B处理失败了。3. 最复杂的是服务A发了消息,成功了。但因为网络原因他不知道,以为发送失败了,又做了重试。
当然,还有“安全风控等一系列问题,但因为更多的是产品逻辑上的,在这里不多说了”
需要在开发中注意的地方
防数据篡改:
1. 以订单ID为参数,尽量避免钱数或其它信息做为参数,给外界系统以更改的机会。2. 更加严格的参数校验,比如订单与用户的关系,订单状态。。。3. 加风控。。。
幂等:
1. 每个可能更改数据的地方,都需要用幂等保护起来,同一个“事件”的数据处理,只执行一次。
状态不同步:
1. 消息发送失败时要支持重试。(但前提是一定要消息消费方保证幂等)2. 消息服务器如果出问题,需要有相应的补偿机制。3. 接口层发消息的同时,也要支持拉取消息。
当然,这也就要求了在写代码之前,要想清楚
1. 到底是TCC?2. 还是最终一致性?3. 还是全不走,但能提供各种业务补偿来去支持失败?
每种做法都会导致代码结构和量级很不一样,所以这些需要提前设计好。
与社交相关的数据库表:
1. 账户表2. 圈子账户表3. 平台账户表4. 账户银行卡对应表5. 账户流水表6. 账户盈豆表7. 盈豆奖励明细表8. 盈豆交易变动流水9. 账户赢币表10. 账户赢币奖励明细表11. 盈币交易变动流水
还有几张与社交无关的
1. SBU-账户2. 账户-供应商3. 生豆交易变动流水4. 账户生豆奖励明细表5. 账户生豆表。。。
在有些表中,有些数据是“计算”的数据(相对容易出现不一致和不幂等的部分)
USABLE_BEANS DECIMAL(20, 4) COMMENT '生豆余额',FREEZE_BEANS DECIMAL(20, 4) COMMENT '冻结余额',UNCLEARED_BEANS DECIMAL(20, 4) COMMENT '未清算余额',PROFIT_BEANS DECIMAL(20, 4) COMMENT '收益豆',
查询条件比较复杂,目前看分片分库分表等都不容易处理。未来的查询是个问题。
AccountBlanceWithdrawalProvide 中@Overridepublic Response<BalanceWithdrawalVo> withdrawal(Request<BalanceWithdrawalDto> req) {BalanceWithdrawalDto dto = req.getData();LogMgr.error("*********余额提现*******参数:"+FastJsonUtil.parseToJSON(req.getData()));。。。。。。try {//校验Response<Integer> validateRes = withdrawalValidate(dto);if(!validateRes.isSuccess()) {response.failure(validateRes.getErrorCode(), validateRes.getErrorMsg());return response;}...accountBlanceWithdrawalService.insert(entity);LogMgr.sysInfo(dto.getmId()+"*********************余额提现记录插入成功**********************"+FastJsonUtil.parseToJSON(entity));// 返回结果封装startLogMgr.sysInfo(dto.getmId()+"*********************余额提现**********************"+FastJsonUtil.parseToJSON(dto));。。。。。。//插入订单PayOrder order = new PayOrder();。。。。。。payOrderService.save(order);//插入订单// 保存到数据库LogMgr.error(dto.getmId()+"*********余额提现*******返回:"+FastJsonUtil.parseToJSON(response));}catch(Exception e) {LogMgr.error("*********余额提现*******异常:"+e.getMessage(),e);response.failure("500",e.getMessage());}return response;}
这个代码中,有这样几个问题
这样的代码还是挺多的存在于目前的支付中的。
。。。。。。。}//事务性消息通知结成功JSONObject jsonObject = new JSONObject();jsonObject.put("businessId", frozenAccountDto.getBusinessId());jsonObject.put("businessType", frozenAccountDto.getBusinessType());jsonObject.put("amount", frozenRecord.getAmount().toString());jsonObject.put("channel", frozenAccountDto.getChannel());SendResult sendFrozenBalance = payNotifyProductor.sendFrozenBalance("frozenBalance", jsonObject.toJSONString(), frozenRecord.getBusinessType());LogMgr.sysInfo("PayFrozenThaw.provide:frozenBalance:发送MQ",FastJsonUtil.parseToJSON(sendFrozenBalance));}catch (Exception e) {res.setErrorCode(ResponseConstant.BASE_SERVICE_ERROR_CODE);res.setErrorMsg(ResponseConstant.map.get(ResponseConstant.BASE_SERVICE_ERROR_CODE));LogMgr.sysInfo("PayConsolidate.provide:payUseFrozenBalance:出参",FastJsonUtil.parseToJSON(req));return res;}finally {try {distributedLock.unLock(lockKey.toString());}catch (CacheException e) {LogMgr.error("payUseFrozenBalance>>>请求解锁失败>>>>>>>>>>>>>>>>>>>>解锁失败-解锁失败e:{}",e);}}
这代码中注释虽然写的是“事务性消息”,但消息的出错处理没有,也不能抛出异常。。。所以。。。