ceph Async 网络通信源代码分析(二)

原创 2018年04月15日 01:04:49

在上文中,主要介绍了相关的类,本文介绍相关流程。

连接相关的流程介绍

Server端监听和接受连接的过程

这段代码来自 src/test/msgr/perf_msgr_server.cc,主要用于建立Server端的msgr:

 void start() {
    entity_addr_t addr;
    addr.parse(bindaddr.c_str());
    msgr->bind(addr);
    msgr->add_dispatcher_head(&dispatcher);
    msgr->start();
    msgr->wait();
 }

上面的代码是典型的服务端的启动流程:

  1. 绑定服务端地址 msgr->bind(addr)
  2. 添加消息分发类型 dispatcher
  3. 启动 msgr->start()

下面从内部具体如何实现。

  • 调用processor的bind 函数,对于PosixStack, 只需要一个porcessor就可以了。
int AsyncMessenger::bind(const entity_addr_t &bind_addr)
{
 ......
     for (auto &&p : processors) {
         int r = p->bind(bind_addr, avoid_ports, &bound_addr);
       }
 ......
}
int Processor::bind(const entity_addr_t &bind_addr,
            const set<int>& avoid_ports,
            entity_addr_t* bound_addr)
{
...
  //向Processor对于的工作者线程 投递外部事件,其回调函数为 worker的 listen函数
   worker->center.submit_to(worker->center.get_id(), [this, &listen_addr, &opts, &r]() {
        r = worker->listen(listen_addr, opts, &listen_socket);
      }, false);
...
}

当该外部事件被worker线程调度执行后,worker->listen完成了该Processor的listen_socket的创建。

  • 添加 dispatcher
 void add_dispatcher_head(Dispatcher *d) { 
        if (first)
      ready();
}

在ready 函数里调用了Processor::start函数

void AsyncMessenger::ready()
{
  ldout(cct,10) << __func__ << " " << get_myaddr() << dendl;

  stack->start();
  Mutex::Locker l(lock);
  for (auto &&p : processors)
    p->start();
  dispatch_queue.start();
}

在Processor::start函数里,向EventCenter 投递了外部事件,该外部事件的回调函数里实现了向 EventCenter注册listen socket 的读事件监听。 该事件的处理函数为 listen_handeler

void Processor::start()
{
  ldout(msgr->cct, 1) << __func__ << dendl;

  // start thread
  if (listen_socket) {
    worker->center.submit_to(worker->center.get_id(), [this]() {
      worker->center.create_file_event(
        listen_socket.fd(), EVENT_READABLE, listen_handler); 
    }, false);
  }
}

listen_handler对应的 处理函数为 processor::accept函数,其处理接收连接的事件。

class Processor::C_processor_accept : public EventCallback {
  Processor *pro;

 public:
  explicit C_processor_accept(Processor *p): pro(p) {}
  void do_request(int id) {
    pro->accept();
  }
};
void Processor::accept()
{
 ......
   if (!msgr->get_stack()->support_local_listen_table())
      w = msgr->get_stack()->get_worker();

    int r = listen_socket.accept(&cli_socket, opts, &addr, w);
    if (r == 0) {
      msgr->add_accept(w, std::move(cli_socket), addr);
      continue;
     }
}

在函数Processor::accept里, 首先获取了一个worker,通过调用accept函数接收该连接。并调用 msgr->add_accept 函数。

void AsyncMessenger::add_accept(Worker *w, 
                               ConnectedSocket cli_socket,
                               entity_addr_t &addr)
{
  lock.Lock();
  //创建连接,该Connection已经指定了 worker处理该Connection上所有的事件。
  AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
  conn->accept(std::move(cli_socket), addr);
  accepting_conns.insert(conn);
  lock.Unlock();
}

Client端主动连接的过程

AsyncConnectionRef AsyncMessenger::create_connect(const entity_addr_t& addr, int type)
{

  // 获取一个 worker,根据负载均衡
  Worker *w = stack->get_worker();
  //创建Connection
  AsyncConnectionRef conn = new AsyncConnection(cct, this, &dispatch_queue, w);
  //
  conn->connect(addr, type);
  //添加到conns列表中
  conns[addr] = conn;


  return conn;
}
void AsyncConnection::_connect()
{
  ldout(async_msgr->cct, 10) << __func__ << " csq=" << connect_seq << dendl;

  state = STATE_CONNECTING;
  // rescheduler connection in order to avoid lock dep
  // may called by external thread(send_message)
  center->dispatch_event_external(read_handler);
}

函数 AsyncConnection::_connect 设置了状态为 STATE_CONNECTING,向对应的 EventCenter投递 外部外部事件,其read_handler为 void AsyncConnection::process()函数。

void AsyncConnection::process()
{
   ......
    default:
        {
          if (_process_connection() < 0)
            goto fail;
          break;
        }
}
ssize_t AsyncConnection::_process_connection()
{
......
  r = worker->connect(get_peer_addr(), opts, &cs);
        if (r < 0)
          goto fail;

        center->create_file_event(cs.fd(), EVENT_READABLE, read_handler);
}

消息的接收和发送

消息的接收

消息的接收比较简单,因为消息的接收都是 内部事件,也就是都是由 epoll_wait触发的事件。其对应的回调函数 AsyncConnection::process() 去处理相应的接收事件。

