ceph-msg-messager|simple 代码分析

目录

ceph的网络通信

ceph网络通信模式分类

simple框架

message数据格式

Ceph通信模块代码分析

ceph网络通信模块类说明

1. Async通信模块角色

2. Async通信模式

Ceph日志和调试


现在ceph的网络是async,simple不用,建议只做了解不不必花太多时间在上面。

ceph的网络通信

原文:Ceph Async Messager · 大专栏

ceph 网络层代码分析(1)_shuningzhang的专栏-CSDN博客

Ceph通信框架设计模式

设计模式:订阅发布模式(Subscribe/Publish),又名观察者模式,它意图是“定义对象间的一种一对多的依赖关系,
当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。

 Ceph通信框架流程图

步骤

  • Accepter监听peer的请求, 调用 SimpleMessenger::add_accept_pipe() 创建新的 Pipe 到 SimpleMessenger::pipes 来处理该请求。
  • Pipe用于消息的读取和发送。该类主要有两个组件,Pipe::Reader,Pipe::Writer用来处理消息读取和发送。
  • Messenger作为消息的发布者, 各个 Dispatcher 子类作为消息的订阅者, Messenger 收到消息之后, 通过 Pipe 读取消息,然后转给 Dispatcher 处理。
  • Dispatcher是订阅者的基类,具体的订阅后端继承该类,初始化的时候通过 Messenger::add_dispatcher_tail/head 注册到 Messenger::dispatchers. 收到消息后,通知该类处理。
  • DispatchQueue该类用来缓存收到的消息, 然后唤醒 DispatchQueue::dispatch_thread 线程找到后端的 Dispatch 处理消息。

ceph_message_2

Ceph通信框架类图

架构上采用 Publish/subscribe(发布/订阅) 的设计模式.

simple框架

src/common/config_opts.h
 
OPTION(ms_type, OPT_STR, "simple")


SimpleMessenger 是simple框架具体的实现。
从这个构造函数中可以看到SimpleMessenger 会在构造函数中分别建立结束accepter和发送dispatch_queue 两个线程 

