对于开房间的游戏,比如想让玩家开黑,可通过这种方式,那么问题来了,如何分配管理这种全服唯一的数据, 在这里用房间号举例。
房间号同一时刻唯一,随机4~6为数字,
服务器模型是和redis类似的 集群式,N*N的链接,,对外只有一个服务器,然后该服务器(服务器0)消息路由给其他服务器(服务器1~N),只做转发之类的简单请求。
对于玩家来说房间号是链接战斗服的标示,所有玩家都可以通过这个房间号加入游戏,随机匹配会通过一定规则去选择可加入的房间。
1:房间号管理和战斗服分配分离开,房间号在服务器0进行产生,该服务器为入口,假设不宕机,那么只需要本地产生一直维持一个唯一性即可,然后把房间号写入redis,来共享给服务器N,服务器N根据这个key把房间数据写入redis,对于战斗服的分配,采用常规模式即可,比如轮训,或者选择一个负载最小的,负载量可以通过rpc 或者redis共享来告知服务器0,这样对于一个房间redis中的数据可能是这样
key=room-6666 value=ip:127.0.0.1,port:9000,server_id:123,player_num:5,
存储着房间号6666所在的服务器N的ip地址和端口,服务器id,玩家数量,等一些需要共享的房间数据。吧这个锅甩给了redis。,,这种方式由于服务器N和房间号是相对独立的,他们关联信息都保存 在redis里面,并且是依据,那么房间号分配池,和redis里面的数据一致性就很重要了,比如服务器0维护,然而旧数据脏数据还在redis里面,是否考虑清空redis里面的数据?很显然不会这么做,因此服务器0的房间号分配池是二次确认的一个重要依据,具体过程:
创建房间:
1.客户端请求服务器0创建一个房间。。。。
2.服务器0从内存中的房间号池中,随机出一个当前唯一的房间号1234,
3.服务器0从服务器N群中选择一个服务器和这个房间号绑定,把房间号发送给目标服务器,目标服务器做二次确认,该房间号在该服务器内有效,然后服务器0写入redis,初始化房间号信息key=room-1234 value=ipXXXXXXX,,,并且本地内存标记为使用状态,(潜在风险,宕机导致数据丢失)
4.服务器0吧房间号和战斗服ip和端口,发送给客户端,,,客户端根据这三个信息,直连战斗服,
5.战斗服收到链接请求后,加入目标房间,并且开始服务。
加入房间:
1.客户端吧房间号发送给服务器0,服务器0收到后,先在房间号池中判定一次房间号的有效性。
2.有效后,再从redis里面查询房间号绑定的ip和port,(潜在风险,房间号绑定的信息失效)
3.吧战斗服信息发送给客户端。
43客户端拿到信息后直连。
退出房间:
1.当房间内为空的时候,战斗服即可让出绑定的房间号,通知服务器 0,吧当前房间号归还给服务器0,吧房间号对应的redis数据标记为未使用状态,
2.服务器0收到归还消息后,把内存中的房间号池标记为未使用状态。以备下次使用。
以上存在的问题:
1.服务器0作为中转,房间号分配,处理可能会占用大量资源,导致整个集群可用性降低。
2。把房间号绑定信息写入redis,存在着要维护redis中的数据问题,维护2分,而且吧压力甩给了redis,响应可能会慢很多,一旦宕机,数据会出现严重的不一致。
针对问题2:如果把房间号 的映射关系直接保存在服务0的:内存中,那么2即可解决,宕机了全部丢失,也不会出现不一致问题,服务器0启动的时候 服务器N吧状态数据全部通过消息RPC同步到服务器0,以恢复已存在的房间和服务器信息,这样弹性就很好了,而且还能动态扩充战斗服。如果服务器0扩充的话,那么这份数据就不能共享给和服务器0同级别的服务器了,因此写入redis这种方案暂时还不不能舍弃,如果不考虑动态扩容的话,可以通过hash来确保,房间号映射到对应的管理器,这要求,hash算法和房间号生成算法是几乎是线性关系,这样才能保证均衡得分配到对于的管理器。这个比较难做到,因为也许分配均衡了,但是房间号弃用是玩家决定的,弃用不均衡也会导致管理器之间的负载不均衡,换句话说需要一种变长的动态hash。这个涉及到一致性hash问题
针对问题1:吧服务器0作为战斗服的管理器的话,非战斗资源就不走服务器0了,那么压力相对较小了