
一个高大上的名字 楼主
2015-07-05 20:31
本文将从架构、机器、业务逻辑,数据存储及性能指标方面,谈谈游戏后台在这几个方面所要关注的点。
1. 架构方面
架构是一个比较务虚的词,面对相同的业务需求,不同的架构师能设计出不同的架构,有时也很难去评判架构的好坏,更多的时候架构是随着业务的发展而不断进化的。对于游戏后台来讲,架构的选择需要满足游戏的核心玩法、功能需求以及具备持续运营的能力。
(1)核心玩法
游戏的核心玩法往往和游戏类型相关,比如RPG,SLG,FPS,卡牌,社交游戏等等。这些游戏类型在后台架构设计需要考虑的侧重点不同,RPG重在实时交互,SLG,社交等注重离线异步交互玩法。对于不同的游戏类型,一般采用全区全服或分区分服的架构模型。全区全服或分区分服主要是指数据逻辑空间的划分上。全区全服在逻辑上所有数据互通,比如微信上的游戏酷跑,打飞机等等,在全区全服的分区策略上采用IOS和Android配置不同的大区;分区分服在逻辑上每个分区对应单独一份数据,各分区数据不互通,比如QQ御剑,全民英雄,手游仙剑奇侠传等。同时对于强交互的游戏,由于交互实时性要求较高,一般采用长连接,后台逻辑svr采用数据有状态;而对于弱交互或异步玩法的游戏,后台逻辑svr一般采用无状态,协议采用HTTP短连接或TCP长连接都可,前后台采用TCP长连接方式通信灵活性较好,建议采用。
(2)功能需求
一堆功能的有机组合组成了一个游戏世界,游戏相对其他传统软件的一个主要特点就是逻辑的复杂性相对较高。合理的划分、解耦游戏的逻辑系统对简化功能开发至关重要。比如MMO RPG,从用户的角度看就是身处某个游戏场景进行某种操作,同时各个场景的角色交互较少,因此在逻辑上就可以把场景当成一个逻辑处理单元,体现在程序上就可以用一个机器、进程甚至线程作为场景的处理逻辑承载单元。用大系统小做的思想,除了主逻辑svr服外,其他的角色管理,交易pay、邮件、商店,在线状态,排行等等都可以拉出单独的服务供主逻辑服务调用。
(3)持续运营
一款游戏能否取得成功,上线的持续运营才是关键。在运营过程也许你也曾遇到这种“痛并快乐着”的情形:玩家突然涌上来,玩家进不了游戏,游戏过程中不流畅等等,你的手机堆满告警短信。“稳定压倒一切”,对于服务器来讲绝对是至理名言。服务器的资源是有限的,所能承载的最大负载也是有限的。在架构设计的过程中,要为最坏和满负载的情况作设计。比如为每个机器设置合理的最大在线承载,比如是不是可以通过扩机器解决资源耗尽问题等等。Gid的生成策略也是需要考虑的问题,特别是对于分区分服的游戏,gid的生成规则往往跟合服紧密相关。运营过程中,需求变更、新增逻辑功能和玩法几乎就是家常便饭。需求的变更往往带来的就是逻辑和数据的变更,比如数量容量变大,数据系统是否能满足这种变更也是需要考虑的问题。同时在更新游戏内容时,后台的更新策略如何?是支持热加载还是要停机维护?前台的版本更新和后台的版本更新的策略等等都是需要考虑的问题。
2. 机器方面
公司的机器都有固定的型号,每种型号的资源配置,性能高低不一,在业务上线时需要对系统的机器需求做适当评估,让合适的后台服务跑在合适的机器上。
(1) CPU
现代处理器基本都能支持多核,采用的也大都是CMP(Chip multiprocessors)结构。目前使用的业务逻辑的机器基本上是采用8核或16核机器,具体可用cat /proc/cpuinfo查看。在逻辑服务架构设计怎么去充分利用现在的多核CPU资源,提高系统的并发和吞吐能力也是一个值得考虑的问题。多核性能的发挥一般取决于软件架构设计,仅仅说采用多线程、多进程的设计方式都不见得能发挥多核的性能,因为多数涉及到并发的时候,便涉及到数据的共享和通信,特别是对数据并发访问上。因此在设计逻辑处理框架的时候,需要充分考虑锁对性能的影响,做到降低锁的粒度甚至不加锁。除了锁之外,需要结合业务的特点设计合理的并发模型。常见的并发模型有迭代模型,fork模型,分发模型,线程池模型,多进程多线程模型等等。多进程/多线程不仅在充分利用多核,还在于CPU计算和网络/IO操作可以很好的重叠进行。对于多进程/多线程,要尽量减少进程/线程的切换,当进程/线程的上下文频繁切换时,所消耗的时间是相当可观的。为减少进程/线程的切换,需要配置合理的线程数量。有一个经验公式可当参考,最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间)*cpu数量。举个列子,cpu核心数8核,线程的任务是请求异地数据并做相应的计算,假定线程CPU计算时间2ms,网络IO请求2ms,此时的最佳线程数量是16。对于一些优先级很高的任务进程,甚至可以直接绑定CPU,增加CPU缓存的命中率。
(2) 内存
游戏后台特别是逻辑服务大都会吃掉大量的内存,内存的分配和释放策略尤为重要。
游戏的内存使用主要有普通内存和共享内存。游戏后台的内存分配/释放一般不用new/delete或malloc/free。
普通内存:主要用在全局配置的加载,对象obj的生成以及运行时临时内存的分配。全局配置内存静态分配,数据不释放常驻内存。对于游戏的关键逻辑内存采用程序启动的时候一次预分配成静态固定内存池,比如玩家,NPC,场景等等都对应不同的池子;对于运行时临时内存在保证不溢出的情况下可直接采用栈内存;对于其他一些内存可以考虑通用的内存池,像TCMalloc,需要时直接向内存池申请,避免频繁的内存分配以及释放整理。
共享内存:共享内存在很多业务的服务器后台都有使用。对游戏后台来说,共享内存更多的主要使用在游戏数据的缓存上,使用共享内存可以更好避免后台服务core引起的数据丢失,也能很好的解决逻辑和数据的分离。
(3) 网络/IO
从游戏服务器后台来说,一般考虑网络IO,磁盘IO一般不用太关心。在手游时代,由于终端时刻移动终端便于携带,由于位置以及环境因素的抖动,终端随时可能面对不稳定的网络环境。对于移动游戏来说,提供稳定健壮高速的网络接入方案对移动终端游戏的体验至关重要。所幸我们在外网的接入已经有成熟的解决方案:GSLB+TGW,同时TGW能进行分运营商的多通接入,从而实现终端用户的就近高速接入。在业务侧会启动一组epoll服务,用来管理网络连接以及数据包收发,epoll相比select的好处就不多讲了。Epoll在处理1W级别的TCP连接性能表现很好,足够满足游戏服务器的需要。互娱的tconnd,即通的netframework都采用epoll。
3.业务逻辑方面
从功能玩法来讲,游戏后台逻辑功能主要由场景系统,角色系统,道具系统,任务系统,活动系统,战斗系统,交易系统,社交系统等组成。
从技术技术角度看,不同的游戏类型在实现上述系统侧重点有所不同,所采用的逻辑处理驱动方式也不同,后台逻辑驱动方式主要有心跳驱动和消息驱动。比如RPG重在交互的实时性,一般采取心跳驱动+消息驱动的方式。心跳驱动主要处理游戏的内在逻辑,这部分逻辑由各种后台事件驱动,比如时间过期,比如活动开启,场景怪物刷新等等;社交策略游戏的实时性相对较低,一般采用消息驱动的方式,系统的逻辑行为主要由玩家的操作消息产生,消息驱动主要由玩家的行为操作来体现,属于服务器的外部事件因素。
4. 数据存储方面
游戏从产品角度看由各种逻辑玩法组成,从技术角度看,游戏最终玩的是数据。网络游戏是一种强数据,强逻辑的系统,业务逻辑的演化最终会体现为系统数据的变化。对于分区分服且实时性要求较高的游戏,比如RPG,可以采用共享内存+nosql的存储方式,即数据一次加载到内存,脏数据定时回写nosql。采用这种方式的优点就是玩家登陆后所有对数据的操作都都只是涉及到本地共享内存数据的读写,没有跨机器数据读写的性能损耗,缺点就是跨线的数据同步问题较复杂,同时数据的扩容也是需要考虑的问题,一般需要停机维护。对于大区类型游戏,所有可平行扩容的无状态逻辑svr共享同一个DB,这个类型的游戏就要考虑数据访问的效率以及数据一致性问题,当然也可以采取一些比较折中的方案,比如可以把玩家的数据进行拆分,分为角色的私有数据和公有数据,私有数据可是做成有状态的,公有数据做成无状态的。公有数据的一致性问题可以采取全局锁,数据带版本号,或者hash串行化等等解决方案。
5.性能指标
这里的性能指标是从用户体验的角度来看。主要有响应时间,吞吐量和最高同时在线。
(1)响应时间
是指玩家的操作请求的响应时间。
(2)吞吐量/包量
吞吐量/包量是指服务器每秒能处理的请求数。
(3)最高同时在线数
一个游戏分区或一个游戏world所能承载的最大玩家数。
响应时间和吞吐量是倒数关系。对一物理机器来说,系统资源总是有限的。当客户端与服务器只建立了一个网络连接的情况下,发送请求后就只能等待服务器处理完成后返回。从用户体验的角度看,用户希望服务器处理每个请求的净耗时是在用户的可接受的范围。假定响应时间在吞吐量仍有很大空间的情况下保持恒定,要增加对服务器的压力,使服务器产生更高的负载,每秒处理的请求更多,只有一个办法,就是提高并发连接数(同时在线数)。当并发数超过系统的负载时,吞吐量不再提高,而响应时间随负载增加而增加。对于不同类型的游戏,对响应时间的要求不同,比如FPS对响应时间要求很高,而社交游戏对响应时间相对较低。因此在综合考虑用户体验流畅度的基础上,需要合理确定最高同时在线数
¥79.00¥179.00
¥199.00
¥98.00
¥398.00