Dispatcher模块

dispatcher 是消息分发中心,所有收到的消息都经由该模块,并由该模块转发给相应的处理模块(moncliet、mdsclient、osd等)。

如图:

创建messenger后,把处理消息的dispatcher add 到dispatcher list里面,当messenger接收到消息msg之后,把msg放入msg的队列,由消息处理线程取出来,遍历dispatcher list里面dispatcher,在dispatcher里面的switch比对msg-type,如果刚好有可以处理该msg的分支就处理,dispatcher返回ture,结束。如果该dispatcher里面的switch可以处理该msg的分支,就到default,dispatcher返回false。msg接着会被交给下一个dispatcher去处理。直到被处理,或dispatcher遍历完。

https://www.edrawmax.cn/online/share.html?code=6d487368b32711ecacb543339f8ff90e

Dispatcher类是一个基类,里面设计封装了应用同Messenger交互的接口(每个具体的Dispatcher派生类自行去实现更具体的消息处理,一般都是再根据消息类型来分开处理消息)。Dispatcher并不是所有的接口封装都是为了转发消息,它更深层次的含义是提供一个应用层和底层的通信接口,而这个接口的桥梁是Messenger消息管理器。

当底层有消息到来时,Messenger会将消息转给dispatcher对于的ms_*系列的接口,最常用的是ms_dispatch接口,因此你可以看到像monitor,osd这些应用的核心消息处理都在ms_dispatch接口里面实现。

bool OSD::ms_dispatch(Message *m)
{
 ……
  _dispatch(m);

……
  return true;
}

void OSD::_dispatch(Message *m)
{
  switch (m->get_type()) {
    // -- don't need OSDMap --
    // map and replication
  case CEPH_MSG_OSD_MAP:
    handle_osd_map(static_cast<MOSDMap*>(m));
    break;
  case MSG_MON_GET_PURGED_SNAPS_REPLY:
    handle_get_purged_snaps_reply(static_cast<MMonGetPurgedSnapsReply*>(m));
    break;
    // osd
  case MSG_OSD_SCRUB:
    handle_scrub(static_cast<MOSDScrub*>(m));
    break;
  case MSG_COMMAND:
    handle_command(static_cast<MCommand*>(m));
    return;
    // -- need OSDMap --
  case MSG_OSD_PG_CREATE:
    {
      OpRequestRef op = op_tracker.create_request<OpRequest, Message*>(m);
      if (m->trace)
        op->osd_trace.init("osd op", &trace_endpoint, &m->trace);
      // no map?  starting up?
      if (!get_osdmap()) {
        dout(7) << "no OSDMap, not booted" << dendl;
    logger->inc(l_osd_waiting_for_map);
        waiting_for_osdmap.push_back(op);
    op->mark_delayed("no osdmap");
        break;
      }
      // need OSDMap
      dispatch_op(op);
    }
  }
}

Dispatcher的使用

最简单的方式就是应用本身作为Dispatcher的派生类,如此,Messenger便是直接通过应用关联,比如Monitor、osd、mgr都是应用组件本身作为Dispatcher的派生类。

class Monitor : public Dispatcher

class MDSDaemon : public Dispatcher

申请一个Dispatcher的派生类实例,做为应用的模块注册给Messenger,比如RadosClient里面会注册各个Client给Messenger,而这些Client都是Dispatcher的派生类。

class MDSDaemon : public Dispatcher

{……}

int MDSDaemon::init()
{

……

messenger->add_dispatcher_tail(&beacon);
  messenger->add_dispatcher_tail(this); #this 就是MDSDaemon 它自己

……
 }

bool MDSDaemon::ms_dispatch(const ref_t<Message> &m)
{
……
}

例子分析:

Dipatcher类是消息分发的接口,OSD、MON、等类都继承该类,并实现了Dipatcher的消息分发接口

class OSD : public Dispatcher,public md_config_obs_t
{/** OSD **/
}class Monitor : public Dispatcher,public md_config_obs_t
{
public:// mestring name;
}

在OSD::init()函数中把  处理不同消息  的Dipatcher加入到Messenger实例中

// i'm ready!
client_messenger->add_dispatcher_head(this);
cluster_messenger->add_dispatcher_head(this);
hbclient_messenger->add_dispatcher_head(&heartbeat_dispatcher);
hb_front_server_messenger->add_dispatcher_head(&heartbeat_dispatcher);
hb_back_server_messenger->add_dispatcher_head(&heartbeat_dispatcher);
objecter_messenger->add_dispatcher_head(service.objecter);

