Ceph Async 网络通信源代码分析(一)

在Ceph的网络通信模块里,早期一直使用 Simple 这个网络通信模块。由于其实现简单,最早被ceph采用并用于生产环境。其最大的缺陷是:针对每个Connection创建两个线程,一个用于接收消息,一个用于发送消息。在大规模的集群环境下,随着连接数的增多会产生大量的用于通信的线程,极大的影响性能。

ceph在L版本中把Async网络通信模型做为默认的通信方式。Async实现了IO的多路复用,使用共享的线程池实现异步发送和接收任务。

本文主要介绍Async的的Epol + 线程池的 实现模型,主要介绍基本框架和关键实现。本文的思路是首先概要介绍相关的类,在介绍类时主要关注其数据结构和相关的操作。 其次介绍网络通信的核心流程:server端sock的监听和接受连接,客户端如何主动发起连接。消息的发送和接收主要流程。

基本类介绍

NetHandler

类NetHandler 封装了Socket的基本的功能。

class NetHandler {
    int generic_connect(const entity_addr_t& addr, 
                        const entity_addr_t& bind_addr,
                        bool nonblock);

    CephContext *cct;
   public:
     explicit NetHandler(CephContext *c): cct(c) {}
    //创建socket
    int create_socket(int domain, bool reuse_addr=false);
    //设置socket 为非阻塞
    int set_nonblock(int sd);
    //当用exec起子进程时:设置socket关闭
    void set_close_on_exec(int sd);
    //设置socket的选项:nodelay,buffer size
    int set_socket_options(int sd, bool nodelay, int size);
    //connect
    int connect(const entity_addr_t &addr, const entity_addr_t& bind_addr);
    //重连
    int reconnect(const entity_addr_t &addr, int sd);
    //非阻塞connect
    int nonblock_connect(const entity_addr_t &addr, const entity_addr_t& bind_addr);
    //设置优先级
    void set_priority(int sd, int priority);
}

Worker类

Worker类是工作线程的抽象接口,同时添加了listen和connect接口用于服务端和客户端的网络处理。其内部创建一个EventCenter类,该类保存相关处理的事件。

class Worker {
  std::atomic_uint references;
  EventCenter center;   //事件处理中心, 处理该center的所有的事件

  // server 端
  virtual int listen(entity_addr_t &addr,
                     const SocketOptions &opts, ServerSocket *) = 0;
  // client主动连接
  virtual int connect(const entity_addr_t &addr,
                      const SocketOptions &opts, ConnectedSocket *socket) = 0;
}

PosixWorker

类PosixWorker实现了 Worker接口。

class PosixWorker : public Worker {

 NetHandler net;

 int listen(entity_addr_t &sa, 
            const SocketOptions 
            &opt,ServerSocket *socks) override;

 int connect(const entity_addr_t &addr,
             const SocketOptions &opts, 
            ConnectedSocket *socket) override;
}

int PosixWorker::listen(entity_addr_t &sa, const SocketOptions &opt,ServerSocket *sock)
函数PosixWorker::listen 实现了Server端的sock的功能:底层调用了NetHandler的功能,实现了socket 的 bind ,listen等操作,最后返回ServerSocket对象。

int PosixWorker::connect(const entity_addr_t &addr, const SocketOptions &opts, ConnectedSocket *socket)
函数PosixWorker::connect 实现了主动连接请求。返回ConnectedSocket对象。

NetworkStack

class NetworkStack : public CephContext::ForkWatcher {
  std::string type;      //NetworkStack的类型
  ceph::spinlock pool_spin;
  bool started = false;
 //Worker 工作队列
  unsigned num_workers = 0;
  vector<Worker*> workers; 
}

类NetworkStack是 网络协议栈的接口。PosixNetworkStack实现了linux的 tcp/ip 协议接口。DPDKStack实现了DPDK的接口。RDMAStack实现了IB的接口。

这里写图片描述

class PosixNetworkStack : public NetworkStack {
   vector<int> coreids;
   vector<std::thread> threads;  //线程池
}

Worker可以理解为工作者线程,其一一对应一个thread线程。为了兼容其它协议的设计,对应线程定义在了PosixNetworkStack类里。

通过上述分析可知,一个Worker对应一个线程,同时对应一个 事件处理中心EventCenter类。

EventDriver

EventDriver是一个抽象的接口,定义了添加事件监听,删除事件监听,获取触发的事件的接口。

class EventDriver {
 public:
  virtual ~EventDriver() {}       // we want a virtual destructor!!!
  virtual int init(EventCenter *center, int nevent) = 0;
  virtual int add_event(int fd, int cur_mask, int mask) = 0;
  virtual int del_event(int fd, int cur_mask, int del_mask) = 0;
  virtual int event_wait(vector<FiredFileEvent> &fired_events, struct timeval *tp) = 0;
  virtual int resize_events(int newsize) = 0;
  virtual bool need_wakeup() { return true; }
};

