RedRabbit基于BrokerPattern构建办事器
添加时间:2013-7-7 点击量:
RedRabbit
经典网游办事器架构
该图省略了专门用处的dbserver、guildserver等用于专门功能的server,该架构的长处有:
- l LoginGate相当于DNS,可以动态的包管GameGate之间负载均衡。
- l 因为Clientt的逻辑操纵都是由GameServer处理惩罚的,而Client的消息恳求都被GameGate转发到GameServer上,所以在不合的GameGate上的client仍能呈如今雷同的场景里。若在不合的场景,又可以将其分布在不公的GameServer处理惩罚,从而实现了GameServer的Scalability。
- 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恳求送达给Serverr,GameGate就是扮演的这种Broker。总的来说BrokerPattern中,Broker具有如下功能:
- l LookUp办事,帮助Client定位Server
- l Route办事,实现Client和Server之间的消息转发
- l 注册办事,Server必必要注册到Broker上如许Broker才干供给LookUp和Route功能。
BrokerPattern示意图:
所以今天的主题是如何哄骗BrokerPattern构建及时的办事器框架。
RedRabbit
目标:
- l 节点之间通信采取异步消息、回调模式
- l Server必须很轻易注册到Broker上
- l C++/EPOOL实现收集通信,包管及时性,支撑逻辑层python实现,支撑热更新
- l 该框架可以或许轻易的构建单个区组的构架
- l 该框架支撑跨区组通信,这也是Broker模式的上风,节点之间通信不须要知道对方的地位,只须要知道对方的名称
这个框架的名字叫RedRabbit。
FFRPC
起首介绍RedRabbit的通信组件ffrpc,ffrpc中有如下5种角色:
- l BrokerMaster,负责经管所有的BrokerSlave,所有Slave须要注册到BrokerMaster上,BrokerMaster同步所有信息给所有节点。
- l BrokerSlave负责转发Client和Service之间的消息。
- l Client为调用Service接口的一方,它经由过程Broker于Service通信,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中的其他组件Gate和Scene
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调用。
须要希罕指出的是,Gate和Scene只是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默示gate的ip、port
- l -brkoker默示作为BrokerMaster启动,一组办事中必须有一个BrokerMaster,若是Broker和Client和Service在同一过程中,Broker专门做了优化,消息会直接从内存间实现传递,避免了收集转发的开销。
Scene
在RedRabbit中的所有Service都是运行在Scene组件之下的。Scene供给了通用的接口,可以和Gate和其他Scene通信,并把接口导入到了python中。Scene接管的Client的恳求都交由Python处理惩罚,所以可以用Scene+Python实现GameServer、DbServer等各类专用的办事器。Scene组件供给的功能有:
- l 验证Client有效性,scene@0必须供给此接口
- l 处理惩罚Client Enter消息,Scene第一次进入该Scene,触发此事务
- l 处理惩罚Client Offline消息,Client下线,触发此事务
- l Scene供给转发、多播、广播、封闭连接等接口给python
- l Scene供给按时器接口给python
- l Scene供给异步操纵Mysql、Sqlite的接口,采取异步加回调,从而避免梗阻主线程
- l Scene供给了一套消息派发框架,支撑client和python通信的和谈包含json、thrift、protobuf。
应用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
该示例中把gate和scene启动到了一个办事器法度上,实际上经由过程调剂参数,二者可以启动到不合过程中,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
print(process_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())
print(loading.......)
总结:
- l Ffrpc是基于BrokerPattern思惟实现的异步消息+回调通信库。
- l 应用python构建及时办事器完全可以做到,在一些页游和手游项目尤其合适。确保高及时性的建议一是把数据在内存中操纵,二是io操纵异步化。
- l RedRabbit支撑Client与Python的通信和谈有Json、thrift、protobuf。我小我最喜好thrift。
- l RedRabbit支撑跨区组通信,经由过程BrokerBridge把GroupA和GroupB的BrokerMaster连通起来。示例:
启动BrokerBridge:
./app_redrabbit -broker tcp://127.0.0.1:10241
启动GroupA的BrokerMaster:
./app_redrabbit -broker tcp://127.0.0.1:10242 -bridge_broker GroupA@tcp://127.0.0.1:10241
启动GroupB的BrokerMaster:
./app_redrabbit -broker tcp://127.0.0.1:10242 -bridge_broker GroupB@tcp://127.0.0.1:10241
在GroupA的python中就可以如许调用GroupB的接口:
Ffext.bridge_call(‘GroupB’, cmd, msg, callback)
项目源码:
https://github.com/fanchy/RedRabbit
TODO:
构建跨服的demo示例, 下一篇。
真正的心灵世界会告诉你根本看不见的东西,这东西需要你付出思想和灵魂的劳动去获取,然后它会照亮你的生命,永远照亮你的生命。——王安忆《小说家的十三堂课》
RedRabbit
经典网游办事器架构
该图省略了专门用处的dbserver、guildserver等用于专门功能的server,该架构的长处有:
- l LoginGate相当于DNS,可以动态的包管GameGate之间负载均衡。
- l 因为Clientt的逻辑操纵都是由GameServer处理惩罚的,而Client的消息恳求都被GameGate转发到GameServer上,所以在不合的GameGate上的client仍能呈如今雷同的场景里。若在不合的场景,又可以将其分布在不公的GameServer处理惩罚,从而实现了GameServer的Scalability。
- 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恳求送达给Serverr,GameGate就是扮演的这种Broker。总的来说BrokerPattern中,Broker具有如下功能:
- l LookUp办事,帮助Client定位Server
- l Route办事,实现Client和Server之间的消息转发
- l 注册办事,Server必必要注册到Broker上如许Broker才干供给LookUp和Route功能。
BrokerPattern示意图:
所以今天的主题是如何哄骗BrokerPattern构建及时的办事器框架。
RedRabbit
目标:
- l 节点之间通信采取异步消息、回调模式
- l Server必须很轻易注册到Broker上
- l C++/EPOOL实现收集通信,包管及时性,支撑逻辑层python实现,支撑热更新
- l 该框架可以或许轻易的构建单个区组的构架
- l 该框架支撑跨区组通信,这也是Broker模式的上风,节点之间通信不须要知道对方的地位,只须要知道对方的名称
这个框架的名字叫RedRabbit。
FFRPC
起首介绍RedRabbit的通信组件ffrpc,ffrpc中有如下5种角色:
- l BrokerMaster,负责经管所有的BrokerSlave,所有Slave须要注册到BrokerMaster上,BrokerMaster同步所有信息给所有节点。
- l BrokerSlave负责转发Client和Service之间的消息。
- l Client为调用Service接口的一方,它经由过程Broker于Service通信,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中的其他组件Gate和Scene
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调用。
须要希罕指出的是,Gate和Scene只是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默示gate的ip、port
- l -brkoker默示作为BrokerMaster启动,一组办事中必须有一个BrokerMaster,若是Broker和Client和Service在同一过程中,Broker专门做了优化,消息会直接从内存间实现传递,避免了收集转发的开销。
Scene
在RedRabbit中的所有Service都是运行在Scene组件之下的。Scene供给了通用的接口,可以和Gate和其他Scene通信,并把接口导入到了python中。Scene接管的Client的恳求都交由Python处理惩罚,所以可以用Scene+Python实现GameServer、DbServer等各类专用的办事器。Scene组件供给的功能有:
- l 验证Client有效性,scene@0必须供给此接口
- l 处理惩罚Client Enter消息,Scene第一次进入该Scene,触发此事务
- l 处理惩罚Client Offline消息,Client下线,触发此事务
- l Scene供给转发、多播、广播、封闭连接等接口给python
- l Scene供给按时器接口给python
- l Scene供给异步操纵Mysql、Sqlite的接口,采取异步加回调,从而避免梗阻主线程
- l Scene供给了一套消息派发框架,支撑client和python通信的和谈包含json、thrift、protobuf。
应用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
该示例中把gate和scene启动到了一个办事器法度上,实际上经由过程调剂参数,二者可以启动到不合过程中,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
print(process_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())
print(loading.......)
总结:
- l Ffrpc是基于BrokerPattern思惟实现的异步消息+回调通信库。
- l 应用python构建及时办事器完全可以做到,在一些页游和手游项目尤其合适。确保高及时性的建议一是把数据在内存中操纵,二是io操纵异步化。
- l RedRabbit支撑Client与Python的通信和谈有Json、thrift、protobuf。我小我最喜好thrift。
- l RedRabbit支撑跨区组通信,经由过程BrokerBridge把GroupA和GroupB的BrokerMaster连通起来。示例:
启动BrokerBridge:
./app_redrabbit -broker tcp://127.0.0.1:10241
启动GroupA的BrokerMaster:
./app_redrabbit -broker tcp://127.0.0.1:10242 -bridge_broker GroupA@tcp://127.0.0.1:10241
启动GroupB的BrokerMaster:
./app_redrabbit -broker tcp://127.0.0.1:10242 -bridge_broker GroupB@tcp://127.0.0.1:10241
在GroupA的python中就可以如许调用GroupB的接口:
Ffext.bridge_call(‘GroupB’, cmd, msg, callback)
项目源码:
https://github.com/fanchy/RedRabbit
TODO:
构建跨服的demo示例, 下一篇。