Linux SCSI 子系统 I

在内核中,不仅要考虑SCSI协议栈本身,还必须和内核的DD框架融合到一起。
在内核中SCSI子系统的主要功能是:

  1. 探测SCSI设备,在内存建立可供设备驱动使用的数据结构
  2. 在sysfs文件系统中构造SCSI子系统的目录树
  3. SCSI高层驱动绑定SCSI设备,在内存中建立对应的数据结构
  4. 提供错误修复API,在SCSI命令错误和超时后被调用

如上图所示, 在内核中,SCSI 子系统被分为三层,从上到下分别是提供request<->CDB转换、设备级驱动能力的HLDD(High Level Device Driver),提供注册回调等公共功能的CommonService层,以及提供某种具体的SCSI协议栈实现的LLDD(Low Level Device Driver)

由此可见,SCSI子系统同IDE等接口驱动一样,位于内核IO栈中的最底层。例如,将一张使用一张PCI接口的SCSI适配器插入PCI插槽后,相应的PCI driver 就会在合适的时候match到相应的PCI device,并通过SCSI Common Service中提供的接口向SCSI LLDD 注册一个SCSI适配器对象及其操作方法,之后,
当上层的Block层将准备好的request提交到SCSI子系统中HLDD中的相应驱动,HLDD将request转换为CDB(__make_request()->__generic_unplug_device()->scsi_request_fn()->blk_peek_request()->sd_prep_fn()->scsi_setup_fs_cmnd()->scsi_init_io() ),并回调当初注册的接口((__make_request()->__generic_unplug_device()->scsi_request_fn()->scsi_dispatch_cmd()->scsi_host_template.queuecommand()),将CDB通过相应的SCSI协议栈发出。

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模块将所有的异步事件分为两类:

  1. handler固定、”定点”执行的file_event,通常用于频繁执行的routine,
  2. 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