服务通信框架Gaea---client的请求处理模型

Gaea的请求处理模型图

Gaea是一个服务通信框架

 图片来源于“58同城的跨平台高性能,高可用的中间层服务架构设计分享” 

根据上图,我们详细的来说明一下Gaea的客户端,请求处理的过程。

Gaea1.0版本中并没有实现异步化调用,那我们就围绕这同步调用来说明一下。处理过程如下:

1、创建代理

为每一个方法的调用创建代理proxy

final String url = "tcp://demo/NewsService"; //demo服务名 NewsService 接口实现类
  INewsService newsService = ProxyFactory.create(INewsService.class, url);
InvocationHandler handler = new ProxyStandard(type, serviceName, lookup);
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{type},
                handler);

在这里放了一个全局的cache,存储了每一个代理,

private static Map cache = new ConcurrentHashMap(); //key:服务名 value: proxy

创建代理,为每一个方法制定统一的调用入口,每一个方法在真正执行的时候,都将跳转到这里往下执行。也就是说,此方法将代理你所调用的方法,去执行后面的操作。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable

2、等待窗口

在这里我们暂时不讨论服务器的选择等策略,继续说明这个请求处理模型。在这个途中提到了一个很有用的东西,即等待窗口,那到底这个等待窗口到底在Gaea中充当一个什么样的角色呢?在代码中我们可以简单的看到,等待窗口,即是一个Map而已

private ConcurrentHashMap<Integer, WindowData> WaitWindows = new ConcurrentHashMap<Integer, WindowData>();
在这个 等待窗口WaitWindows中Gaea放入了两个个很重要的东西key:session 和 value:WindowData

session是一个随着每一次调用自增长的一个int,它将被写入到Gaea的协议中,用于找到返回数据的归属

private int sessionId; 
private int createSessionId() {
        synchronized (this) { //同步,确保线程安全
            if (sessionId > GaeaConst.MAX_SESSIONID) { //当大于最大值后,从1继续累加
                sessionId = 1;
            }
            return sessionId++;
        }
    }
WindowData是一个对象类型,用于时间通知和存放返回值。
public class WindowData {

	AutoResetEvent _event; //用于事件通知
	byte[] _data; //接受返回值
	private byte flag; //Gaea1.0中没有用到
	private Exception exception; 
...........
}
在send之前,Gaea在 等待窗口waitWindows中注册了这个windowData
socket.registerRec(p.getSessionID());
public void registerRec(int sessionId) {
        AutoResetEvent event = new AutoResetEvent(); 
        WindowData wd = new WindowData(event);
        WaitWindows.put(sessionId, wd);
    }

在发送之前Gaea往等待窗口waitWindows中,利用sessionId注册了windowData,在windowData中Gaea又new了一个AutoResetEvent,用于通知接收程序。

3、数据发送

在发送线程中,直接利用send函数发送了数据,也没有用到等待窗口waitWindows和WindowData用于拥塞控制,而是直接发送

socket.registerRec(p.getSessionID());
  socket.send(data);

在send中,直接添加了协议的头和尾就直接发送了,因此目前还没有实现设计中的拥塞控制

4、数据接收

返回数据的接受,是在创建server,socket时,就启动了一个死循环在接收数据,新版的Gaea中,此处已改为select方式获取数据。

@Override
    public void run() {
        while (true) {
            try {
                for (final CSocket socket : sockets) {
                    try {
                        pool.execute(Handle.getInstance(socket));
                    } catch (Throwable ex) {
                        logger.error(ex);
                    }
                }
                Thread.sleep(1);
            } catch (Throwable ex) {
                logger.error(ex);
            }
        }
    }
真正接收数据实在CSocket.java中
protected void frameHandle() throws IOException, InterruptedException
在frameHandle()中,Gaea从receive中获取到sessionId,因为sessionId是被写入到协议中来回传输的,

通过这个sessionId,很容易的就从等待窗口中取出了WindowData

WindowData wd = WaitWindows.get(pSessionId);
  if (wd != null) {
      wd.setData(pak);
      wd.getEvent().set();
 }
其中wd.setData(pak);就是向windowData中写入返回数据,wd.getEvent().set() 则是通知接收函数,这个sessionId的请求回来了,你可以返回给调用者了。

5、数据返回

因为讲的是同步,其中send,和 receive在同一个request()的方法中,send之后,receive一直在等待着,此次调用的返回

AutoResetEvent event = wd.getEvent();
        int timeout = getReadTimeout(socketConfig.getReceiveTimeout(), queueLen);
        if (!event.waitOne(timeout)) {
            throw new TimeoutException("Receive data timeout or error!timeout:" + timeout + "ms,queue length:" + queueLen);
        }
在这一段代码中,receive通过发送时的sessionId找到windowData,然后获取AutoResetEvent

