详细游戏服务器端架构升级实录【干货】

一. 农业时代

创业最重要的就是一个“快”字,所以最开始的时候,所有的架构都以快速出模型为前提。

而常看我博客的朋友应该知道我对python情有独钟,所以自然的,python成为了我开发服务端框架的语言。

python自带的多线程tcp服务器框架非常简单:ThreadingTCPServer,即每个链接一个线程的模式:

import SocketServer

class RequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        f = self.request.makefile('r')

        while True:
            message = f.readline()
            if not message:
                print 'client closed'
                break
            print "message, len: %s, content: %r" % (len(message), message)
            self.request.send('okn')

class MyServer(SocketServer.ThreadingTCPServer):
    request_queue_size = 256
    daemon_threads = True
    allow_reuse_address = True

server = MyServer(('127.0.0.1', 7777), RequestHandler)
server.serve_forever()

但是我又觉得多线程加锁使用实在太过麻烦,所以就引入了gevent:

import gevent
from gevent.server import StreamServer

class RequestHandler(object):

    closed = False

    def __init__(self, sock, address):
        self.sock = sock
        self.address = address
        self.f = self.sock.makefile('r')
        self.handle()

    def handle(self):
        while not self.closed:
            t = gevent.spawn(self.read_message)
            t.join()

    def read_message(self):
        message = self.f.readline()
        if not message:
            self.closed = True
            print 'client closed'
            return
        print "message, len: %s, content: %r" % (len(message), message)
        self.sock.send('okn')

server = StreamServer(('127.0.0.1', 7777), RequestHandler)
server.serve_forever()

而又因为之前在做个人开发者的时候,对flask的装饰器设计甚为喜欢,所以就参考flask设计了我自己的tcp server:

    https://github.com/dantezhu/haven

使用方法也是非常简单(服务器端):

import logging

from haven import GHaven, THaven, logger
from netkit.box import Box

app = GHaven(Box)

@app.before_request
def before_request(request):
    logger.error('before_request')

@app.route(1)
def index(request):
    request.write(dict(ret=100))

app.run('127.0.0.1', 7777, workers=2)

客户端:

from netkit.contrib.tcp_client import TcpClient
from netkit.box import Box

import time

client = TcpClient(Box, '127.0.0.1', 7777, timeout=5)
client.connect()

box = Box()
box.cmd = 101
box.body = '我爱你'

client.write(box)

t1 = time.time()

while True:
    # 阻塞
    box = client.read()
    print 'time past: ', time.time() - t1
    print box
    if not box:
        print 'server closed'
        break

这套架构在开发服务器端原型的时候非常有效,因为开发效率极高。

而我们开发的是棋牌游戏,当时为了图方便,几乎所有的数据都放在了进程内存里,所以操作起来也非常方便。

所以在整个研发过程中,服务器端的开发速度一直是客户端开发速度的数倍。

 二. 工业时代

然而很快,我发现了现有框架的一些问题,而这些问题都极其致命。

    1. 所有逻辑揉在一个进程中,性能太低,2000人同时打牌就会导致卡顿

    2. 多线程的模型在大量用户在线时,性能极差

    3. 逻辑server和存储server揉在一起,导致维护十分困难。重启逻辑服务器会影响业务,无法接受

因为如上的原因,我一直在考虑一套新的业务模型,除了要解决上面的问题之外,还要有如下的特性:

    1. 尽量保留python开发业务逻辑,因为与c++相比,开发效率极高。

    2. 可伸缩,分布式

    3. 尽量少改动现有逻辑代码

    4. 尽量让业务开发理解简单

 

最终,我实现了这套server框架,并将其开源在这里:

    https://github.com/dantezhu/maple

maple的实现,受到了很多想有框架的启发,其中包括zmq,half-async half-sync,以及当时淘宝的一个业务模型分享。

我记得印象比较清楚的是,当时主讲是这么说的:

    我们怎么判断该不该给某个server发送消息呢?

    根据成功率?根据响应时间?

    no,我们把push换成pull,让worker完成处理后,自己过来要数据。

    要,我才给,不要我就不给

 

maple的整个模型即是如此:

    gateway
    worker
    trigger

其中,gateway是用c++、epoll实现的一个高性能转发服务器,收到的客户端消息都会转发给对应的worker。

