下图是在使用RDMAStack时的IO路径,可以看出,整个异步读写流程都是EventCenter在承担主要工作。
Tag: Ceph
Ceph AsyncMessenger 简析 II
在IO栈的优化中,同步改异步是很常用的一种方法,往往可以提高系统的吞吐率,Ceph Messenger就是利用Linux的阻塞异步IO机制,以及自身设计的队列结构来实现对Event的异步处理,进而获取了比Simple Messenger优越很多的性能。Ceph的异步机制根据EventCenter::EventDriver的不同实例可以使用几种模型,本文讨论的是基于epoll机制的Ceph Async + RDMAStack下的IO路径
Ceph Async机制的核心即是EventCenter,下图简述了EventCenter对这一机制的实现
在Async机制中,Ceph Msg模块将所有的异步事件分为两类:
- handler固定、”定点”执行的file_event,通常用于频繁执行的routine,
- handler形式多样但”顺便”执行的external_event
file events
file events的核心结构是EventCenter::vectorfile_events,该vector以fd为索引封装了一组FileEvents实例,每个FileEvents实例都包含两个handler:readcb用于处理fd可读,writecb用于fd可写。系统通过create_file_event()将fd及其handler注册到file_events。最终,所有的file_events注册的fd都会通过epoll_ctl()将其注册到内核,并通过在Worker中调用epoll_wait()来实现异步阻塞IO。
external events
相比于file_events与特定的fd绑定,external events要自由的多,external_events就是一个EventCallback的deque,使用方式与fd无关, 所以只要EventCallback及其子类的实例,都可以在需要的时候注册到其中以此让Worker线程执行之。值得注意的是,在Ceph的设计中,file event和external event并不是割裂的,事实上,external event依赖于在file_events中设置代理才能工作,通过将管道的读端注册为file event,dispatch_event_external()首先会将相应的EventCallback实例入队,再向管道的写端notify_send_fd写入一个字符,如此一来管道的读端notify_receive_fd就会变的可读,进而通过的epoll机制wakeup相应的Worker工作线程,Worker工作线程首先会回调发生事件的notify_receive_fd的readcb,该cb只是将在写端写入的字符读出,之后,Worker就会将external event全部回调一遍,即将其从队列清空。
Ceph AsyncMessenger 简析 I
作为分布式存储系统,Msg(src/msg)模块可谓是Ceph的基石之一。Ceph发展到Luminous ,已经支持的3大通信机制:simple,async和xio,其中simple历史最为悠久,是Ceph最早的通信模块,原理简单但性能较差。async作为后起之秀,优良的性能使其自Luminous开始已经作为了缺省msg方案。xio拥有众多实验特性,目前距离生产环境还有很大距离。
在使用OOP设计一个通信模块时,往往少不了以下几个抽象:
- Messenger 用于在最高层次管理所有通信,通常包括通信策略,工作线程等等
- Connection表示对一个连接的抽象,经常会设计一个状态机来供上层管理该Connection
- Message是对消息的封装,通常包含’Header + Data + Checking’ 几部分,Message和报文流的常常需要转换方法,Message->buf:encode(),Message<-buf:decode()
- Stack 负责实现真实的通信,比如TCP/IP协议栈、RDMA协议栈
以此为基础,Ceph Msg框架就显得十分清晰,下面就是Async机制核心的封装:AsyncMessenger,Processor,AsyncConnection,NetworkStack,Worker,EventCenter,Message,本文将逐个讨论这些角色。
上图是Ceph Msg模块框图,可以看出,msg模块可以分为3个层次:async/simple/xio + Generic NetworkStack + Specific NetworkStack,上层将”通信机制”抽象出来,下层聚焦于协议栈,包括硬件无关的部分以及硬件相关的部分,比如RDMAStack针对配置了IB卡的存储节点,DPDKStack用于使用X86 DPDK技术的存储节点,而PosixStack则是Linux原生的Socket通信接口。
Continue reading