刘源霖20151119 php
本文档主要是调研分析新的手游服务端架构,为下一款手游服务端研发提供可参考的方案。主要的参考点是数据持久化,并发效率,分布式,沙盒机制,热更新机制,研发维护成本。若是从头根据需求开发一款新的服务器架构,须要大量的时间,并且可能会得不偿失,一款新的架构稳定都须要时间的。咱们应该尝试使用开源的,成熟的,活跃度高的开源框架。正文将先从服务器设计须要考虑的因素进行需求分析,以致明确咱们须要的服务器架构原型,而后再分析现有的开源架构方案。 html
服务器操做系统大多采用Unix和Linux操做系统,而Linux发行版本系统中,多使用CentOS、Redhat、Ubuntu、Gentoo、Debian。而这些发行版本能够大致分为两类,一类是商业公司维护的发行版本,一类是社区组织维护的发行版本,前者以著名的Redhat(RHEL)为表明,后者以Debian为表明。Redhat的稳定性和硬件兼容性都比Debian高。而且RHEL的生命周期是7到10年,基本上能够覆盖硬件的生命周期,也就意味着一个新硬件安装之后,不用再次安装操做系统。而Debian的生命周期是不固定的,通常新版本发布之后,上个版本再维护18个月。而Debian的版本发布时间间隔不稳定,常常会延期。综合起来一个版本的生命周期通常在3~4年。若是选用了 Debian 或者 Ubuntu做为服务器,等生命周期过了之后,就没有安全补丁,服务器就会有安全风险。 前端
基于以上对比,在给服务器选择Linux操做系统时,咱们会优先考虑Redhat系统的操做系统。 html5
因为CentOS源于 Red Hat 企业级 Linux(RHEL)的源代码,依照开放源代码规定释出的源代码所编译而成。因为CentOS开源特性,选择CentOS能够下降成本,同时又可以享受RHEL的服务支持。目前市场最大的两个centos系统是centos5(2007)和centos6(2011),最新的是centos7(2014),每一次的大版本升级系统意味着更好的稳定性和功能扩展。因为centos7刚刚在2014.7月发布,最新版本7.2稳定性还有待考证。因此选择centos6是最为合适的。 Centos6版本最新centos6.7。 java
对于服务器而言,数据是最重要的。有一个好的数据持久化方案,对于服务器开发将会是事半功倍。在介绍数据的持久化方案之前,咱们如今介绍服务器数据读取和修改的运用场景。服务器运行过程当中会不断的生产数据(增删读改),而且将数据落地(如存入数据或者文件)。 python
可是若是服务器每次都直接从数据库或者文件读取和修改数据,那么服务器的io操做可能成为瓶颈,能够采用异步读写方案来下降io读写对服务器逻辑处理能力影响,可是同时提升逻辑的复杂度。 因此较好的方式是将数据缓存到内存中,同步读写,每次读写都先操做缓存,而后再由缓存同步到数据库。同步机制决定了数据持久化能力。若是本身去实现这套机制无疑是造轮子,并且效果不必定好。数据持久是每一个服务器都须要的。已经有不少专业的团队提供有不少开源的成熟的解决方案。如memchache 和redis 缓存系统。 mysql
下面提供三种方案: c++
第一:redis + mysql git
第二:redis + unsqlite(推荐,两种都是key-value,nosql) 程序员
第三:redis.(redis 自带数据落地策略)
对于具体如今那种能够后续再讨论
注意:对于在选择数据持久化方案时,须要考虑咱们的对数据的需求,如是多读少写,仍是少读多写。在游戏服务器中还应该考虑合服和跨服等需求是否方便实现。
对于游戏服务器而言,首先应该保证的就是高并发处理能力,从而最大限度的提升服务器的吞吐率,提升单服在线人数,下降服务器硬件成本。实现的方式有不少,没有决对好坏。只有针对具体的需求,才有好差之分。
方式有不少,经常使用的两种:单线程多进程,单进程多线程
第一:主逻辑单线程+[多辅助线程]
好处:不用考虑锁,多线程数据同步等。开发门槛低,开发方式方式灵活,bug定位容易,新人上手容易
坏处:没法充分利用cpu多核
对于游戏服务器架构而言,服务中存在不少模块,因此的模块都将混入这个单线程中,若是cpu性能出现瓶颈, 优化成本将会很是高,因为是单线程,抛弃了锁等束缚,给程序员提供太大的空间,每每在书写的过程当中比较随意,若是没有沙盒机制,要保证代码的质量对参与开发的每一个程序员的水平要求都要要比较高。
第二:主逻辑多线程+[多辅助线程]
好处:充分利用多核
坏处:开发过程要考虑数据同步等问题。Bug定位困难
因为单核cpu的能力限,而且游戏服务器模块较多,并不是处理某一类单一问题,因此服务器的实现应该尽可能利用cpu的多核处理能力,并且能够绑定线程,提升cache命中几率。可是多线程并发编程若是没有一个好的系统机制或者语言支持,如使用c 或者 c++语言。门槛较高,要求开发人员的必须具备较高的架构能力,不然将会出现多线程处理能力不如单线程。因此如何下降并发编程的门槛也是服务器架构设计的重要部分。
服务器分布式,是指服务器支持分别部署在不一样物理机上。能够以增长物理机的方式提升服务器的承载能力。因此好的服务器应当有一个灵活的扩展分布方案。因此如何让咱们的服务器具备灵活的扩展能力,将是服务器架构中的重要部分。
沙盒机制:就是让代码在一个比较安全的受包含的环境中运行,即便代码出现错误,产生了叫恶劣的影响,其破坏能力将被禁止在沙盒中不会影响到沙盒外的环境。这样的机制能够提升服务器的安全性和稳定性,而且提升开发效率。因此如何让服务器架构具有沙盒能力将是服务器架构设计的重要部分。
若是服务器可以作到不停服维护,那么能够在不承受停服带来的损失的状况下,修复服务器缺陷。然而咱们一般应的c语言,c++, java的语言都是不支持热更新。一般只有解释型的脚本语言才能支持人更新,还有函数编程语言也支持简单热更新,由于函数编程语言函数内无状态。
相信有不少知足上面要求的服务器架构,可是选择这些架构须要根据团队成员的自身能力。好比erlang语言,天生支持分布式,支持沙盒机制,因为自己是函数式编程语言,天生时候并发编程,简单热更新等机制。可是团队成员中没有一个会erlang,咱们也不会选择erlang语言。由于咱们耗不起从头学习erlang的时间。
调研报告主要从两个方面进行:语言、开源引擎。
如今有不少面向并发或者易于并发编程的语言,他们大可能是一些小众语言,如go,erlang语言。不少游戏喜欢用erlang语言作服务端。Erlang是函数式编程语言,接近天然语言易于理解,而且天生支持并发编程,热更新。Erlang的核心概念是节点,一个节点就是一个独立的系统包含了地址空间和独立的进程集的完整虚拟机,这种设计基础让erlang语言天生具备分布式和沙盒机制。根据erlang的这些特性,无疑彻底知足咱们对服务器的要求,并且大大下降了门槛了,由于咱们不在须要考虑并发,考虑分布式,考虑锁等。可是通常小众的诞生都是为了特意的解决某一类问题而诞生的。天然就有这种语言最适合的,和不适合作的事情。Erlang适合作非计算密集超大并发服务器,不适合作数值计算和业务逻辑很是复杂的系统。
经过上面的分析,erlang语言确实适合轻量级游戏的开发,并且开发门槛低,特别是对于没有经验和技术沉淀的小公司而言。可是咱们团队成员都没有学过erlang语言,都没有学习过任何函数式编程语言,虽然erlang的门槛低,可是要用好,相信仍是须要的时间的。这将会大大提升的咱们的时间成本。因此对于咱们选择erlang是不太合适的。可是erlang的思想是能够借鉴的。若是咱们能用熟悉的语言实现erlang的思想,无疑是很是完美。那有没有一套这样现成的系统,答案是确定的。 Skynet(开源服务器引擎)正是研发者在使用erlang时出现瓶颈后使用c语言和lua语言模拟了erlang的机制,最终替换了erlang语言。而且通过日活跃用户50万的考验。具体细节后面具体章节再讨论。
可以站在巨人的肩膀上,利用前人的研究成果,是最快最有效的方式。开源的游戏服务器有不少,根据咱们自身的因素,咱们只能选择c/c++ lua相关的。这样的服务器引擎目前比较活跃的有两个:KBEngine(c++ + python), skynet(c + lua)
KBEngine:
发布时间2012年6月,
开源地址:https://github.com/kbengine/kbengine
Fork次数766
Issues 22
Pull requests 83
Star:891
最新release版本:V0.6.21
社区关注人数:1773
成功产品:
KBEngine是一款开源mmog服务端引擎, 使用统一协议可以轻松与前端对接,能轻松使用unity3d、 ogre、 cocos2d、 html5等做为前端表现。
底层框架由c++编写, 逻辑层使用python(支持热更新), 开发者无需重复实现一些通用的底层服务端技术, 使开发者可以真正集中精力到游戏开发上来, 快速打造各类游戏。
KBEngine底层架构被设计为多进程分布式动态负载均衡方案, 理论上只须要不断扩展硬件就可以不断增长承载上限,单台机器的承载上限取决于游戏逻辑自己的复杂度。
Skynet:
发布时间:2012年7月
开源地址:https://github.com/cloudwu/skynet
Fork次数:1469
Issues:16
Pull requests: 192
Pull requests: 192
Star:3038(star> 3000, all1386 c 46 c++ 28)
最新release版本:V1.0.0
社区关注人数:1213
表明产品:陌陌争霸(日活跃50万,大服结构),每天来战, , 战神黎明,逍遥西游
http://tech.qq.com/a/20140325/020893.htm
skynet是云风编写的服务端底层管理框架,底层由C编写,配套lua做为脚本使用,可换python等其余脚本语言。
skynet默认开启_timer线程、_socket线程、_monitor线程以及可配置个数的多个_worker线程,启动skynet服务就是向skynet注册由c编写的so模块实例也就是服务。
skynet主要工做是经过模块注册管理服务,并协调服务之间的调用和通信。
二者数据对比分析,发布时间相同,社区关注度kbengine更胜一筹,可是参与开源贡献和维护方面skynet更胜一筹,而且skynet已发布1.0版本。 Kbengine目前没有成功的产品。为何会出现这种状况呢, 第一:kbengine 封装完整,代码量大,用户能够很简单快速的搭建游戏服务器,可是很难把握其底层整个架构,一旦出现问题很难跟踪,这就是为何参与其开源贡献的人比较少, 而skynet至提升一个简单框架,代码量少,使用者很容易把握住,虽然没有kbengine那么方便,可是也提供更多自由选择的空间。第二:skynet成功的产品都主导研发skynet的简约公司的产品,而kbengine没有成功的产品,有多是有产品用了没有宣传,还有多是研发者并无将引擎用于本身的项目,只是业余时间开发。
总之从二者来看,skynet更适合,skynet只提供简单框架,彻底模拟erlang的思想,而且采用了咱们熟悉的二者语言lua和c, 而且代码量少,容易把握。而且已有成功的产品和相对客观数据验证了skynet的健壮性。下面对skynet架构作具体分析。
在正式具体的介绍skynet设计细节以前,先来分析它是如何模拟实现erlang思想的。
Erlang的主要几个核心点:节点核心概念,分布式, 并发编程,actor 模式,沙盒机制, 多进程实,热更新,开发简单。
Skynet核心概念也是节点,通常称之为服务,也使用actor模式,也提供分布式方案(harbor 和 cluster模式),多线程驱动, 与lua结合,利用lua天生的沙盒机制(state)和热更新机制,同时经过lua来下降开发门槛。简单说:skynet 利用了操做系统线程+luaState + lua coroutine实现了简单的erlang。Erlang底层也是采用c实现的,只是封装的更加完善,没有接种其余的语言实现本身是的沙盒方式。
skynet是简约公司云风主导研发的轻量级服务端底层管理框架,底层由C编写,配套lua做为脚本使用,可换python等其余脚本语言。整个服务器逻辑层偏lua。底层C框架主要工做是经过模块注册管理服务,并协调服务之间的调用和通信。
Skynet 发布与2012年7月,2015年11月正式发布release版本1.0。
简约公司产品都使用了skynet框架:如陌陌争霸,每天来战,陌陌弹珠,逍遥西游等
设计综述:http://blog.codingnow.com/2012/09/the_design_of_skynet.html
Skynet是设计是使用actor模式,所有工做线程以消息驱动。服务器初始化启动多个工做线程,一个网络线程,一个定时器线程,一个监控线程。用线程带动各个服务运行,若是是lua服务则须要一个lua state 协助运行,在lua state能够启动多个coroutine协同工做。详细见其层次图。
因为skynet使用actor模式,使用消息驱动,那么全局就须要维护消息队列。Skynet的消息队列设计以下,每一个服务有个独立消息队列,全局有一个全局的全局队列,每一个服务启动后须要将本身的消息队列注册到全局队列中, 全部的工做线程依次轮询全局队列,以此调度各个服务执行本身的任务。
每一个消息队列都是多个生产者和多个消费者。见下图
Skynet采用的自旋锁
每个lua服务都有一个独立lua state,由此造成服务器的沙盒机制。配合lua中协同开发模式,能够同时执行多个任务。 对于c层的异步接口,能够在lua层封装一层阻塞接口,而后交给coroutine去等待。等待有结果时再唤醒coroutine。Coroutine的阻塞并不会致使整个lua state的阻塞,因此整个工做线程仍是在运行的,简单的说就是用同步写异步。如:lua socket
当单台机器的处理能力达到极限后,能够考虑经过内置的 master/slave 机制来扩展。
每一个 skynet 进程都是一个 slave 节点。但其中一个 slave 节点能够经过配置 standalone 来多启动一个 cmaster 服务,用来协调 salve 组网。对于每一个 slave 节点,都内置一个 harbor 服务用于和其它 slave 节点通信。
skynet 提供了更具弹性的集群方案。它能够和 master/slave 共存。也就是说,你能够部署多组 master/slave 网络,而后再用 cluster 将它们联系起来。固然,比较简单的结构是,每一个集群中每一个节点都配置为单节点模式(将 harbor id 设置为 0)。
要使用它以前,你须要编写一个 cluster 配置文件,配置集群内全部节点的名字和对应的监听端口。并将这个文件事先部署到全部节点,并写在 Config 中。
如下是skynet主导研发云风在腾讯课堂上对skynet提出的二者部署方案。
Skynet实例介绍,过程参考下图:
1. 本实例是将登录单独出了一个skynet节点,也能够与游戏服之前作成同一个skynet。
2. 登录的主服务负责接收登录消息,从节点负责验证
3. 网关服务负责接收网络消息,并转发给对应的agent
4. Redis主服务负责接收数据请求,并派发给从节点,从节点负责从各自链接的redis数据查询更改数据。用于数据库链接池
5.本方案只考虑单服
对于多服的实现并必定时由于单服的承担能力不够,有多是运营须要,运营须要多个排行榜,以养更多的大R,如不少页游开了几百个服,实际上是开了几百个排行榜。因此实现为服务架构支持灵活的多服部署方式和合服策略是很重要的,合服操做的是数据,因此要保证在数据标识设计时要为后期的合服作准备。下图是skynet多服部署图,采用使用skynet cluster模式。