if(!event.waitOne(timeout)){} 在这里程序将等待这个event的set()函数通知自己,数据已经被返回了,否则等待timeout以后,将不再等待,执行if中的语句,返回超时。超时后,在异常处理中,删除这个等待窗口中的sessionId,则如果再返回,就会因为找不到这个sessionId,而抛弃返回值。

if (socket != null) {
      socket.unregisterRec(p.getSessionID());
 }
至此整个Gaea客户端的请求处理模型就说完了,可以说,整个模型都是围绕这 等待窗口WaitWindows、sessionId、windowData来处理的。





转载于:https://my.oschina.net/le284/blog/176829

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Gaeaphp 是一个基于 flightphp 的 PHP 框架基础环境要求php 5.4 安装WebServer,具体配置方法参见Flight按照要求Php-Memcached扩展,具体配置方法参见pecl结构设计项目目录结构|-app/|    |-configs/    配置文件夹|    |-bootstrap.php   引导文件|-src/      代码目录|    |-libs/       类库方法库|    |  |-classes/|    |  |-functions/|    |-modules/    模块文件夹|    |  |-xxxmodules/|    |  |  |-controller/|    |  |  |-libs/|    |  |  |-model/|    |-templates/|    |  |-default/|-temp/     临时目录|    |-caches/|    |-compiled/|    |-logs/url访问框架采用mvc设计模式开发,采用单一入口方式部署和访问。 访问示例http://yourdomain.com/module/controller/action/param1/param2其中将会访问/src/module/controller.php下的action方法引导文件/app/bootstrap.php引导文件完成了命名空间的注册,扩展模版引擎,以及路由的注册。其中常量定义:ROOT_PATH 系统根目录APP_PATH app目录TEMP_PATH 临时目录SSRC_PATH     系统代码目录WEB_PATH      系统WEB资源目录系统配置所有的配置文件均已数组形式返回。具体配置文件项在/app/configs下|-db.php    数据库(Mysql)配置文件|-memcache.php       缓存(Memcache)配置文件|-route.php     路由配置文件|-smarty.php    模版引擎配置文件|-system.php    系统配置文件系统配置结构为一维数组,各项参数见注释return  array(     'theme'     =>      'default',   //主题     'debug'     =>      true,       //是否调试信息     'log_level' =>      'DEBUG',    //日志打印级别EMERGENCY|ALERT|CRITICAL|ERROR|WARNING|NOTICE|INFO|DEBUG     'cache_expire'  =>  3600,       //缓存时间,单位秒     'prefix'  =>  'sobey_',   //存储键值前缀,包含db和cache );数据库配置结构为二维数组,默认使用default,可参考default结构配置多个数据库配置如testreturn  array(     'default'   =>  array(             'database_type'=>'mysql',             'database_name'=>'ecshop',             'server'=>'127.0.0.1',             'username'=>'root',             'password'=>'123456',             //其他可选参数参见php手册             //http://www.php.net/manual/en/pdo.setattribute.php             'port'=>3306     ),     //test配置非系统默认     'test'      =>  array(         //.........     ), );Memcached配置结构为二维数组,默认使用default,可参考default结构配置多个数据库配置如testreturn array(     'servers'=>array(         //array('域名','端口','权重')      array('127.0.0.1','11211'),     ),     //options为Memcached::setOptions参数     'options'=>array(         //Memcached::OPT_HASH => Memcached::HASH_MURMUR,         //Memcached::OPT_PREFIX_KEY => "widgets"     ), );smarty配置结构为二维数组,默认使用default,可参考default结构配置多个数据库配置如testreturn array(     'servers'=>array(         //array('域名','端口','权重')      array('127.0.0.1','11211'),     ),     'options'=>array(         //Memcached::OPT_HASH => Memcached::HASH_MURMUR,         //Memcached::OPT_PREFIX_KEY => "widgets"     ), );模块modules一个模块的基本结构为,请遵循以下的规则:|-src/      代码目录|    |-modules/    模块文件夹|    |  |-xxxmodules/         模块根目录|    |  |  |-api/    接口文件目录|    |  |  |-controller/     控制器文件夹 |    |  |  |-libs/       工具类库|    |  |  |-model/     模型类库项目开发技巧Core文件Core::config($file,[$key,[$dafault = false,[$reload = false]]])   获取配置文件Core::load_func($func,[$path= '']) 加载函数Core::log($module,$level,$message,[$context = array()]) 日志记录Core::db([$key='default',[$option=array()]]) 获取db实例Core::memcached([$key='default',[$servers=array(),[$options=array()]]]) 获取memcached实例项目函数库一些项目的全局函数位于/src/libs/functions/global.php,该文件会被自动加载。 自己可新建模块的函数库并使用Core::load_func()引入使用模版模版文件位于: /src/teplate/{风格}/sso(模块)下,为smarty语法文件 标签:Gaeaphp  Web框架

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值