SimpleMessenger::SimpleMessenger(CephContext *cct, entity_name_t name,
                                 string mname, uint64_t _nonce)
    : SimplePolicyMessenger(cct, name, mname, _nonce),   accepter(this, _nonce),
      dispatch_queue(cct, this, mname),
      reaper_thread(this),
      nonce(_nonce),
      lock("SimpleMessenger::lock"), need_addr(true), did_bind(false),
      global_seq(0),
      cluster_protocol(0),
      reaper_started(false), reaper_stop(false),
      timeout(0),
      local_connection(new PipeConnection(cct, this))
{
    ANNOTATE_BENIGN_RACE_SIZED(&timeout, sizeof(timeout),
                               "SimpleMessenger read timeout");
    init_local_connection();

accepter和发送dispatch_queue 线程 建立代码

//这里以accepter为例看看是如何建立接受线程的
class Accepter : public Thread
{
    SimpleMessenger *msgr;
    bool done;
    int listen_sd;
    uint64_t nonce;
    int shutdown_rd_fd;
    int shutdown_wr_fd;
    int create_selfpipe(int *pipe_rd, int *pipe_wr);
public:
    Accepter(SimpleMessenger *r, uint64_t n)
        : msgr(r), done(false), listen_sd(-1), nonce(n),
          shutdown_rd_fd(-1), shutdown_wr_fd(-1)
    {}

    void *entry() override;
    void stop();
    int bind(const entity_addr_t &bind_addr, const set<int> &avoid_ports);
    int rebind(const set<int> &avoid_port);
    int start();
};
//可以看到accepter 是thread的子类
//所以我们先看看其start函数
int Accepter::start()
{
    ldout(msgr->cct, 1) << __func__ << dendl;
    // start thread
    create("ms_accepter");
    return 0;
}
//在start中通过create来新建一个接收线程,其name是ms_accepter
//其次我们在看看这个线程只要执行的工作,其在entry中实现
void *Accepter::entry()
{
    ldout(msgr->cct, 1) << __func__ << " start" << dendl;

    int errors = 0;
    int ch;
    struct pollfd pfd[2];
    memset(pfd, 0, sizeof(pfd));
    pfd[0].fd = listen_sd;
    pfd[0].events = POLLIN | POLLERR | POLLNVAL | POLLHUP;
    pfd[1].fd = shutdown_rd_fd;
    pfd[1].events = POLLIN | POLLERR | POLLNVAL | POLLHUP;
#开始polling
    while (!done)
    {
        ldout(msgr->cct, 20) << __func__ << " calling poll for sd:" << listen_sd << dendl;
        int r = poll(pfd, 2, -1);
        if (r < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            ldout(msgr->cct, 1) << __func__ << " poll got error"
                                << " errno " << errno << " " << cpp_strerror(errno) << dendl;
            break;
        }
#检查是否polling返回error
        if (pfd[0].revents & (POLLERR | POLLNVAL | POLLHUP))
        {
            ldout(msgr->cct, 1) << __func__ << " poll got errors in revents "
                                <<  pfd[0].revents << dendl;
            break;
        }
        if (pfd[1].revents & (POLLIN | POLLERR | POLLNVAL | POLLHUP))
        {
            // We got "signaled" to exit the poll
            // clean the selfpipe
#检查是否要退出polling
            if (::read(shutdown_rd_fd, &ch, 1) == -1)
            {
                if (errno != EAGAIN)
                    ldout(msgr->cct, 1) << __func__ << " Cannot read selfpipe: "
                                        << " errno " << errno << " " << cpp_strerror(errno) << dendl;
            }
            break;
        }
        if (done) break;
        // accept
#走到这里polling函数就正常返回了,通过accept函数开始接收
        sockaddr_storage ss;
        socklen_t slen = sizeof(ss);
        int sd = ::accept(listen_sd, (sockaddr *)&ss, &slen);
        if (sd >= 0)
        {
            int r = set_close_on_exec(sd);
            if (r)
            {
                ldout(msgr->cct, 1) << __func__ << " set_close_on_exec() failed "
                                    << cpp_strerror(r) << dendl;
            }
            errors = 0;
            ldout(msgr->cct, 10) << __func__ << " incoming on sd " << sd << dendl;
#实际从pipe中读入msg
            msgr->add_accept_pipe(sd);
        }
        else
        {
            ldout(msgr->cct, 0) << __func__ << " no incoming connection?  sd = " << sd
                                << " errno " << errno << " " << cpp_strerror(errno) << dendl;
            if (++errors > 4)
                break;
        }
    }

    ldout(msgr->cct, 20) << __func__ << " closing" << dendl;
    // socket is closed right after the thread has joined.
    // closing it here might race
    if (shutdown_rd_fd >= 0)
    {
        ::close(shutdown_rd_fd);
        shutdown_rd_fd = -1;
    }

    ldout(msgr->cct, 10) << __func__ << " stopping" << dendl;
    return 0;
}

message数据格式

通信的双方需要约定数据格式,这是很明显的。否则收到对方发送的数据,不知道如何解析。这应该是通信的首先要解决的问题。

class Message : public RefCountedObject {
protected:
  ceph_msg_header  header;      // headerelope
  ceph_msg_footer  footer;
  bufferlist       payload;  // "front" unaligned blob
  bufferlist       middle;   // "middle" unaligned blob
  bufferlist       data;     // data payload (page-alignment will be preserved where possible)
 
  ...
};

在消息内容可以分成3个部分

  • header
  • user data
  • footer。

user data 当中可以分成3个部分

  • payload
  • middle
  • data

payload 一般是ceph操作的元数据 , middle是预留字段目前没有使用。 data是一般为读写的数据。

接下来先介绍header:

struct ceph_msg_header {
	__le64 seq;       /* message seq# for this session */
	__le64 tid;       /* transaction id */
	__le16 type;      /* message type */
	__le16 priority;  /* priority.  higher value == higher priority */
	__le16 version;   /* version of message encoding */
 
	__le32 front_len; /* bytes in main payload */
	__le32 middle_len;/* bytes in middle payload */
	__le32 data_len;  /* bytes of data payload *
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值