天天飞车弱网络环境重复请求解决方案
移动网络的不稳定性,对接入层设计的影响,是手游和端游最大的区别之一。本文针对弱网络下重复发包导致的问题,对天天飞车的解决方案进行介绍。
问题定义
在弱网络环境下,手游客户端往服务器发送请求并等待回复的过程中,上行的请求包和下行的回复包都有可能因网络波动导致丢失。
上行包丢失:
这种情况下服务器并未收到请求协议,客户端只需要重新请求即可。
下行包丢失:
服务器已经收到请求协议并处理,但是由于没有收到回复,客户端不知道服务器是否已处理以及处理的返回数据是什么。如果只是单纯的再次请求,有可能导致业务逻辑上的错误。例如天天飞车单局内的购买燃油请求,在这种情况下服务器会有两次扣除费用的操作,但是客户端只能收到一次购买的回复,导致玩家利益受损。
关键请求和非关键请求
首先要意识到,并不是所有的请求都会收到上述问题影响。正如上面所说,下行包丢失最大的影响是在于玩家多次消耗没有对应收到多次的收益。收益实际到帐并且玩家可以通过重新登陆等同步数据的操作确认收益的请求在业务层面不会有太大的问题,这些属于非关键请求。典型的有在大厅内购买道具、领取任务奖励等。
对于客户端没有收到回复,又没有额外的数据同步点的请求,则属于关键请求,如天天飞车单局内的购买燃油。这类请求则需要有相应的机制保护。
解决方案
要解决关键请求下行包丢失后重复发包的问题,要提供以下几项措施:
1. 识别重复的请求
我们用<协议ID, 序列号>的二元组对请求进行标识,如果当前收到的请求的二元组数据和上一次处理的请求一样,则可以认为是重复的请求。
2. 避免重复请求的逻辑错误
其实重复的请求本质上是上一次请求的历史回放,应对回放的请求,最直接的解决方案就是返回回放的回复数据。因此只需要在逻辑处理完“非重复请求”后以及将回复数据提交网络层返回客户端之前,对回放数据进行缓存,在后续遇到这次回复的重复请求时,绕过逻辑处理,直接将之前缓存的回复数据返回客户端即可。
3. 客户端提供锁定机制
在客户端发送关键请求后,在收到回复或者请求超时之前,应该对UI交互进行锁定,一方面确保关键请求都是串行上报和处理的,另一方面也能避免用户意外多次点击造成多次请求(实际上除非策划层面有特殊要求,我们建议所有玩家手动点击触发的请求都应该加上这层保护)。在请求超时后,可以通过提示“是否重试”的方式,引导玩家手动触发重发,以确认玩家意图和实际的请求一一对应,并且在请求中带上和之前相同的序列号,以便服务器识别为重复请求。
调整后的请求处理流程如下图所示。
总结
本文介绍的方案只是单纯针对重复发包的问题,弱网络的影响不仅于此,不同的游戏类型在不稳定、高延迟的移动网络环境下都面临着不同的问题和挑战,欢迎各位抛出问题一起探讨。