这里写图片描述
针对不同的IO多路复用机制,实现了不同的类。SelectDriver实现了select的方式。EpollDriver实现了epoll的网络事件处理方式。KqueueDriver是FreeBSD实现kqueue事件处理模型。

EventCenter

类EventCenter是保存所有事件,并提供了处理事件的相关函数。

FileEvent

FileEvent事件,也就是socket对应的事件。

struct FileEvent {
    int mask;                  //标志
    EventCallbackRef read_cb;  //处理读操作的回调函数
    EventCallbackRef write_cb;  //处理写操作的回调函数
    FileEvent(): mask(0), read_cb(NULL), write_cb(NULL) {}
  };

TimeEvent

struct TimeEvent {
    uint64_t id;              //时间事件的ID号
    EventCallbackRef time_cb;  //事件处理的回调函数

    TimeEvent(): id(0), time_cb(NULL) {}
};

类Poller 用于轮询事件,主要用于DPDK 模式。在PosixStack模式里没有用。

EventCenter

Class EventCenter {
     //外部事件
     std::mutex external_lock;
     std::atomic_ulong external_num_events;
     deque<EventCallbackRef> external_events;
      //socket事件, 其下标是socket对应的fd
     vector<FileEvent> file_events; 
     //时间事件 [expire time point, TimeEvent]
     std::multimap<clock_type::time_point, TimeEvent> time_events;
     //时间事件的map [id,  iterator of [expire time point,time_event]]
     std::map<uint64_t, 
             std::multimap<clock_type::time_point, TimeEvent>::iterator> event_map;  

    //触发执行外部事件的fd
     int notify_receive_fd;
     int notify_send_fd;
     EventCallbackRef notify_handler;

     //底层事件监控机制
     EventDriver *driver;
     NetHandler net;

  // Used by internal thread
  //创建file event
  int create_file_event(int fd, int mask, EventCallbackRef ctxt);
  //创建time event
  uint64_t create_time_event(uint64_t milliseconds, EventCallbackRef ctxt);
  //删除file event
  void delete_file_event(int fd, int mask);
  //删除 time event
  void delete_time_event(uint64_t id);
  //处理事件
  int process_events(int timeout_microseconds);
  //唤醒处理线程
  void wakeup();

  // Used by external thread
  void dispatch_event_external(EventCallbackRef e);

}

类EventCenter,主要保存事件(包括fileevent,和timeevent,以及外部事件)和 处理事件的相关的函数。

处理事件
int EventCenter::process_events(int timeout_microseconds, ceph::timespan *working_dur)

函数process_event处理相关的事件,其处理流程如下:

  1. 如果有外部事件,或者是poller模式,阻塞时间设置为0,也就是epoll_wait的超时时间。
  2. 默认超时时间为参数设定的超时时间timeout_microseconds,如果最近有时间事件,并且expect time 小于超时时间timeout_microseconds,就把超时时间设置为expect time到当前的时间间隔,并设置trigger_time为true标志,触发后续处理时间事件。
  3. 调用epoll_wait获取事件,并循环调用相应的回调函数处理相应的事件。
  4. 处理到期时间事件
  5. 处理所有的外部事件

在这里,内部事件指的是通过 epoll_wait 获取的事件。外部事件(external event)是其它投送的事件,例如处理主动连接,新的发送消息触发事件。

在类EventCenter里定义了两种方式向EventCenter里投递外部事件:

//直接投递EventCallback类型的事件处理函数
void EventCenter::dispatch_event_external(EventCallbackRef e)
//处理func类型的事件处理函数
void submit_to(int i, func &&f, bool nowait = false) 

AsyncMessenger

类AsyncMessenger 主要完成AsyncConnection的管理。其内部保存了所有Connection相关的信息。

class AsyncMessenger : public SimplePolicyMessenger {
   //现在的Connection
     ceph::unordered_map<entity_addr_t, AsyncConnectionRef> conns;  
 //正在accept的Connection
      set<AsyncConnectionRef> accepting_conns;
 //准备删除的 Connection
      set<AsyncConnectionRef> deleted_conns;
}

Processor类

class Processor {
  NetHandler net;
  Worker *worker;
  ServerSocket listen_socket;  //监听的socket
  EventCallbackRef listen_handler; //accept的处理函数 
       对应 C_processor_accept,其对应Processor::accept()函数
}

AsyncConnection

class AsyncConnection : public Connection {
    //对应的socket
    ConnectedSocket cs; 
    //发送消息队列
    map<int, list<pair<bufferlist, Message*> > > out_q;
    //对应的工作者线程
    Worker *worker;
    //对应的事件中心,也就是本Connection的所有的实际都有center处理
    EventCenter *center;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值