Messenger::add_dispatcher_head(Dispatcher *d) 把Dipatcher放入链表Messenger::list<Dispatcher*> dispatchers中,并调用ready(),SimpleMessenger::ready()重写了基类的ready,

void add_dispatcher_head(Dispatcher *d)
{bool first = dispatchers.empty();dispatchers.push_front(d);if (d->ms_can_fast_dispatch_any())fast_dispatchers.push_front(d);if (first)ready();
}

在ready函数中调用DispatchQueue::start, start()函数启动DispatchQueue::DispatchThread和DispatchQueue::LocalDeliveryThread线程类,最终调用DispatchQueue::entry()和DispatchQueue::run_local_delivery。

void DispatchQueue::start()
{assert(!stop);assert(!dispatch_thread.is_started());dispatch_thread.create("ms_dispatch");    //调用Thread::create->Thread::try_create->Thread::_entry_func->Thread::entry_wrapper->DispatchThread::entrylocal_delivery_thread.create("ms_local");
}
class DispatchThread : public Thread
{DispatchQueue *dq;
public:explicit DispatchThread(DispatchQueue *dq) : dq(dq) {}void *entry(){dq->entry();return 0;}
} dispatch_thread;

在DispatchQueue::entry()中调用根据不同的命令码qitem.get_code调用不同的Messenger类中的处理函数:

void DispatchQueue::entry()
{
    .
    .

switch (qitem.get_code())
    {
    case D_BAD_REMOTE_RESET:
        msgr->ms_deliver_handle_remote_reset(qitem.get_connection());
        break;
    case D_CONNECT:
        msgr->ms_deliver_handle_connect(qitem.get_connection());
        break;
    case D_ACCEPT:
        msgr->ms_deliver_handle_accept(qitem.get_connection());
        break;
    case D_BAD_RESET:
        msgr->ms_deliver_handle_reset(qitem.get_connection());
        break;
    default:
        assert(0);
    }
}
else
{
    Message *m = qitem.get_message();
    if (stop)
    {
        ldout(cct, 10) << " stop flag set, discarding " << m << " " << *m << dendl;
        m->put();
    }
    else
    {
        uint64_t msize = pre_dispatch(m);
        msgr->ms_deliver_dispatch(m);
        post_dispatch(m, msize);
    }
}
.
.

}

在Messenger::ms_deliver_dispatch中最终遍历注册到链表的Dipatcher,找到可以处理到来的消息的 Dipatcher调用Dipatcher继承类的ms_dispatch进行处理:

void ms_deliver_dispatch(Message *m)
{m->set_dispatch_stamp(ceph_clock_now(cct));for (list<Dispatcher *>::iterator p = dispatchers.begin();p != dispatchers.end();++p){if ((*p)->ms_dispatch(m))     //在Dispatcher继承类中进行处理return;}lsubdout(cct, ms, 0) << "ms_deliver_dispatch: unhandled message " << m << " " << *m << " from "<< m->get_source_inst() << dendl;assert(!cct->_conf->ms_die_on_unhandled_msg);m->put();
}

原文:ceph Dispatcher模块分析_weixin_34320724的博客-CSDN博客

bool MgrClient::ms_dispatch(const ref_t<Message>& m)
{std::lock_guard l(lock);switch(m->get_type()) {case MSG_MGR_MAP:return handle_mgr_map(ref_cast<MMgrMap>(m));case MSG_MGR_CONFIGURE:return handle_mgr_configure(ref_cast<MMgrConfigure>(m));case MSG_MGR_CLOSE:return handle_mgr_close(ref_cast<MMgrClose>(m));case MSG_COMMAND_REPLY:if (m->get_source().type() == CEPH_ENTITY_TYPE_MGR) {MCommandReply *c = static_cast<MCommandReply*>(m.get());handle_command_reply(c->get_tid(), c->get_data(), c->rs, c->r);return true;} else {return false;}case MSG_MGR_COMMAND_REPLY:if (m->get_source().type() == CEPH_ENTITY_TYPE_MGR) {MMgrCommandReply *c = static_cast<MMgrCommandReply*>(m.get());handle_command_reply(c->get_tid(), c->get_data(), c->rs, c->r);return true;} else {return false;}default:ldout(cct, 30) << "Not handling " << *m << dendl; return false;}
}

创建 osd_dispatcher/mon_dispatcher ==>add_dispatcher_

==>ready()

==>start()

==>DispatchThread

==>entry()

==>LocalDeliveryThread

==>run_local_delivery()

ms_fast_dispatch和ms_dispatch的区别

fast_preprocess

d) 调用函数read_message()来接收消息,当本函数返回后,就完成了接收消息

