spymemcached源码中Reactor模式分析

不想你离开。 提交于 2019-12-09 11:30:13

简介

spymemcached 是一个 memcached 的客户端, 使用 NIO 实现。采用Reactor模式实现,单线程,高性能Memcached客户端。

spymemcached源码分析:http://my.oschina.net/astute/blog/93492

Reactor模式介绍

所谓reactor模式,其实是event-driven pattern在网络服务设计中的应用,以平衡CPU与IO速率,最大化CPU资源与IO资源的利用率;

先来看看经典的服务器设计:

经典网络服务接受客户端请求,响应请求过程可以抽象为以下步骤:

  1. 读取请求数据 : read
  2. 解码数据: decode
  3. 计算:compute
  4. 编码数据:encode
  5. 发送数据:send

网络服务所有动作被抽象为这个五个步骤的handler;可能每个handler有单独线程执行,或者由一个线程顺序执行;

这种经典设计中存在以下问题:

  1. 每个连接分配一个线程,而每个连接发送请求数据较少,导致大量空闲线程;
  2. 大量线程上下文切换和锁竞争

为了解决上述问题,采用两个方法实现:


  1. 采用分治的思想,将连接划分为更小粒度的非阻塞任务:将用户连接划分为 多个用户请求,每个请求一个线程处理;减少 请求间空闲时间占用线程
  2. 采用事件处理模式,分派可执行任务;通过IO 事件触发 handler 处理


采用事件处理模式的单线程Reactor模式:

单线程Reactor 处理 连接请求,所有用户请求都在同一个线程中;通过IO事件触发相应的操作;IO事件触发机制可参考java nio机制;

单线程版本的Reactor模式,还有以下问题:

  1. 触发事件处理 与 处理事件 在同一个线程中;减缓了Reactor的事件触发及时性
  2. 所有请求必须等待之前请求中IO操作之外的处理过程
  3. 无法解决CPU与IO速率不一致问题
  4. 不能有效利用多核优势

为解决上述问题,采用多线程设计方案的Reactor模式:

多线程版本的Reactor模式,有以下优势:

  1. Reactor可以快速触发handler执行
  2. IO操作以外操作由线程池中线程独立处理
  3. Reactor 线程满负荷 IO操作
  4. 平衡CPU 与 IO 速率

reactor模式就介绍到此,具体看下spymemcached中reactor模式的应用吧

spymemcached中Reactor模式实现

spymemcached中reactor模式设计到以下概念:

  1. IO线程:MemcachedConnection 负责处理
  2. 工作线程:调用spymemcached操作的线程;通常是应用线程,例如tomcat线程等等;

工作线程职责:

  1. 通过MemcachedClient提交操作请求给MemcachedConnection
  2. MemachedClient提交操作过程:实例化异步操作回执OperationFuture(该回执都会实例化一个CountDownLatch(1));通过OperationFactory 生成定制Callback操作的Operation对象;将Operation操作加入对应ShardedNode 的inputQ;返回异步结果回执OperationFuture对象
  3. 调用OperationFuture对象的get操作阻塞在CountDownLatch,等待后台IO线程,调用countDown;

IO线程职责:

  1. 由MemcachedClient初始化启动后台MemcachedConnection 线程,接受工作线程提交操作:从inputQ拷贝到writableQ;发送操作请求到Memcached服务器;添加操作到readQ,并把操作从writableQ删除;修改监听IO事件
  2. 执行select操作,获取感兴趣IO事件
  3. 执行handleIO处理:根据SelectKey发生事件类型:执行读取操作 or 写入操作;
  4. 当IO操作完成后,调用Operation Callback对象的receivedStatus设置回执结果;调用countDown释放阻塞的工作线程;

由此可见,spymemcached Reactor模式实现中,工作线程相当于客户端请求; IO线程相当于单线程Reactor设计中的Reactor负责接收请求,处理请求;spymemcached对数据解码部分可以扩展实现线程池方式提供解码计算,无需占用Reactor线程资源,使得Reactor线程满负荷IO操作和事件触发;


在spymemcached的Reactor设计中:

MemcachedClient负责接收请求

MemcachedConnection负责处理IO请求

同时还可以扩展支持线程池TranscodeService对解码计算提供异步线程支持; 这也是OperationFuture.get()返回值仍未一个Futrue,内部再次调用future.get返回最终数据的原因。


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!