Ceph源码分析之Async模块:3. Async+posix的协议栈收发消息模型分析

ceph Async模块提供一种异步收发消息的机制,最底层的异步机制可以查看博文 Ceph源码分析之Async模块:1、异步通信核心模块EventCenter+Epoll,上层的收发消息机制可以查看博文Ceph源码分析之Async模块:2、上层通信模型。因此这里主要介绍的是整个异步消息机制的中间层,即ceph抽象网络协议栈。在L版的ceph中,支持3种Async类型的网络协议栈

  • PosixNetworkStack
  • RMDAStack
  • DPDKStack
    本文主要介绍的是基于Posix协议栈的收发消息模型

收发消息交互模型图

这里写图片描述

下面介绍下几个重要的模块及流程

Processor

Processor是Messenger用来同worker交互的层,每个processor实例对接一个worker实例,从上面我们可以看出实际上Messenger是可以通过stack同worker交互的,那设计Processor主要是为了将那些跟消息传输无关的操作接口封装起来(比如:端口bind,accept连接),这样stack只管做消息传输类型接口的封装即可。

AsyncConnection

每个来自客户端的连接都会分配一个AsyncConnection实例来维护底层已经建立的socket连接,Messenger端会维护一个全局的连接表,用来供上层应用使用。


  • 负责已经建立的连接socket的读写事件及对于的读写事件回调处理,包含了ceph协议栈状态机以及对消息的处理。
  • 读写是直接调用的系统的read/write,不经过Net_handler模块
  • fast 类型dispatcher,直接将MSG会直接转给Messenger
  • 普通类型的dispatcher,将MSG放入DispatcherQueue mqueue队列
  • 每个连接都有一个worker,而这个worker就是当初接受连接的worker,一个worker会负责所有从它建立的连接。

AsyncConnection的维护的ceph状态机待后续分析
DispatchQueue

DispatchQueue的职责就是维护mqueue队列,将mqueue队列的内容按优先级转给Messenger

  • 消息队列mqueue
    开放enqueue入队列接口,用来将MSG放入队列mqueue队列(优先级队列)。
  • 线程
    DispatchQueue内部通过一个线程去处理mqueue,在mqueue没有数据时,会进入线程条件变量等待使进程睡眠。如果有数据入队列时,则会唤醒。
Net_handler

从上图可以看出,Net_handler模块只是负责部分socket的操作,基于这些基础的socket操作,封装了几个接口,比如:

  • create_socket
  • connect
  • generic_connect
  • nonblock_connect
  • set_close_on_exec
  • set_nonblock
  • set_priority
  • set_socket_options

对于已经建立连接的socket的读写则是有AsyncConnection直接通过PosixConnectedSocketdImpl直接调用read/write接口

Worker

Worker被设计寓意一个线程的意思,每个Worker通过EventCenter维护一个自己的事件表。

NetworkStack

NetworkStack被设计用来接受不同的类型的网络传输,比如dpdk、rdma、posix,上图是以PosixStack为例子画的。每个PosixStack主要用来负责管理worker,比如批量创建worker、开启worker监听、开启worker线程、关闭worker线程等。

bind阶段

bind阶段不会涉及到event center事件,它只是在每个worker中新建监听socket,并将worker新建的socket封装后传给每个processor的listen_socket变量。bind之后ceph还不会接受来自客户端的连接请求,接受连接请求的是在ready阶段,Messenger的bind阶段对应的是每个worker线程的listen阶段,worker线程的listen阶段的操作步骤,如下:

  • net._create_socket
  • net.set_nonblock
  • net.set_close_on_exec
  • net.set_socket_options
  • ::bind
  • ::listen
ready阶段

应用添加dispatcher给Messenger的时候,会触发Messenger进入ready()阶段,ready阶段是真正开始接受连接并处理消息的阶段。ready阶段分为两个步骤:

  • stack->start()
    根据worker数,创建对应的std::thread线程,线程函数负责处理当前worker的event center事件处理
  • processor->start()
    调用每个processor的start方法。
    • 给每个worker线程创建监听socket的fd读事件
    • 读事件的回调则是通过accept新建一个连接socket,并将新连接socket上传给AsyncMessenger,AsyncMessenger会给新的连接socket分配一个AsyncConnection实例,并将新连接socket添加到accepting_conns中。分配完AsyncConnection实例之后,会马上让连接进入消息处理阶段,这里存在一个线程死锁的逻辑:不要直接在当前线程上下文下去开始处理消息,理由是当前线程上下文会占了一个从Messenger带来的线程锁,而如果在这个上下文下处理消息,一旦消息处理异常导致线程挂死,意味着Messenger的那把线程锁将无人释放,从而导致整个worker集群全部阻塞在加锁状态。因此这里需要添加一个external外部事件,让worker线程先行退出当前堆栈,等待下次事件处理的时候再处理接受消息,因为这时候的线程上下文是不带锁的。

结束语

Async系列博文只是指出了大家在理解ceph Async网络模块的时候一些痛点,本系列博文的受众更偏向于打算自己阅读一遍或者正在阅读ceph Async模块的人。这个系列的3篇都是作者在阅读Async模块之后理解和总结出来的一些痛点于大家分享,对于AsyncConnection的状态机这块等待后续有时间再更新。

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值