2) 调用函数in_q->fast_preprocess(m)预处理消息

3) 调用函数in_q->can_fast_dispatch(m),如果可以进行fast_dispatch,就in_q->fast_dispatch(m)处理。fast_dispatch并不把消息加入到mqueue里,而是直接调用msgr->ms_fast_dispatch()函数,并最终调用注册的fast_dispatcher来进行处理。

4) 如果不能fast_dispatch,就调用函数in_q->enqueue(m, m->get_priority(), conn_id)把接收到的消息加入到DispatchQueue的mqueue队列里,由DispatchQueue的分发线程调用ms_dispatch处理。

ms_fast_dispatch和ms_dispatch两种处理的区别在于:ms_dispatch是由DispatchQueue的线程处理的,它是一个单线程;ms_fast_dispatch函数是由Pipe接收线程直接调用处理的,因此性能比前者好。

ceph网络通信 | Ivanzz

Ceph 数据IO全栈流程-源码分析_Darren_Wen的技术博客_51CTO博客

bool ms_can_fast_dispatch(const Message *m) const override {
    switch (m->get_type()) {
    case CEPH_MSG_PING:
    case CEPH_MSG_OSD_OP:
    case CEPH_MSG_OSD_BACKOFF:
    case MSG_OSD_SCRUB2:
    case MSG_OSD_FORCE_RECOVERY:
    case MSG_MON_COMMAND:
    case MSG_OSD_PG_CREATE2:
    case MSG_OSD_PG_QUERY:
    case MSG_OSD_PG_QUERY2:
  ……
      return true;
    default:
      return false;
    }
  }

bool DispatchQueue::can_fast_dispatch(const cref_t<Message> &m) const
{
  return msgr->ms_can_fast_dispatch(m);
}

void DispatchQueue::fast_dispatch(const ref_t<Message>& m)
{
  uint64_t msize = pre_dispatch(m);
  msgr->ms_fast_dispatch(m);
  post_dispatch(m, msize);
}

void DispatchQueue::run_local_delivery()
{
  std::unique_lock l{local_delivery_lock};
  while (true) {
    if (stop_local_delivery)
      break;
    if (local_messages.empty()) {
      local_delivery_cond.wait(l);
      continue;
    }
    auto p = std::move(local_messages.front());
    local_messages.pop();
    l.unlock();
    const ref_t<Message>& m = p.first;
    int priority = p.second;
    fast_preprocess(m);
    if (can_fast_dispatch(m)) {fast_dispatch(m);
    } else {enqueue(m, priority, 0);
    }
    l.lock();
  }
}

Dispatcher处理线程

dispatcher 是消息分发中心,所有收到的消息都经由该模块,并由该模块转发给相应的处理模块(moncliet、mdsclient、osd等)。

其实现方式比较简单,就是把所有的模块及其处理消息的方法 handle 注册到分发中心,具体函数为 add_dispatcher_head/tail(),这样就向 dispatcher_queue 中添加了指定模块。后续在分发消息时,对 dispatcher_queue 进行轮询,直到有一个处理模块能够处理该消息,通过 message->get_type() 来指定消息的处理函数。所有的消息分发都在 dispatcher 线程中完成。

在 add_dispatcher_head() 和 add_dispatcher_tail() 函数中,都做了 dispatcher 队列是否为空的判断(通过 dispatchers.empty() == true)。如果判定结果为空,说明需要重新创建 dispatcher 线程并绑定服务端地址,加入事件中心监听端口,具体方法在 ready() 中。

void add_dispatcher_head(Dispatcher *d) {bool first = dispatchers.empty();dispatchers.push_front(d);if (d->ms_can_fast_dispatch_any())fast_dispatchers.push_front(d);if (first)ready();}

add_dispatche_* 中调用了 AsyncMessenger::ready() 方法。下面给出AsyncMessenger::ready()方法代码:

