一套C/S模式日志上传的机制

1.背景

一个客户端-服务器模式的游戏,将会有非常多的玩家使用不同的客户端在一起进行游戏,如果想要根据不同玩家的操作来对玩家进行分类,比如数据分析师想要知道某些玩家偏好哪些功能,某些玩家不喜欢哪些功能,就需要记录这些玩家的给各类点击操作。
在这里插入图片描述

2.需求

如果一个系统不是根据各种需求来制定的,那么在上线之后就会有各种各样需要优化的点。所以数据分析师提出了以下的需求:

(1)顺序准确

玩家操作的顺序要保证是正确的,否则无法获取真实的玩家一系列操作

(2)存储稳定

玩家的操作不能一直保存在内存中,否则玩家突然关闭客户端后前面的数据会全部丢失。也不可以每记录一条就上传至服务器中,否则用户量级大的时候连接数过大将会是很大的灾难。

(3)尽量靠近玩家最后的操作

在某些情况下这一套日志系统想要记录玩家离开前最后的几步操作,而这些玩家通常是通过杀死进程来结束的,并非是使用游戏内退出的方法。这样就需要退出前对玩家的日志进行最后上传。

(4)快速、高效

需要一整套系统各自的协同配合

3.思考可能会出现的问题

(1)服务器时间误差

服务器在运行时会比一般时间走得快或慢,会导致以服务时间为准可能会出现顺序的问题

(2)客户端时间误差

客户端的时间受到玩家手机的影响较大,准确度比较低

(3)数据重复

玩家上报数据时,如果上次上报之后服务端回应超时/回应失败,那么下一次上传时需要将上次的数据再次上传,此时如果服务端其实是成功的,那么就上传了两份同样的数据。

(4)数据残缺

玩家在操作之后突然切后台且杀进程了,并且玩家自己清除了数据,这时候玩家上传的数据是缺少了一部分的数据,需要让服务端知道。

(5)日志文件过大

如果玩家上传日志时一直无法上传成功,本地存储的日志文件将会越来越大,每次读取以及上传的成本也越来越高

(6)连接服务端前的数据

在某些情况下玩家在某个时间段之前可能无法连接日志服务,比如需要登录才能进行日志的上报,那么玩家在成功登陆到大厅之前会有一些数据,而这些数据是在客户端同步服务端时间之前操作的,可能会与同步之后的时间冲突,造成分析上的困难。

4.解决方法

(1)解决时间误差

首先玩家在客户端登录,连接到服务端第一时间就要向服务去请求服务端的时间戳,而客户端需要记下这个时间戳与本地时间的差值,之后的保存操作时就需要根据差值来与服务端进行时间的同步(这样可以使同一时间进行登录的玩家不会因为手机时间原因上报的时间数据有很大的区别),但是这样会受到服务端时间误差的影响,所以这个差值需要经常性的同步(可以在每次上传数据返回中添加服务端的时间来同步)。

(2)解决数据重复

解决数据重复需要有一个上传文件的guid来标识每次的上传,保证上次上传的数据如果没有收到回应,下次发送同样的内容时,可以在服务中进行判断以及去重。
每个玩家自增长的guid在服务端生成,保存在服务端内存中,当玩家登录时与服务器时间一起下发。而在客户端,这个guid保存在内存以及要上传的文件中,下次上传文件时需要将这个guid携带发送至服务端。在assist服务中进行判断是否小于服务端的guid,是的话说明是重复数据。
遇到异常情况时:
遇到服务重启时,每个人的guid会被重置。
如果玩家上次上传没有成功,客户端不会收到成功的回应,那么客户端将会保存原先的guid,下次上传时会用原先的guid再次上传这一部分数据。
如果玩家上次上传刚刚上传就杀进程,但是服务端上传成功了,那么服务端保存的旧的guid,在上传到服务端时会由服务端判断,如果小于服务端存的guid就不上传到日志服务,而是返回给客户端新的guid。
如果玩家上次上传成功了,服务端给客户端下发的是新的guid,此时服务重启后,玩家需要上传数据而服务端没有该玩家的guid,于是将上传的guid保存。
服务器重启而玩家不在游戏中,并且玩家上次上传其实成功但是客户端没有收到,下次登录时获取到的guid是0,由于玩家上次上传的文件中存在guid,那么客户端会用上次的guid上传,这是唯一一种会导致重复上传数据的原因。
如果玩家打开客户端没有收到服务端下发的guid和时间戳,那么玩家就保存本地时间的数据,而之前每次上传数据的操作改为获取时间戳和guid,直到获取到了下服务端时间戳和guid,那么下次上传就是正常上传。

(3)解决客户端顺序

客户端的每条日志还需要记录一个客户端的本地保存顺序id,用来保证客户端重复启动后的数据顺序准确。该顺序id首次由客户端生成,当每次将数据保存至文件中时这个顺序id也要保存,以保证下次登录时能够用这个本地顺序id来继续记录。

(4)解决数据残缺

如果上次玩家还没上传一部分数据就杀死进程关闭游戏了,那么下次登录时还是这个从服务端获取的guid,在上传的时候那个上传文件中如果没有guid字段(由于每次上传成功后这个文件里的guid不清除),那么说明玩家删除过数据,需要一个标记有残缺数据的标志位,下次上传数据时将标志位也加上,返回上传成功后需要清除该标记。

(5)日志大小

如果总是上传失败,游戏本地保存的第一个文件大小会越来越大,这时候需要增加客户端对这个文件的处理,上传失败时发一个钉钉消息来通知,如果上传失败多次的话就分割原文件(或者直接清除数据,这样简单一点)

(6)紧急上传处理

为了避免玩家退出游戏时还有未上传的数据,设置玩家在切后台前、退出游戏、大厅弹出退出框时进行紧急上传。

5.流程图

在这里插入图片描述

6.流程讲解

(1)玩家登录时,会向服务请求服务器的时间戳以及该玩家的上传id(即guid),保存在客户端以便使用。
(2)玩家的每次点击操作,会在客户端内存中的日志表中插入一条包含各种信息的记录。
(3)每隔1-2秒,日志模块会将内存中的日志表数据取出来,以xml形式存入本地的文件1中
(4)每隔10秒,日志模块会将文件1中的数据取出,而这时候需要判断文件2中是否存在guid,不存在则直接将数据存入文件2,并上传至服务端,清除文件1的数据。如果存在guid需要与服务器获取的guid进行比较,相同的话则上次数据发送不成功,重新发送文件2中的数据,并保留文件1;guid不同就将文件1的数据存入文件2替换原数据,并上传。
(5)收到服务返回:返回失败不对文件做任何处理,返回成功需要将获取到的新guid存下来作为下一次上传的凭据,同时清除文件2的数据。而同步服务端时间也在这个过程中。

发布了2 篇原创文章 · 获赞 2 · 访问量 205

猜你喜欢

转载自blog.csdn.net/weixin_41880150/article/details/103880173