ceph-msg-messager|ceph网络通信架构--02

目录

ceph的网络通信

ceph网络通信模式分类

simple框架

message数据格式

Ceph通信模块代码分析

ceph网络通信模块类说明

1. Async通信模块角色

2. Async通信模式

Ceph日志和调试


ceph的网络通信

原文:https://www.dazhuanlan.com/2019/08/21/5d5c34bb785c1/

https://blog.csdn.net/shuningzhang/article/details/90206293

ceph网络通信模式分类

ceph的网络通信的源码在src/msg下,有Ceph Messager的三个实现:simple,async,xio。

simple模式相对比较简单,一个链接的每一端都有两个线程,分别负责读和写,当集群规模很大的时候,会有大量线程,占用大量资源,限制了网络性能。(SimpleMessenger是网络层最早的实现,当时的网络编程模型还是线程当道,因此simple采用的就是这种简单粗暴的线程模型)

async模式基于Epoll + EventCenter,这也是当前的默认消息机制。(async主要是国内ceph大神麦子迈 王豪迈大神的实现的。随着linux提供epoll这样的系统调用,可以提供基于事件的IO多路服用,越来越多的网络开始使用该系统调用来实现高并发通信。比如libevent。async也是如此。)

xio模式基于开源网络通信库accelio来实现,目前处于试验阶段。(xio使用了开源网络通信模块accelio,需要依赖第三方的库,目前也在实验阶段。)

从Messenger.cc 这个类中可以看出在create Messager实例的时候根据type选择网络框架是simple/async/xio.其中选择xio的话需要的话需要定义HAVE_XIO 这个宏,并且xio支持tcp/ip。infiniband 这两种协议,而前两种支持tcp/ip 协议

Messenger *Messenger::create(CephContext *cct, const string &type,
                             entity_name_t name, string lname,
                             uint64_t nonce, uint64_t cflags)
{
    if (r == 0 || type == "simple")
        return new SimpleMessenger(cct, name, std::move(lname), nonce);
    else if (r == 1 || type.find("async") != std::string::npos)
        return new AsyncMessenger(cct, name, type, std::move(lname), nonce);
#ifdef HAVE_XIO
    else if ((type == "xio") &&
             cct->check_experimental_feature_enabled("ms-type-xio"))
        return new XioMessenger(cct, name, std::move(lname), nonce, cflags);
#endif
    lderr(cct) << "unrecognized ms_type '" << type << "'" << dendl;
    return nullptr;
}

Ceph通信框架设计模式

设计模式:订阅发布模式(Subscribe/Publish),又名观察者模式,它意图是“定义对象间的一种一对多的依赖关系,
当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。

 Ceph通信框架流程图

步骤

  • Accepter监听peer的请求, 调用 SimpleMessenger::add_accept_pipe() 创建新的 Pipe 到 SimpleMessenger::pipes 来处理该请求。
  • Pipe用于消息的读取和发送。该类主要有两个组件,Pipe::Reader,Pipe::Writer用来处理消息读取和发送。
  • Messenger作为消息的发布者, 各个 Dispatcher 子类作为消息的订阅者, Messenger 收到消息之后, 通过 Pipe 读取消息,然后转给 Dispatcher 处理。
  • Dispatcher是订阅者的基类,具体的订阅后端继承该类,初始化的时候通过 Messenger::add_dispatcher_tail/head 注册到 Messenger::dispatchers. 收到消息后,通知该类处理。
  • DispatchQueue该类用来缓存收到的消息, 然后唤醒 DispatchQueue::dispatch_thread 线程找到后端的 Dispatch 处理消息。

ceph_message_2

Ceph通信框架类图

架构上采用 Publish/subscribe(发布/订阅) 的设计模式.

simple框架

src/common/config_opts.h
 
OPTION(ms_type, OPT_STR, "simple")


SimpleMessenger 是simple框架具体的实现。
从这个构造函数中可以看到SimpleMessenger 会在构造函数中分别建立结束accepter和发送dispatch_queue 两个线程 

SimpleMessenger::SimpleMessenger(CephContext *cct, entity_name_t name,
                                 string mname, uint64_t _nonce)
    : SimplePolicyMessenger(cct, name, mname, _nonce),   accepter(this, _nonce),
      dispatch_queue(cct, this, mname),
      reaper_thread(this),
      nonce(_nonce),
      lock("SimpleMessenger::lock"), need_addr(true), did_bind(false),
      global_seq(0),
      cluster_protocol(0),
      reaper_started(false), reaper_stop(false),
      timeout(0),
      local_connection(new PipeConnection(cct, this))
{
    ANNOTATE_BENIGN_RACE_SIZED(&timeout, sizeof(timeout),
                               "SimpleMessenger read timeout");
    init_local_connection();

accepter和发送dispatch_queue 线程 建立代码

//这里以accepter为例看看是如何建立接受线程的
class Accepter : public Thread
{
    SimpleMessenger *msgr;
    bool done;
    int listen_sd;
    uint64_t nonce;
    int shutdown_rd_fd;
    int shutdown_wr_fd;
    int create_selfpipe(int *pipe_rd, int *pipe_wr);
public:
    Accepter(SimpleMessenger *r, uint64_t n)
        : msgr(r), done(false), listen_sd(-1), nonce(n),
          shutdown_rd_fd(-1), shutdown_wr_fd(-1)
    {}

    void *entry() override;
    void stop();
    int bind(const entity_addr_t &bind_addr, const set<int> &avoid_ports);
    int rebind(const set<int> &avoid_port);
    int start();
};
//可以看到accepter 是thread的子类
//所以我们先看看其start函数
int Accepter::start()
{
    ldout(msgr->cct, 1) << __func__ << dendl;
    // start thread
    create("ms_accepter");
    return 0;
}
//在start中通过create来新建一个接收线程,其name是ms_accepter
//其次我们在看看这个线程只要执行的工作,其在entry中实现
void *Accepter::entry()
{
    ldout(msgr->cct, 1) << __func__ << " start" << dendl;

    int errors = 0;
    int ch;
    struct pollfd pfd[2];
    memset(pfd, 0, sizeof(pfd));
    pfd[0].fd = listen_sd;
    pfd[0].events = POLLIN | POLLERR | POLLNVAL | POLLHUP;
    pfd[1].fd = shutdown_rd_fd;
    pfd[1].events = POLLIN | POLLERR | POLLNVAL | POLLHUP;
#开始polling
    while (!done)
    {
        ldout(msgr->cct, 20) << __func__ << " calling poll for sd:" << listen_sd << dendl;
        int r = poll(pfd, 2, -1);
        if (r < 0)
        {
            if (errno == EINTR)
            {
                continue;
            }
            ldout(msgr->cct, 1) << __func__ << " poll got error"
                                << " errno " << errno << " " << cpp_strerror(errno) << dendl;
            break;
        }
#检查是否polling返回error
        if (pfd[0].revents & (POLLERR | POLLNVAL | POLLHUP))
        {
            ldout(msgr->cct, 1) << __func__ << " poll got errors in revents "
                                <<  pfd[0].revents << dendl;
            break;
        }
        if (pfd[1].revents & (POLLIN | POLLERR | POLLNVAL | POLLHUP))
        {
            // We got "signaled" to exit the poll
            // clean the selfpipe
#检查是否要退出polling
            if (::read(shutdown_rd_fd, &ch, 1) == -1)
            {
                if (errno != EAGAIN)
                    ldout(msgr->cct, 1) << __func__ << " Cannot read selfpipe: "
                                        << " errno " << errno << " " << cpp_strerror(errno) << dendl;
            }
            break;
        }
        if (done) break;
        // accept
#走到这里polling函数就正常返回了,通过accept函数开始接收
        sockaddr_storage ss;
        socklen_t slen = sizeof(ss);
        int sd = ::accept(listen_sd, (sockaddr *)&ss, &slen);
        if (sd >= 0)
        {
            int r = set_close_on_exec(sd);
            if (r)
            {
                ldout(msgr->cct, 1) << __func__ << " set_close_on_exec() failed "
                                    << cpp_strerror(r) << dendl;
            }
            errors = 0;
            ldout(msgr->cct, 10) << __func__ << " incoming on sd " << sd << dendl;
#实际从pipe中读入msg
            msgr->add_accept_pipe(sd);
        }
        else
        {
            ldout(msgr->cct, 0) << __func__ << " no incoming connection?  sd = " << sd
                                << " errno " << errno << " " << cpp_strerror(errno) << dendl;
            if (++e
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值