p->start()(Processor::start())方法中监听 EVENT_READABLE 事件,并把事件提交到 EventCenter 事件中心,由上文介绍的 msgr-worker-x 线程去轮询事件中心的队列,监听端口是否收到消息。收到的消息则由 dispatcher 线程分发给指定的处理程序,其分发消息的接口为 ms_dispatch() 和 ms_fast_dispatch()。

dispatch_queue.start() 中开启了消息分发线程,分别为处理外部消息的 ms_dispatch 线程和处理本地消息的 ms_local 线程。相应的,它们有各自的优先级队列(注意:分发消息的队列时有优先级的,优先级越高,发送时机越早),分别是存储外部消息的 mqueue 和本地消息队列的 local_messages。消息队列的添加方式也有两种:mqueue.enqueue() 和 local_queue.emplace()。

void AsyncMessenger::ready()
{ldout(cct,10) << __func__ << " " << get_myaddrs() << dendl;stack->ready();//绑定端口if (pending_bind) {int err = bindv(pending_bind_addrs);if (err) {lderr(cct) << __func__ << " postponed bind failed" << dendl;ceph_abort();}}Mutex::Locker l(lock);//调用 worker 线程,监听端口for (auto &&p : processors)  p->start();//开启 ms_dispatcher 和 ms_locla 线程dispatch_queue.start();
}void DispatchQueue::start()
{ceph_assert(!stop);ceph_assert(!dispatch_thread.is_started());//开启 ms_dispatch 和 ms_local 线程dispatch_thread.create("ms_dispatch");local_delivery_thread.create("ms_local");
}

链接:https://www.jianshu.com/p/58956728dadc

Messenger和Dispatcher两大角色

ceph通信模块的角色主要分为Messenger和Dispatcher两大角色

使用ceph通信模块来收发消息* 发送消息

