MSG模块源码分析—NetworkStack

MSG模块源码分析—NetworkStack

以mon为例,在ceph_mon.cc的main函数中:

// bind
int rank = monmap.get_rank(g_conf()->name.get_id());
std::string public_msgr_type = g_conf()->ms_public_type.empty() ? g_conf().get_val<std::string>("ms_type")
                                                                : g_conf()->ms_public_type;
Messenger *msgr = Messenger::create(g_ceph_context, public_msgr_type,
                                    entity_name_t::MON(rank), "mon", 0);

首先,从配置文件中获取ms_type,该字段用于指定传输类型,这里默认是async+posix

Messenger *Messenger::create(CephContext *cct, const std::string &type,
                             entity_name_t name, std::string lname,
                             uint64_t nonce) {
  if (type == "random" || type.find("async") != std::string::npos)
    return new AsyncMessenger(cct, name, type, std::move(lname), nonce);
  return nullptr;
}

进而创建了一个AsyncMessenger,其构造函数如下:

AsyncMessenger::AsyncMessenger(CephContext *cct, entity_name_t name,
                               const std::string &type, std::string mname,
                               uint64_t _nonce)
    : SimplePolicyMessenger(cct, name),
      dispatch_queue(cct, this, mname),
      nonce(_nonce) {
  std::string transport_type = "posix";
  if (type.find("rdma") != std::string::npos)
    transport_type = "rdma";
  else if (type.find("dpdk") != std::string::npos)
    transport_type = "dpdk";

  auto single = &cct->lookup_or_create_singleton_object<StackSingleton>(
      "AsyncMessenger::NetworkStack::" + transport_type, true, cct);

  single->ready(transport_type);
  stack = single->stack.get();
  stack->start();
  ...
}

在这里,我们的transport_typeposix

第13行,会创建一个StackSingleton对象,他就是我们分析的开端。首先看一下与之相关的类图。

简单的介绍一些每一个类的作用:

类名 作用
ceph::NetHandler 封装了一些对socket的基本操作(创建、连接、非阻塞、option等)
EventDriver 提供了一些IO多路复用的抽象接口,我们这个具体的实现是EpollDriver
EventCenter 基于EventDriver实现了事件处理,支持FileEventTimeEvent
Worker 每一个Worker都会对应一个EventCenter,其本质上就是一个线程,不断的处理EventCenter中的事件
NetworkStack 管理多个Worker,我是将其理解为一个处理网络连接的线程池,具体的实现是PosixNetworkStack

线程池(PosixNetworkStack)创建

AsyncMessenger会创建一个SingleNetworkStack对象,然后调用其ready方法,实现如下:

struct StackSingleton {
  CephContext *cct;
  std::shared_ptr<NetworkStack> stack;

  explicit StackSingleton(CephContext *c) : cct(c) {}
  void ready(std::string &type) {
    if (!stack) stack = NetworkStack::create(cct, type);
  }
  ~StackSingleton() { stack->stop(); }
};

这里进入到NetworkStack的静态方法create中:


std::shared_ptr<NetworkStack> NetworkStack::create(CephContext* c,
                                                   const std::string& t) {
  std::shared_ptr<NetworkStack> stack = nullptr;
  //创建PosixNetworkStack
  if (t == "posix") stack.reset(new PosixNetworkStack(c));
  ...
  //设置异步线程数,默认是3个([1, 24])
  unsigned num_workers = c->_conf->ms_async_op_threads;
  const int InitEventNumber = 5000;
  for (unsigned worker_id = 0; worker_id < num_workers; ++worker_id) {
    Worker* w = stack->create_worker(c, worker_id);
    int ret = w->center.init(InitEventNumber, worker_id, t);
    ...
    stack->workers.push_back(w);
  }
  return stack;
}
  1. 创建完成PosixNetworkStack后,会根据配置文件中的ms_async_op_threads来配置Worker的数量。
  2. PosixNetworkStack->create_worker返回一个PosixWorker对象。
  3. 初始化PosixWorkerEventCenter。这里面会创建一个EpollDriverInitEventNumber指定了EventCenter内部事件缓存池的初始大小,以及EpoolDriver每次epoll_wait的最大事件数(第三个参数)。
  4. 所有的worker都会保存在staock->workers中。

线程池(PosixNetworkStack)启动

对应 NetworkStack::start()

void NetworkStack::start() {
  std::unique_lock<decltype(pool_spin)> lk(pool_spin);

  if (started) {
    return;
  }

  for (Worker* worker : workers) {
    if (worker->is_init()) continue;
    spawn_worker(add_thread(worker));
  }
  started = true;
  lk.unlock();

  for (Worker* worker : workers) {
    worker->wait_for_init();
  }
}

class PosixNetworkStack : public NetworkStack {
  std::vector<std::thread> threads;

  virtual Worker* create_worker(CephContext *c, unsigned worker_id) override {
    return new PosixWorker(c, worker_id);
  }

 public:
  explicit PosixNetworkStack(CephContext *c);

  void spawn_worker(std::function<void ()> &&func) override {
    threads.emplace_back(std::move(func));
  }
  void join_worker(unsigned i) override {
    ceph_assert(threads.size() > i && threads[i].joinable());
    threads[i].join();
  }
};

这里,逐个通过spawn_worker函数启动Worker线程(工作线程的主要工作就是add_thread返回的std::function)。

Worker线程的主循环

std::function<void()> NetworkStack::add_thread(Worker* w) {
  return [this, w]() {
    rename_thread(w->id);
    const unsigned EventMaxWaitUs = 30000000; ?/30s
    w->center.set_owner();
    ldout(cct, 10) << __func__ << " starting" << dendl;
    w->initialize(); //空实现
    w->init_done(); //stack->start() 最后的 worker->wait_for_init()对应
    while (!w->done) { //什么时候会退出?
      ceph::timespan dur; //记录process_events的执行时间
      int r = w->center.process_events(EventMaxWaitUs, &dur);
      if (r < 0) {
        ldout(cct, 20) << __func__
                       << " process events failed: " << cpp_strerror(errno)
                       << dendl;
        // TODO do something?
      }
      w->perf_logger->tinc(l_msgr_running_total_time, dur);
    }
    w->reset();
    w->destroy();
  };
}

over!

非阻塞IO+事件驱动的实现基本类似,不同的就是 封装方式吧。 所以 Stack往下就不继续贴代码了。

posted @ 2022-07-07 17:11  liutimo  阅读(148)  评论(0编辑  收藏  举报