消息的发送

消息的发送比较特殊,它涉及到外部事件和内部事件的相关的调用。

int AsyncConnection::send_message(Message *m){
     ......
     //把消息添加到 内部发送队列里
      out_q[m->get_priority()].emplace_back(std::move(bl), m);
     //添加外部事件给对应的的CenterEvent,并触发外部事件
      if (can_write != WriteStatus::REPLACING)
         center->dispatch_event_external(write_handler);
}

发送相关的调用函数

void AsyncConnection::handle_write()
       ssize_t AsyncConnection::write_message(Message *m,
                       bufferlist& bl, bool more)
         ssize_t AsyncConnection::_try_send(bool more)
ssize_t AsyncConnection::_try_send(bool more)
{
......
   if (!open_write && is_queued()) {
    center->create_file_event(cs.fd(), EVENT_WRITABLE, 
                            write_handler);
    open_write = true;
  }

  if (open_write && !is_queued()) {
    center->delete_file_event(cs.fd(), EVENT_WRITABLE);
    open_write = false;
    if (state_after_send != STATE_NONE)
      center->dispatch_event_external(read_handler);
  }

}

函数_try_send里比较关键的是:

  1. 当还有消息没有发送时, 就把该socket的 fd 添加到 EVENT_WRITABLE 事件中。
  2. 如果没有消息发送, 就把该 socket的 fd 的 EVENT_WRITABLE 事件监听删除

也就是当有发送请求时, 添加外部事件,并触发线程去处理发送事件。当外部事件一次可以完成发送消息的请求时,就不需要添加该fd对应的EVENT_WRITABLE 事件监听。当没有发送完消息时,就添加该fd的EVENT_WRITABLE 事件监听来触发内部事件去继续完成消息的发送。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/changtao381/article/details/79946111

Ceph源码分析之Async模块:2、上层通信模型

在博文Ceph源码分析之Async模块:1、异步通信核心模块EventCenter+Epoll 里面介绍了Async实现异步通信的底层核心模块。这次打算从上层应用来看ceph的通信模型模型。ceph通...
  • hawkerou
  • hawkerou
  • 2017年03月24日 13:45
  • 868

Ceph 网络通信源代码分析

对于一个分布式存储系统,需要一个稳定的底层网络通信模块,用于各个节点的之间的互联互通。对于一个网络通信系统,要求: 高性能 性能评价的两个指标: 带宽和延迟 稳定可靠 在网络中断时,实现重连。数据...
  • changtao381
  • changtao381
  • 2016年03月17日 17:19
  • 2942

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

ceph Async模块提供一种异步收发消息的机制,最底层的异步机制可以查看博文 Ceph源码分析之Async模块:1、异步通信核心模块EventCenter+Epoll,上层的收发消息机制可以查看博...
  • hawkerou
  • hawkerou
  • 2017年03月28日 08:27
  • 1341

Ceph网络模块(3)——AsyncMessenger代码流程分析

Ceph网络模块(3)——AsyncMessenger代码流程分析
  • zhq5515
  • zhq5515
  • 2017年01月08日 19:50
  • 1256

ceph源码分析之消息通信机制

在介绍ceph的读写流程时,我们流程的开始于OSD::_ms_dispatcher,这个函数的意义表示,osd拿到了消息,并要根据不同的表示对消息进行dispatcher,那么消息究竟是如何来的,这个...
  • ywy463726588
  • ywy463726588
  • 2015年01月20日 10:33
  • 2392

Ceph学习——Librados与Osdc实现源码解析

本文介绍Ceph客户端方面的某些模块的实现。客户端主要是实现了接口,对外提供访问的功能。上层可以通过接口来访问Ceph存储。Librados 与 Osdc 位于Ceph客户端中比较底层的位置,Libr...
  • CSND_PAN
  • CSND_PAN
  • 2017年12月04日 18:34
  • 528

Ceph网络模块(2) - AsyncMessenger组织结构

本文主要介绍AsyncMessenger的代码框架结构以及基本数据结构
  • zhq5515
  • zhq5515
  • 2017年01月08日 19:04
  • 1159

Ceph 源代码分析 -OS module

Ceph的src/os 中保存了 ObjectStore代码实现。 基本概念 对象 对象存储的概念,把对象作为存储的实体。 在Ceph 文件系统里,对象的命名空间分了两层, 第一...
  • changtao381
  • changtao381
  • 2013年03月26日 14:19
  • 8600

ceph中的信号处理线程

linux 信号sigset_t 信号集类型 sigfillset(...) 初始化所有信号位,值为 1。 sigemptyset(...) 清空所有信号,值为0. sigaddset(...) 向信...
  • litianze99
  • litianze99
  • 2016年05月24日 13:46
  • 482

Ceph源码分析之Async模块:1、异步通信核心模块EventCenter+Epoll

概述EventCenter是Async异步消息通信的核心模块,通过事件/回调模型向上提供异步消息通信,每个Async下的worker线程负责处理一个EventCenter的事件集合。EventCent...
  • hawkerou
  • hawkerou
  • 2017年03月23日 21:51
  • 1375
收藏助手
不良信息举报
您举报文章:ceph Async 网络通信源代码分析(二)
举报原因:
原因补充:

(最多只允许输入30个字)