发消息比较简单,应用只需将消息内容按照需要的消息类型(定义在messaging/*或自定义)进行封装后调用Messenger的send_message即可。

接收消息
Messenger是如何将消息转给应用的或者说是如何管理?

Messenger设计了两个分发器管理成员:dispatchers和fast_dispatchers,用来处理不同类型的请求处理。应用层则按需求将不同的分发器注册给Messenger,进而Messenger接收到底层来的消息时,会将消息分发给已经注册的两个dispatchers。

设计fast_dispatchers的目的就是为了让有些消息能够省去底层的一层流程(如放入队列),直接到达应用。

Dispatcher类是一个基类,里面设计封装了应用同Messenger交互的接口(每个具体的Dispatcher派生类自行去实现更具体的消息处理,一般都是再根据消息类型来分开处理消息)。Dispatcher并不是所有的接口封装都是为了转发消息,它更深层次的含义是提供一个应用层和底层的通信接口,而这个接口的桥梁是Messenger消息管理器。

当底层有消息到来时,Messenger会将消息转给dispatcher对于的ms_*系列的接口,最常用的是ms_dispatch接口,因此你可以看到像monitor,osd这些应用的核心消息处理都在ms_dispatch接口里面实现。

Dispatcher的使用

最简单的方式就是应用本身作为Dispatcher的派生类,如此,Messenger便是直接通过应用关联,比如Monitor、osd、mgr都是应用组件本身作为Dispatcher的派生类。

class Monitor : public Dispatcher

申请一个Dispatcher的派生类实例,做为应用的模块注册给Messenger,比如RadosClient里面会注册各个Client给Messenger,而这些Client都是Dispatcher的派生类。

消息类型

ceph的消息基类是:Message,Message里面设计了一个type成员,用来区分不同的消息类型,不同的消息模块可以通过type来构造,而这些type定义在Message.h中

switch(m->get_type()) {

case MSG_MGR_MAP:
    return handle_mgr_map(ref_cast<MMgrMap>(m));
  case MSG_MGR_CONFIGURE:
    return handle_mgr_configure(ref_cast<MMgrConfigure>(m));

……}

type定义在Message.h中

Message.h

……

// monitor internal
#define MSG_MON_SCRUB              64
#define MSG_MON_ELECTION           65
#define MSG_MON_PAXOS              66
#define MSG_MON_PROBE              67
#define MSG_MON_JOIN               68
#define MSG_MON_SYNC           69
#define MSG_MON_PING               140

……

技巧:比如你想要看某个消息是谁发的,那么你只需要去查看这个消息类型对应的消息模块有哪些,然后再查到谁在使用这个消息模块来封装消息,进而就可以找到发送这个消息的地方。

例子
以ceph-mon为例子,Monitor类继承自Dispatcher

class Monitor : public Dispatcher,
实现它的ms_dispatcher方法,这个方法里面实现了mon的消息处理

注册给Messenger,add_dispatcher_tail方法就是将当前应用添加到dispatcher列表中

messenger->add_dispatcher_tail(this); 
 Messenger收到消息转给dipatcher

void ms_deliver_dispatch(Message *m)
{
    m->set_dispatch_stamp(ceph_clock_now());
    for (list<Dispatcher *>::iterator p = dispatchers.begin();
            p != dispatchers.end();
            ++p)
    {
        if ((*p)->ms_dispatch(m))
            return;

}
    lsubdout(cct, ms, 0) << "ms_deliver_dispatch: unhandled message " << m << " " << *m << " from "
                                    << m->get_source_inst() << dendl;
    assert(!cct->_conf->ms_die_on_unhandled_msg);
    m->put();

}
ceph monitor处理消息

bool ms_dispatch(Message *m) override
{
    lock.Lock();
    _ms_dispatch(m);
    lock.Unlock();
    return true;

}

bool MgrClient::ms_dispatch2(const ref_t<Message>& m)
{std::lock_guard l(lock);switch(m->get_type()) {case MSG_MGR_MAP:return handle_mgr_map(ref_cast<MMgrMap>(m));case MSG_MGR_CONFIGURE:return handle_mgr_configure(ref_cast<MMgrConfigure>(m));case MSG_MGR_CLOSE:return handle_mgr_close(ref_cast<MMgrClose>(m));case MSG_COMMAND_REPLY:if (m->get_source().type() == CEPH_ENTITY_TYPE_MGR) {MCommandReply *c = static_cast<MCommandReply*>(m.get());handle_command_reply(c->get_tid(), c->get_data(), c->rs, c->r);return true;} else {return false;}case MSG_MGR_COMMAND_REPLY:if (m->get_source().type() == CEPH_ENTITY_TYPE_MGR) {MMgrCommandReply *c = static_cast<MMgrCommandReply*>(m.get());handle_command_reply(c->get_tid(), c->get_data(), c->rs, c->r);return true;} else {return false;}default:ldout(cct, 30) << "Not handling " << *m << dendl; return false;}
}

未整理内容;

Ceph网络模块使用案例:OSD心跳检测机制 - 灰信网(软件开发博客聚合)

ceph的组件主要包括,OSD,monitor,mgr,osdclient,client等,这些模块内部的通信,以及模块间的通信都使用了,后面我们直接把这些组件称为网络模块的使用者。使用者在使用网络模块的时候,主要涉及到2个角色,一个是messenger,一个是dispatcher。messenger相当于一个消息管理器(网络模块的核心,消息的发送和接收都是messenger通过底层的类实现),dispatcher相当于一个消息的处理器。

-messenger

  • ① 将dispatcher移交给它的信息发送给其它节点(节点,这里节点是一个逻辑单元,比如osd.0就算是一个节点,osd.1算一个新的节点)处理
  • ② 从其它节点的messenger获取消息移交给本节点的dispatcher。

-dispatcher

  • ① 对接收到的消息(有messenger移交给它)进行处理
  • ② 把需要发送的消息移交给本节点的messenger

每个ceph组件都会注册多个messenger和多个dispatcher用于处理不同类型的消息。以OSD组件为例,OSD的守护进程启动的时候会注册7个messenger来管理消息,每个messenger的用途不一样。这部分代码在ceph osd守护进程启动中 /src/ceph_osd.cc。 每一个OSD都有一个守护进程(OSD deamon)。这个deamon负责完成OSD的所有逻辑功能,包括与monitor和其他OSD(事实上是其他OSD的deamon)通信以维护更新系 统状态,与其他OSD共同完成数据的存储和维护,与client通信完成各种数据对象操作等等。

例子:一个OSD模块会注册7个messenger和2个dispatcher。

编号

Messenger实例名称

作用

1

*ms_public

用来处理OSD和Client之间的消息

2

*ms_cluster

用来处理OSD和集群之间的消息

3

*ms_hb_front_client

用来向其它OSD发送心跳的消息

4

*ms_hb_back_client

用来向其它OSD发送心跳的消息

5

*ms_hb_back_server

用来接收其他OSD的心跳消息

6

*ms_hb_front_server

用来接收其他OSD的心跳消息

7

*ms_objecter

用来处理OSD和Objecter之间的消息

编号

Dispatcher实例名称

作用

1

*OSD

可以处理部分osd节点的消息

2

*heartbeat_dispatcher

处理心跳连接

1 消息模块的使用框架

1.1 发送消息

本节描述ceph中的应用(osd、mgr、monitor等)是如何使用网络模块发送消息的。在实际的应用中,有两种常见的发送消息的方式,当然这两种方式只是看起来有些不同,的底层实现都是相同,都是调用AsyncConnection::send_message(Message *m)把消息发送出去。

1)方式一:使用AsyncMessenger::send_message(Message *m, const entity_inst_t& dest))

其中Message *m是要发送的消息,dest是目的地址。

send_message会首先去判断自己和目标地址之前是不是已经存在链接Connection,如果没有就创建一个,conn->send_message(m)发送消息

-----------------------------------------------------------

conn->send_message(m)

-----------------------------------------------------------

2) 方式二:

① 首先要通过Messenger类,获取对应的Connection:

------------------------------------------------------------

conn = messenger->get_connection(dest_server);

------------------------------------------------------------

get_connection过程是这样的,如果dest.addr是my_inst.addr,就直接返回local_connection。

如果链接不存在就新建一个。

② 当获得一个Connection之后,就可以调用Connection的发送函数来发送消息。

-----------------------------------------------------------

conn->send_message(m)

-----------------------------------------------------------

具体发送的实现过程依赖于选择的消息模式,simple、async等实现方式都不同。在另一个文章里我会讲到具体实现过程,这里不多做解释。

1.2 消息的接收

消息的接收过程简言之就是通过监听socket判断是否有消息到来,如果有就接收。这个过程是个很复杂的过程,涉及到了连接建立、错误处理等等。具体的实现依赖于选择的消息模式,比如,SimpleMessenger是使用一个read线程来实现;AsyncMessenger是使用基于事件的机制实现。接收的过程对应用层都是透明的,本章不做解释。

1.3 消息的处理

消息接收完成后,就进入消息的处理。首先判断消息m是否可以fast_dispatch,如果可以,调用注册fast_dispatcher函数处理消息。如果不能fast_dispatch,调用函数in_q->enqueue,将接收到的消息加入到DispatchQueue的mqueue队列中,排队等待处理。

2 ceph OSD心跳检测与网络模块 

下面我们具体举一个OSD心跳检测的例子来讲解,通过心跳检测机制来了解网络模块的使用。在ceph中需要通过心跳检测来判断OSD是不是在线,因为这部分的功能比较简单独立。

2.1 Messenger & Dispatcher的注册

在OSD模块注册的7个Messenger和2个Dispatcher中,4个Messenger都和心跳检测相关,一个heartbeat_dispatcher用来处理心跳连接。

编号

Messenger实例名称

作用

1

*ms_public

用来处理OSD和Client之间的消息

2

*ms_cluster

用来处理OSD和集群之间的消息

3

*ms_hb_front_client

用来向其它OSD发送心跳的消息

4

*ms_hb_back_client

用来向其它OSD发送心跳的消息

5

*ms_hb_back_server

用来接收其他OSD的心跳消息

6

*ms_hb_front_server

用来接收其他OSD的心跳消息

7

*ms_objecter

用来处理OSD和Objecter之间的消息

对应代码在ceph_osd.cc中

-------------------------------------------------------------------------------------------------------

-HeartBeatMessenger

在ceph守护进程启动过程中(ceph-osd.cc),创建了4个messenger用于心跳检测。

在ceph守护进程创建osd的时候将这些messenger传给了osd, 注意这些messenger在osd中被重命名了。

重命名为了:

hb_front_client_messenger

hb_back_client_messenger

hb_front_server_messenger

hb_back_server_messenger

---------------------------------------------------------------------------------------------------

编号

Dispatcher实例名称

作用

1

*OSD

可以处理部分osd节点的消息

2

*heartbeat_dispatcher

处理心跳连接

对应代码在osd.cc中

-------------------------------------------------------------------------------------------------------

hb_front_client_messenger->add_dispatcher_head(&heartbeat_dispatcher);

hb_back_client_messenger->add_dispatcher_head(&heartbeat_dispatcher);

hb_front_server_messenger->add_dispatcher_head(&heartbeat_dispatcher);

hb_back_server_messenger->add_dispatcher_head(&heartbeat_dispatcher);

-------------------------------------------------------------------------------------------------------

【ceph 】ceph messenger的Dispatcher模块分析相关推荐

  1. ceph Dispatcher模块分析

    2019独角兽企业重金招聘Python工程师标准>>> Dipatcher类是消息分发的接口,OSD.MON.等类都继承该类,并实现了Dipatcher的消息分发接口 1079 cl ...

  2. 觉SLAM的主要功能模块分析

    视觉SLAM的主要功能模块分析 一.基本概念 SLAM (simultaneous localization and mapping),也称为CML (Concurrent Mapping and L ...

  3. Asterisk cli模块分析

    最近写一些工具库,需要远程命令行调试(cli)功能,原有的一个cli模块是将接收处理的命令具体实现在cli模块中,其他模块需要修改添加自己的cli命令都需要去修改cli模块代码,觉得模块间耦合度太高, ...

  4. 2016年大数据Spark“蘑菇云”行动代码学习之AdClickedStreamingStats模块分析

    2016年大数据Spark"蘑菇云"行动代码学习之AdClickedStreamingStats模块分析     系统背景:用户使用终端设备(IPAD.手机.浏览器)等登录系统,系 ...

  5. 来自damon的zencart二次开发教程-2.2登录模块分析

    我们在制作zencart的模板时,经常会遇到需要将zencart的登陆页面与注册账户页面分离的情况(在 默认情况下,点击"Login"按钮会进入登陆页面与注册账号页面,登录zenc ...

  6. Mybatis源码日志模块分析

    看源码需要先下载源码,可以去Mybatis的github上的仓库进行下载,Mybatis 这次就先整理一下日志这一块的源码分析,这块相对来说比较简单而且这个模块是Mybatis的基础模块. 之前的文章 ...

  7. 【转】python模块分析之collections(六)

    [转]python模块分析之collections(六) collections是Python内建的一个集合模块,提供了许多有用的集合类. 系列文章 python模块分析之random(一) pyth ...

  8. 旅游类APP-Android模块分析

    2.Android模块分析 2.1系统框架 2.2Android APP启动流程 AndroidManifest.xml 2.3网络交互 2.4开发中的知识点 1.启动时使用引导页使用渐变效果: pr ...

  9. 游戏模块分析总结(4)之系统篇

    游戏模块分析总结(4)之系统篇 发布者: wuye | 发布时间: 2014-12-19 12:10| 评论数: 1 1.系统结构 几乎所有游戏都遵循同一个原则,即:玩→获得产出→能力提升→继续玩.每 ...

最新文章

  1. java使用正则表达为数字添加千位符的简单方法
  2. POJ 2187 Beauty Contest( 凸包求最远点对 )
  3. 特征提取方法 SIFT,PCA-SIFT,GLOH,SURF
  4. Python中局部变量和全局变量的详解
  5. NOI[2001]食物链
  6. 计算机二级c语言2021年重点内容,2021年5月计算机二级C语言试题(总)
  7. 学生选课系统的源码-代码布局截图
  8. AI 用神经网络实现序列到序列的学习
  9. 赚了李嘉诚2.7亿元
  10. js 将html 某个dom 导出pdf,并处理分页
  11. 客快物流大数据项目(一):物流项目介绍和内容大纲
  12. 为什么量子计算机是锥形,科学家制作超高精度微腔为量子计算机铺垫
  13. css3 匀速运动的圆
  14. 父债子偿有法可依吗?可法院却对这个案子说:不!
  15. opengl实现太阳系、地球系,并加上地球的贴图
  16. Mockjs-官网学习总结
  17. Swiper说明及API手册说明
  18. linux手机内存碎片整理软件,Linux不需要磁盘碎片整理
  19. android 发布最新系统更新包,Android 12系统
  20. UNIX和Linux Shell正则表达式语法介绍

热门文章

  1. IPFS——下一个Http取代?
  2. 部分安全厂商误报分析提交方法
  3. 用超级计算机当游戏服务器,超级计算机做服务器 中国网游照样卡死你
  4. 统计所有n阶方阵(n>0)中既满足自反性规则又满足对称性规则的方阵数量(注:矩阵元素值仅为0或1)
  5. HTTP基础:请求报文
  6. R语言画基因突变结构图
  7. 应用解决告诉你什么时候该用ajax
  8. 老板利用全民养羊,只用18天就连本带利收回42万?脑洞大开!
  9. Java将json中key值下划线转为驼峰格式
  10. STM32硬件剖析(LD MD HD 的选择)