问题描述:游戏斗地主,血战麻将都用到了自动分配的功能,自动分配即为用户点击开始游戏,服务端将用户添加至分配列表中,分配列表为N秒轮循一次进行分配.而这两款游戏都出现了机器人断线的问题,经排查有如下问题:
A.斗地主的问题:斗地主的机器人逻辑是重新开发完成的,老版的AI逻辑只有在新版AI逻辑出现异常的时候才会使用到.
A.1.斗地主AI逻辑可能出现异常
问题还原:经排查为机器人出现断线的情况下,游戏开始之后,AI类的逻辑中将无法正常接收到游戏消息,例如游戏的开始消息,而当机器人重新返回游戏中时,已经错过了游戏开始设置相关数据的最佳时间,这就导致新版AI在没有设置相关数据的情况下进行运行,就会出现异常。
解决方案:在三个不同的游戏场景时,服务端增加了向机器人发送游戏开始设置数据,这将解决机器人断线时,无法正常设置游戏开始数据,但这样的办法并不能解决根本的问题,因为根本的问题是机器人掉线,后面我们将分析记录机器人掉线的原因,而游戏AI逻辑里也必须这样做。
B.血战麻将的问题:血战麻将目前发现了5个问题.
B.1.AI逻辑可能出现出牌位置异常,意思就是说本来不该由机器人A出牌,但是A出了一张牌,这并不会导致程序异常,但这对于AI逻辑的运行来说,并不是什么好事。
问题还原:当机器人A打出一张9筒,机器人B胡9筒,机器C碰9筒,哪么B和C都将得到扑克操作提示的动作,按照程序的预设逻辑,应该是B胡牌的优先级高于C碰牌,也就是只有当B放弃胡牌时,C才能碰牌,而目前的情况是,B和C都得到操作扑克的提示之后,都相应的创建了属于自己的操作定时器(N秒后执行扑克操作),机器人B使用了胡牌操作,而机器人C应当使用放弃和碰牌的操作,但是机器人C并没有这么做,而是选择了出牌操作,这就导致了B.1出现的问题,经排查原来是因为AI逻辑出牌方法中的一段出牌代码并没有进行操作类型判断,当为胡,杠,碰的操作时是不能出牌。
解决方案:AI操作扑克逻辑中,增加当操作类型为胡,杠,碰时不能进行出牌操作的代码.
B.2.当使用相同的游戏数据进行挂机测试时,AI代码运行也会出现异常的情况,经排查应该也是由于机器人断线导致的问题.
问题还原:使用相同的游戏数据进行测试,只是为了验证是否是因为不同的游戏数据导致了AI逻辑运行错误,现已排除这个问题.
解决方案:解决机器人掉线的问题即可(还需挂机测试进行验证).
B.3.自动分组的模式下,可能出现用户坐下失败的情况
问题还原:这个问题应该是由于目前服务端代码版本的问题导致,在分配用户坐下时,使用了前一个版本的人数判断,即组里用户大于3人时就进行分组.
解决方案:将人数判断修改为最小分配人数即可(还需要挂机测试)。
B.4.游戏桌上只剩余3个机器人,并且桌子的状态为游戏状态,好像卡了的问题
问题还原:引起这个问题的原因是机器人做了杠牌动作引起,具体场景如下:
B.4.1.例如机器人用户1手牌中有3个二筒,系统向用户1派发扑克时,发了一张二筒.
B.4.2.此时系统判定用户1可以做杠牌的操作,将用户的操作类型设置为杠牌操作(此时用户可以直接出牌或杠牌的操作)
B.4.3.系统创建出牌超时定时器(注意是创建了出牌定时器,而不是操作定时器,这里是造成游戏无法正常进行的原因,后面会继续说明这个BUG)
B.4.4.机器人接到发牌消息之后,没有选择碰牌或杠牌,而是选择了出其它的牌(非二筒),此时机器人手上有4个二筒.
B.4.5.一轮发牌结束后,系统向此机器人发送扑克,并重复了B.4.3的操作.
B.4.6.例如此时机器人接到系统发送的1万,因为上一轮机器人有4个人筒,没有进行碰牌或杠牌操作,这一轮机器人仍然获得了杠牌的状态.机器人进行了杠牌请求,注意就是这里,当机器人向服务端发送杠牌操作时,由于这一轮发送的扑克为1万,服务端在判断时发现,操作的扑克为二筒,并不等于系统这一轮发送出去的1万,于是返回了处理(不继续往下处理了,但是已经将用户手中的四个二筒删除了)(大致逻辑就这样).
B.4.7.由于B.4.3创建的出牌定时器,所以此时服务端代替机器人打出了扑克,由于某个原因,导致异常返回(具体原因已记不清了).
B.4.8.经过以上流程之后,系统处于了没有任何状态,这也是导致游戏无法进行下去的原因.
解决方案:修复机器人断线的问题,上线正式环境验证是否还存在这个问题.
B.5.服务端程序卡死的问题
问题还原:导致卡死的原因有多个,如While死循环,指针异常等,目前还无法确定是哪个部分引起的问题
解决方案:修复机器人断线的问题,上线正式环境验证是否还存在这个问题.
C.机器人断线的问题(断线的原因是由于删除了机器人导致的).
C.1.删除机器人的几个场景
a.机器人服务时间到期,
a.1.机器人服务时间到期,删除机器人先进行状态判定,当机器人为站立,坐下状态(即非游戏状态)时,才能删除机器人.
a.2.机器人服务时间段过期,基于非游戏状态,强制删除机器人(这个逻辑暂时是注释掉的,是为了解决飞禽到整点机器人全部出房间的问题).
b.游戏消息异常导致。
b.1.机器人管理类向机器人AI发送数据出现异常或者失败时.
b.2.机器人AI向服务端发送数据出现异常或者失败时.
c.系统关闭消息。
c.1.服务端向机器人发送了某一个带有关闭游戏或者房间的系统消息.
经排查以上三种情况,删除机器人导致掉线属于a的场景,这个问题出现的算是比较极限,具体逻辑如下(以下数据展示均为实际测试日志数据):
场景还原: a.某机器人A在20:30:49:952(时间精确到毫秒)分时做了服务时间到期退出处理,此时机器人的用户状态为站立.
b.在20:30:49:952时向IO投递了删除机器人A的命令.
c.在20:30:50:732时自动分组将机器人A分配并坐下(至此时机器人并未删掉,并且用户状态为站立).
d.在20:30:51.272时,服务端接到底层IO调用了关闭事件,即机器人A关闭的处理(机器人删除的后续操作,如从机器人管理列表中删除机器人,设置机器人状态等都是在这里面处理).
e. 在20:42:27.642时,设置用户断线状态(这里时间与d相差很大是因为我调试停留导致的延迟,正常时间间隔不到1秒).
问题分析:根据场景还原的日志链可得出,a,b两个步骤是因为机器人A服务时间到期,并且用户状态为非游戏状态,并得到了删除,而在投递删除命令之后,步骤c进行了自动分配,因为b投递之后,d并没有马上调用,这可能是IO阻塞或IO队列数据较多造成的短暂延时,正是由于这不到1秒的延时,导致c进行了分配,c将用户进行分配之后,游戏就开始了,哪么机器人A的状态变更为"站立->坐下->游戏",当d调用时,机器人A的用户状态为游戏状态,根据预设的逻辑,此时系统删除机器人时发现机器人的状态为游戏状态,只能将用户设置为断线状态.至此机器人断线的问题水落石出.
解决方案:在分配机器人时,计算计机器人的服务到期时间,例如机器人的服务到期时间为100,哪么当时间到95的时候,机器人则就不往游戏队列中分配,这样就解决机器人断线的问题.为什么是5秒?正常情况提高1秒或不提高都没问题,提升到5秒只是为了提高容错率,如果IO非常慢高于1秒呢?是吧!