worker,即工作进程,他可以随时attach到某个gateway上来处理数据,也可以随时detach。并且worker使用python来实现的,兼顾了开发效率和运行效率。

trigger,触发器,即他可以触发事件来发给gateway,gateway会根据事件的不同,发给客户端或者worer。

 

详细的设计思路,可以参看maple的readme,里面有详细的设计思路。

一个简单的worker代码如下:

import logging

LOG_FORMAT = 'n'.join((
    '/' + '-' * 80,
    '[%(levelname)s][%(asctime)s][%(process)d:%(thread)d][%(filename)s:%(lineno)d %(funcName)s]:',
    '%(message)s',
    '-' * 80 + '/',
))

logger = logging.getLogger('maple')
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(LOG_FORMAT))
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

from maple import Worker
from netkit.box import Box

app = Worker(Box)

@app.close_client
def close_client(request):
    logger.error('close_client: %r', request)

@app.route(1)
def test(request):
    request.write_to_client(dict(
        ret=0,
        body="test"
    ))

app.run("192.168.1.67", 28000, workers=2, debug=True)

一个简单trigger代码如下:

from maple import Trigger
import time
from netkit.box import Box

import logging

logger = logging.getLogger('maple')
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)

def main():
    trigger = Trigger(Box, '192.168.1.67', 28000)
    # trigger = Trigger(Box, '115.28.224.64', 28000)

    for it in xrange(0, 99999):
        time.sleep(1)

        print trigger.write_to_worker(dict(
            cmd=3,
            ret=100,
            body='from trigger: %s' % it
        ))
        # print trigger.close_users([-1,3])
        # print trigger.write_to_users([
        #     ((1,2,3), dict(cmd=1, body='direct event from trigger: %s' % it))
        # ])

main()

很简单,对吧?

值得一提的是,为了方便worker的随时重启而不会影响外网服务,worker内部实现了对USR1和USR2信号的特殊处理。分别代表安全停止所有进程和安全重新拉起workers。

 

最后,上一张gateway运行时的统计图,命令如下:

    ./tool_stat -f stat_file

github链接:

https://github.com/dantezhu/haven

https://github.com/dantezhu/maple

时间: 2024-09-11 20:54:43

详细游戏服务器端架构升级实录【干货】的相关文章

棋牌游戏服务器架构: 总体设计

      首先要说明的是, 这个棋牌游戏的服务器架构参考了网狐棋牌的架构.网狐棋牌最令人印象深刻的是其稳定性和高网络负载.它的一份压力测试报告上指出:一台双核r的INTEL Xeon 2.8CPU加上2G内存和使用共享100M光纤的机子能够支持5000人同时在线游戏.       在研究其服务器框架后发现,它的网络部分确实是比较优化的.它主要采用了Windows提供的IO完成端口来实现其网络组件.本服务器虽然参考了其设计,但是还是有很大的不同,因为这个服务器框架主要是用在Linux系统之上,而

游戏运维编年史:可能是目前最详细游戏运维指南

游戏运维编年史:可能是目前最详细游戏运维指南 从端游到页游再到手游,15年来中国网游在世界上都有着举足轻重的地位.但是再好的游戏如果出现连接.延迟等问题时也会造成巨大损失,这时游戏运维便发挥了举足轻重的作用.中国网游的发展史,其实也是游戏运维的变革史,今天便由经典武侠手游<大掌门>运维掌门人吴启超来向我们讲述,进入游戏领域10余年来的风风雨雨. 有服务器的地方就有运维 如今我们说到游戏,可能想到的是火爆异常的VR,办公室里一言不合带上眼镜就地开打:亦或是刚刚虐了李世石的AlphaGo,扬言要挑

游戏服务器架构演进(完整版)

一.游戏服务器特征 游戏服务器,是一个会长期运行程序,并且它还要服务于多个不定时,不定点的网络请求.所以这类服务的特点是要特别关注稳定性和性能.这类程序如果需要多个协作来提高承载能力,则还要关注部署和扩容的便利性;同时,还需要考虑如何实现某种程度容灾需求.由于多进程协同工作,也带来了开发的复杂度,这也是需要关注的问题. 功能约束,是架构设计决定性因素.基于游戏业务的功能特征,对服务器端系统来说,有以下几个特殊的需求: 游戏和玩家的数据存储落地 对玩家交互数据进行广播和同步 重要逻辑要在服务器上运

