• 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往下就不继续贴代码了。

  • 相关阅读:
    前端设计网站收藏
    JAVA的StringBuffer类
    JDBC连接数据库
    JSP中request属性的用法
    jquery学习
    servlet学习(一)
    javascript 计算器
    xml学习(一)
    网站之单点登录简单思路
    关于ASP.NET中Menu控件在浏览器中不正常显示解决方法
  • 原文地址:https://www.cnblogs.com/liutimo/p/16455401.html
Copyright © 2020-2023  润新知