} } }

    RedRabbit基于BrokerPattern构建办事器

    添加时间:2013-7-7 点击量:

    RedRabbit


    经典网游办事器架构



    该图省略了专门用处的dbserverguildserver等用于专门功能的server,该架构的长处有:



    • l LoginGate相当于DNS,可以动态的包管GameGate之间负载均衡。

    • l 因为Clientt的逻辑操纵都是由GameServer处理惩罚的,而Client的消息恳求都被GameGate转发到GameServer上,所以在不合的GameGate上的client仍能呈如今雷同的场景里。若在不合的场景,又可以将其分布在不公的GameServer处理惩罚,从而实现了GameServerScalability

    • l GameServer一般是由C++与脚本连络实现的。因为数据都是在内存中处理惩罚并且大项目组的IO操纵(收集、数据库等)都被异步化,所以包管了很是高的及时性。


    毛病是:



    • l 各个节点之间经由过程socket进行异步通信,测试过程叫错杂。

    • l 各个节点往往都须要交互,这时就涉及到了谁连谁的题目,懂得和设计架构的收集拓扑也变得不太轻易,响应的设备也会叫繁琐,排错的难度也较大。

    • l GameServer因为是C++主说话实现,不免会涉及到溃散和内存泄目,采取C++与脚本连络很大程度上缓解了这个题目,实际上越来越多的逻辑操纵都是放到脚本中实现。

    • l 因为该架构必须正确的设备连接关系,不然不克不及正常工作,对于运维而言也并不轻松。


     


    评论辩论完经典网游的办事器架构,今天的主题也呼之欲出了,但在此之前,先说一下该架构的核心思惟,若是你读过《面向模式的软件架构.4分布式策画的模式说话》你也许想到了BrokerPattern,其核心思惟是经由过程Broker层,促使Server的地位对于Client对峙透明,client经由过程Broker找到对应的Server处理惩罚恳求,Serverr是如何分布的、数量几许,Client都不受影响。Broker可以存在两种模式,一种是类似于DNS供给的LookUp办事,它只是帮助Client定位到Server的地位,Client直接连接到Serverr进行通信。LoginGate扮演的就是这种Broker。别的一种Broker直接将Client恳求送达给ServerrGameGate就是扮演的这种Broker。总的来说BrokerPattern中,Broker具有如下功能:



    • l LookUp办事,帮助Client定位Server

    • l Route办事,实现ClientServer之间的消息转发

    • l 注册办事,Server必必要注册到Broker上如许Broker才干供给LookUpRoute功能。


    BrokerPattern示意图:


     


     


    所以今天的主题是如何哄骗BrokerPattern构建及时的办事器框架。


    RedRabbit


    目标:



    • l 节点之间通信采取异步消息、回调模式

    • l Server必须很轻易注册到Broker

    • l C++/EPOOL实现收集通信,包管及时性,支撑逻辑层python实现,支撑热更新

    • l 该框架可以或许轻易的构建单个区组的构架

    • l 该框架支撑跨区组通信,这也是Broker模式的上风,节点之间通信不须要知道对方的地位,只须要知道对方的名称


    这个框架的名字叫RedRabbit


    FFRPC


    起首介绍RedRabbit的通信组件ffrpcffrpc中有如下5种角色:



    • l BrokerMaster,负责经管所有的BrokerSlave,所有Slave须要注册到BrokerMaster上,BrokerMaster同步所有信息给所有节点。

    • l BrokerSlave负责转发ClientService之间的消息。

    • l Client为调用Service接口的一方,它经由过程BrokerService通信,Client不知道Service的具体地位,它只是知道当前与之通信的Service名称。

    • l Service供给给Client调用的接口,并把接口注册到Broker上,Service若调用了其他的Service的接口,则相对于其他Service其为Client角色。

    • l BrokerBridge负责桥接各个brokerMaster,每一个BrokerMaster负责一组办事,BrokerBridge使Client调用其他组接口和调用本组的接口一样轻易,因为只须要指定对方办事名称即可。


    各个角色示意图:


     


    应用FFRPC实现的Echo办事实例代码:


    http://www.cnblogs.com/zhiranok/archive/2013/06/06/ffrpc.html


    RedRabbit中的其他组件GateScene


    Gate


    外网接入的client有些特别,须要必然的安然处理惩罚。Gate是专门用于接入外部Client的组件。Gate的感化有:



    • l Client的第一个消息必须为验证消息,Gate 并没有验证Client的才能,它调用Scene@0的接口处理惩罚

    • l Scene@0经由过程验证后将Client将被分派独一的SessionId

    • l Client的所有消息都被Gate转发到对应的Scene上,Scene可以把握Gate接口切换某个Client到其他Scene

    • l Gate供给转发消息、多播、广播、断开连接等接口公scene调用。


    须要希罕指出的是,GateScene只是RedRabbit的组件,RedRabbit经由过程制订不合的启动参数来断定开启哪些组件。示例:



    • l ./app_redrabbit -gate gate@0 -broker tcp://127.0.0.1:10241 -gate_listen tcp://121.199.21.238:10242

    • l -gate 默示gate的名称,scene经由过程名称调用其接口



    • l -gate_listen默示gateipport

    • l -brkoker默示作为BrokerMaster启动,一组办事中必须有一个BrokerMaster,若是BrokerClientService在同一过程中,Broker专门做了优化,消息会直接从内存间实现传递,避免了收集转发的开销。


    Scene


    RedRabbit中的所有Service都是运行在Scene组件之下的。Scene供给了通用的接口,可以和Gate和其他Scene通信,并把接口导入到了python中。Scene接管的Client的恳求都交由Python处理惩罚,所以可以用Scene+Python实现GameServerDbServer等各类专用的办事器。Scene组件供给的功能有:



    • l 验证Client有效性,scene@0必须供给此接口

    • l 处理惩罚Client Enter消息,Scene第一次进入该Scene,触发此事务

    • l 处理惩罚Client Offline消息,Client下线,触发此事务

    • l Scene供给转发、多播、广播、封闭连接等接口给python

    • l Scene供给按时器接口给python

    • l Scene供给异步操纵MysqlSqlite的接口,采取异步加回调,从而避免梗阻主线程

    • l Scene供给了一套消息派发框架,支撑clientpython通信的和谈包含jsonthriftprotobuf


    应用RedRabbit构建的demo示例:


    http://ffown.sinaapp.com/flash/


    批改名称,点击flash的连接按钮,进入发消息,右侧的python脚本为办事器python的实现,批改右侧脚本点保存按钮,在flash中输入reload即可实现热更新!!!!


    该办事器启动的参数是:


    ./app_redrabbit -gate gate@0 -broker tcp://127.0.0.1:10241 -gate_listen tcp://121.199.21.238:10242 -python_path ./ -scene scene@0


    该示例中把gatescene启动到了一个办事器法度上,实际上经由过程调剂参数,二者可以启动到不合过程中,RedRabbit经由过程参数开启组件,而组件之间是经由过程Broker建树接洽的。


    对应的python代码:


     



     coding=UTF-8
    
    import os
    import time
    import ffext

    def GetNowTime():
    return time.strftime(%Y-%m-%d %H:%M:%S, time.localtime(time.time()))

    class player_mgr_t(object):
    def __init__(self):
    self.all_players
    = {}
    def get(self, session_id_):
    return self.all_players.get(session_id_)
    def remove(self, session_id_):
    del self.all_players[session_id_]
    def add(self, session_id_, player):
    self.all_players[session_id_]
    = player
    def size(self):
    return len(self.all_players)
    def idlist(self):
    return self.all_players.keys()

    class player_t(object):
    def __init__(self, session_id_):
    self.session_id
    = session_id_;
    def id():
    return self.session_id

    这个润饰器的意思是注册process_chat函数接管cmd=1的消息
    @ffext.session_call(1
    def process_chat(session_id, msg):
    content
    = msg[0]
    if content == reload:
    os.system(
    ./_code.sh
    ret
    = ffext.reload(main重载此脚本
    ffext.broadcast_msg_session(1, <b><font color=#ff0000> main.py已完成重载 %s</font></b>(str(ret)))
    return

    printprocess_chat session_id=%s content=%s(session_id, content))

    ret
    = <font color=#008000>[%s %s]:</font>%s(session_id, GetNowTime(), content)
    ffext.broadcast_msg_session(
    1, ret)


    这个润饰器的意思是注册下面函数处理惩罚验证client账号暗码,
    session_key为账号暗码组合体,client第一个包必为登岸包
    @ffext.session_verify_callback
    def my_session_verify(session_key, online_time, ip, gate_name):
    return [session_key]须要返回数组,验证成功,第一个元素为分派的id,
    第二个元素可以不设置,若设置gate会返回给client,login gate的时辰
    须要第二个元素返回分派的game gate

    此润饰器的感化是注册下面函数处理惩罚用户下线
    @ffext.session_offline_callback
    def my_session_offline(session_id, online_time):
    content
    = <font color=#ff0000>[%s %s] offline </font>(session_id, GetNowTime())
    ffext.broadcast_msg_session(
    1, content)
    ffext.singleton(player_mgr_t).remove(session_id)
    ffext.broadcast_msg_session(
    1, <font color=#ff0000>当前在线:</font>
    ffext.broadcast_msg_session(
    1, ffext.singleton(player_mgr_t).idlist())

    此润饰器的感化是注册下面函数处理惩罚client切换到此场景办事器
    @ffext.session_enter_callback
    def my_session_enter(session_id, _scene, extra_data):
    单播接口
    ffext.send_msg_session(session_id, 1, <font color=#ff0000>测试单播接口!迎接你! </font>
    content
    = <font color=#ff0000>[%s %s] online </font>(session_id, GetNowTime())
    ffext.broadcast_msg_session(
    1, content)
    player
    = player_t(session_id)
    ffext.singleton(player_mgr_t).add(session_id, player)
    ffext.broadcast_msg_session(
    1, <font color=#ff0000>当前在线:</font>
    ffext.broadcast_msg_session(
    1, ffext.singleton(player_mgr_t).idlist())

    printloading.......


     



     


    总结:



    • l Ffrpc是基于BrokerPattern思惟实现的异步消息+回调通信库。

    • l 应用python构建及时办事器完全可以做到,在一些页游和手游项目尤其合适。确保高及时性的建议一是把数据在内存中操纵,二是io操纵异步化。

    • l RedRabbit支撑ClientPython的通信和谈有Jsonthriftprotobuf。我小我最喜好thrift

    • l RedRabbit支撑跨区组通信,经由过程BrokerBridgeGroupAGroupBBrokerMaster连通起来。示例:


    启动BrokerBridge


    ./app_redrabbit  -broker tcp://127.0.0.1:10241


    启动GroupABrokerMaster:


    ./app_redrabbit  -broker tcp://127.0.0.1:10242 -bridge_broker GroupA@tcp://127.0.0.1:10241


    启动GroupBBrokerMaster:


    ./app_redrabbit  -broker tcp://127.0.0.1:10242 -bridge_broker GroupB@tcp://127.0.0.1:10241


    GroupApython中就可以如许调用GroupB的接口:


    Ffext.bridge_call(‘GroupB’, cmd, msg, callback)


     项目源码:


    https://github.com/fanchy/RedRabbit


    TODO:


    构建跨服的demo示例, 下一篇。


    真正的心灵世界会告诉你根本看不见的东西,这东西需要你付出思想和灵魂的劳动去获取,然后它会照亮你的生命,永远照亮你的生命。——王安忆《小说家的十三堂课》
    分享到: