棋牌类游戏服务器构架设计分析html
原文地址:http://bbs.gameres.com/thread_703363_1_1.html
原文做者:小篱
原文出处:GameRes游资网mysql
通常来讲,棋牌游戏都是不分区不分服的。因此棋牌类服务器要知足随着用户量的增长而扩展的须要。nginx
即在同一局游戏中就是在同一个房间中,同一个房间中的人能够接收到其余人的消息。程序员
这个特性相似与通常游戏的回合制,每一个玩家的操做都是有顺序性的。web
由于棋牌类游戏不分区不分服,咱们在设计服务器的时候,是按世界服的思想去设计,即服务器是一个n多台物理机的集群。当用户登录服务器,建立房间时,可能根据负载均衡算法,它能够在任何一台服务器上面。因此,无论用户登录到哪一台服务器上面了,均可以得到本身的数据。咱们可使用redis来作数据共享。redis
在同一局游戏中,咱们要求全部人都在同一个房间中,咱们能够规定在同一个房间中的用户,必须登录到同一台物理服务器上面。在建立房间完成以后,其余人根据房间号查找房间的时候,能够根据房间号,获取这个房间所在的服务器ip和端口,判断一个当前用户登录的服务器ip与房间所在的服务器ip是否相同,若是相同,就不作切换,若是不同,客户端就使用ip和端口,链接到房间所在的服务器上面。算法
建立房间成功以后,接下来的操做都要保证它的顺序性,因此房间须要有一个它本身的消息个队列。咱们能够把每一个房间到达服务器的消息封装为一个任务,把这个任务放到消息队列中,而后有一个任务执行者去按顺序执行这些任务。sql
通常都是须要接第三方登录,登录这一块是http操做,咱们统一提供一个web服务,用来作登录验证。由于在登录时,调用第三方的http服务,这个过程可能很慢,若是放在逻辑服务器的话,可能会卡业务逻辑任务。由于可能不一样的玩家业务请求可能同在一个线程中,若是有任务卡了,那么这个任务之后新来的请求请会卡住,致使消息延迟。数据库
也放在web服务中。公告通常是游戏登录的时候向服务器获取一次。把它放在web服务器中,与业务逻辑分离的好处是,当业务逻辑服务器维护或更新的时候,不影响用户的登录,和获取公告,这样用户体验会好一些。缓存
由于棋牌类游戏服务器是世界服,无分区,因此用户的id必须是全局惟一的。能够利用redis的incr方法,原子的递增,若是不想被别人根据userid的递增推算出有多少注册用户,递增的梯度能够随机,好比每次递增的值从1到1024中随机一个。
当房间主建立房间时,房间的id须要在任何台服务器上能够查询到,因此建立房间成功后,房间id要存储在共享内存redis中,每一个房间id对应一个房间所在的ip地址或服务器id.这样,当有用户要进入房间,在查询房间id时,可能判断这个房间是否和本身登录的游戏服务器相同。
根据房间id查询房间,查找到房间后,获取房间所在的ip地址或服务器id,若是发现和本身所登录的服务器同样,直接能够加入房间。若是不同,把这个房间所在的ip和端口返回给客户端,让客户端从新与房间所在的服务器创建链接,使用登录时的token验证用户。
在验证游戏是否合法时,客户端与服务器都要验证,验证的算法是同样的,因此可使用脚原本写,写一份脚本,在服务器与客户端中同时使用。可使用lua。同一个算法使用同一个脚本 ,这样在开发新的同类型棋牌游戏时,只须要替换一下这个脚本就好了,不用再重复开发。
这个通常是根据运营需求开发的,每一个公司不同。不过有一点,后台管理系统可能要和游戏服务器通讯,这种通讯方式最好是采用redis的订阅/发布机制。这样能够把某个消息事件同时发送到全部的业务服务器上面。根据用户所在的服务器进行处理。
玩家同屏是棋牌游戏中的一个重点,对于作过那些大型的arpg,或mmo游戏的程序员来讲,这并非什么难事。由于同屏就是服务器对客户端的消息进行转发。一个房间四我的,一我的出的牌或操做能被其余三我的同时看到。
由于棋牌游戏的同步数据量比较小。通常常见的同步方式有两种:
客户端主动拉取
客户端定时主动向服务器请求一个用户的消息队列,当一个玩家有操做须要同步到其余玩家时,在服务器端先把这个消息放到这个用户的消息队列中。等待客户端的拉取操做。这种方式的好处是,不须要考虑网络闪断或网络很差的状况,信息都是同步获取的。缺点是,定时拉取的时间间隔很短,可能不到一秒就会拉取一次。
客户端主动推送
当一个用户出牌的消息须要同步给其余玩家时,服务器会得到这个玩家与服务器创建的socket链接,而后服务器使用socket 主动向客户端发送消息。
这种方式要考虑网络闪断,消息丢失的问题。由于服务器推送的消息,客户端有可能会收不到。因此客户端须要根据心跳来判断网络是否有断开过,若是有断开,须要从新从服务器拉取整个房间状态的消息。或者根据服务器发送的消息号,若是客户端发现接收到的服务器消息号有跳号的,好比应该接收10,却收到了12,说明中间有消息丢失,须要从新拉取整个房间的状态信息。
这种方式的缺点是,开发复杂,须要考虑一些网络问题。优势是,只有在有消息的时候才会推送,没有的话不推送,不占用带宽等系统资源,能够增长用户同时在线量,也就是增长了服务器的承载量。
1,因为棋牌类的游戏数据少,计算量也小,因此彻底能够不使用内存缓存,而直接使用redis共享内存,用户的全部数据都缓存在redis中。更新也同步更新到redis中,这样无论一个用户登录哪一台业务服务器,都能得到本身的最新数据。
2,更新数据库,因为数据第一缓存是redis,因此活跃的用户数据都是能够从redis中直接得到的,而不用查询数据库,因此数据库的更新能够采起异步更新,而不会产会数据的延迟。须要注意的一点是,数据的异步更新必须保证是有顺序的。那么这就会产生一个问题,怎么保证用户的更新不会乱呢?
3,如何保证更新的顺序性
由于咱们的业务服务器是多个的,用户可能链接其中的任何一个,若是说登录的是服务器A,加入的房间在服务器B上,那么链接就会切换。为了保证数据更新的顺序,咱们能够作一个数据库持久化服务,把须要更新数据库的任务实时发送到这台服务器上,由数据库持久化服务执行对数据库的更新。这样无论用户链接的哪台业务服务器,它的更新都是有顺序保证的。
因为棋牌类的业务少,数据更新少,因此查询能够有redis缓存,减小数据库查询的压力,而更新实行实时更新到数据库,前期不须要开发数据库持久化服务。等用户积累到必定程序以后,发现更新数据库比较慢的时候,再单独作一个数据库持久化服务。
1,登录时,客户端首先向登录的web服务器请求登录信息,登录成功以后,返回登录的token,为了适应大规模的web请求和登录服务的稳定,可使用nginx作负载均衡。
2,登录成功以后,请求负载均衡服务器,获取一台链接的业务服务器。这个负载均衡服务器能够和登录web在一个进程中,也能够独立出来。
3,拿到登录成功的token和须要链接的业务服务器的ip和端口以后,再去链接业务服务器。链接成功以后,要使用token到登录服务器去验证,这个用户是否登录了。
4,同一个房间的用户要链接到同一台物理服务器上面。在上面已经说过了。
5,redis用来作共享缓存。
6,mysql作持久化存储。
7,数据库持久化服务器,统一作数据入库操做。
1,网关的做用
a,转发消息包
b,业务的负载均衡,好比A业务由服务器a处理,B业务由服务器b处理,由网关进行转发。
c,维护与客户端的链接
d,带宽的整合,通常的云服务都是按购买的服务器计算带宽的。经过一台服务器转发消息,能够只购买一个大带宽就能够了。以节约成本。
2,棋牌类游戏须要网关吗?
我认为不太须要,由于棋牌类游戏业务比较单一,作的最多的就是消息同屏转发。最可能是再有一些任务或活动,这些由一台服务器直接处理彻底能够搞定。并且开发网关也是一个复杂的工做,不必在这个上面花太多的时间。