分布式游戏服务器端框架 Firefly

Firefly是免费.开源.稳定.快速扩展.能 "热更新"的分布式游戏服务器端框架,采用Python编写,基于Twisted框架开发.它包括了开发框架和数据库缓存服务等各种游戏服务器基础服务,节省大量游戏开发的工作时间,真正做到让使用者把精力放在游戏玩法逻辑上.用它可以搭建自定义的分布式架构,只需要修改相应的配置文件即可. 优势特性 采用单线程多进程架构,支持自定义的分布式架构: 方便的服务器扩展机制,可快速扩展服务器类型和数量: 与客户端采用TCP长连接,无需考虑粘包等问题: 封装数

专访阿里云游戏首席架构师李刚:如何解决云服务技术两大痛点?

对于如今的游戏行业来说,云服务早已不是什么新鲜的话题.一定程度上,不论是近期兴起的手游,还是曾经的端游和页游,如今都会或多或少地运用到云计算功能.在众多"云厂商"中,如果从技术角度来看,阿里云无疑是经验资历最老的团队之一.据悉今年上半年,阿里云已占据将近50%的云服务市场份额. 来源:IDC 2008年9月,阿里巴巴正式确定了"云计算"战略,1年后阿里云正式成立.阿里云通过搭建原创底层代码研发出了"飞天"云操作系统.同时为了满足阿里旗下淘宝等核心

《Android 3D 游戏案例开发大全》——6.3节游戏的架构

6.3 游戏的架构Android 3D 游戏案例开发大全本节主要介绍本游戏的类框架,通过本节的介绍,读者可以进一步了解本游戏的开发过程,为后面要开发的代码部分打下坚实的基础. 6.3.1 各个类简要介绍为了使读者可以更好地了解各个类的作用,本小节将本游戏中用到的所有类分为4部分进行介绍,而每个类的代码将在后面的小节中相继给出. 1.公共类Activity的实现类TXZActivity.TXZActivity是本游戏中的主控制类,此类继承自Activity,是整个游戏的控制类,同时也是整个游戏的入

分享值得收藏的Yupoo(又拍网)系统架构【绝对干货】

Yupoo!(又拍网) 是目前国内最大的图片服务提供商,整个网站构建于大量的开源软件之上.以下为其使用到的开源软件信息: 操作系统:CentOS.MacOSX.Ubuntu 服务器:Apache.Nginx.Squid 数据库:MySQLmochiweb.MySQLdb 服务器监控:Cacti.Nagios. 开发语言:PHP.Python.Erlang.Java.Lua 分布式计算:Hadoop.Mogilefs. 日志分析:AWStats 任务管理:Redmine 消息系统:RabbitMQ

游戏引擎竞争升级

李晶 当手机游戏摇身成为移动互联网上最炙手可热的应用, 手机浏览器巨头们围绕游戏引擎展开了新的角逐.用浏览器搭建HTML5(用于描述网页文档的一种标记语言)平台,聚集大量游戏开发者,是手机浏览器厂商转型的必然之路,这是它们发起"平台化"运动之后的进一步蜕变. 2月26日,全球最大的手机浏览器厂商Opera欧朋在西班牙举办的2013世界移动通讯大会(MWC)发布了一款游戏处理引擎产品--欧朋Sphinx.这款全球首款基于硬件渲染的HTML5 游戏处理引擎的诞生将大幅提升HTML5 游戏性

游戏云架构方案介绍

游戏云:www.game.aliyun.con 为游戏行业用户提供多类型.多场景的成熟部署架构参考方案,技术文档与部署架构优化服务. 游戏云如何解决游戏部署的五大问题: 不让等待成为遗憾 云服务器的多线独享BGP带宽,国内最优网络,完美解决玩家南北互通问题.启用CDN服务,解决网络带宽小.用户访问量大.网点分布不均等问题. 二.坚不可催的护盾 频繁遭遇大规模攻击,安全问题如何解决? 开启云盾服务,为已部署游戏的云服务器提供防DDoS.后门清除.漏洞和木马检测等安全功能,全面提供安全防护服务. 三