Ceph 学习——OSD读写流程与源码分析(一)

本文详细探讨Ceph OSD模块的主要类,包括OSD、PrimaryLogPG和PGBackend,以及OSD读写流程。从接收到客户端消息开始,分析OSD如何处理请求,封装为RequestOp,检查epoch,直到在PrimaryLogPG类中完成PG状态转换和数据读写的处理。文章还介绍了读写函数调用路径,从ms_fast_dispatch到do_request,再到do_op,最终在os层完成事务处理。
摘要由CSDN通过智能技术生成

消息从客户端发送而来,之前几节介绍了 客户端下 对象存储、块存储库的实现以及他们在客户端下API请求的发送过程(Ceph学习——Librados与Osdc实现源码解析Ceph学习——客户端读写操作分析Ceph学习——Librbd块存储库与RBD读写流程源码分析)。当请求被封装后,通过消息发送模块(Ceph学习——Ceph网络通信机制与源码分析)将请求及其相关信息发送到服务端实现真正的对数据的操作。服务端的操作模块便是由OSD、OS模块完成的,这节先介绍OSD模块。

直接上图:


这里写图片描述

同样当前最新的版本,和之前的版本有所不同,有一些模块简化了,类的名字也改了。先介绍图中涉及的相关的类,然后在对类中具体函数主要调用流程进行分析。

OSD 模块主要的类


这里写图片描述

盗图:其中ReplicatedPG 在最新的版本中去掉了,更改为PrimaryLogPG类

OSD类

OSD和OSDService是核心类,他们直接在顶层负责一个OSD节点的工作,从客户端的得到的消息,就是先到达OSD类中,通过OSD类的处理,在调用PrimaryLogPG(之前为ReplicatedPG 类)类进行处理。该类中,在读写流程中的主要工作是消息(Message)封装为 RequestOp,检查epoch (版本)是否需要更新,并获取PG句柄,并做PG相关的检查,最后将请求加入队列。

PrimaryLogPG类

该类继承自PG类,PGBackend::Listener(该类是一个抽象类)类PG类处理相关状态的维护,以及实现PG层面的功能,核心功能是用boost库的statechart状态机来做PG状态转换。它实现了PG内的数据读写等功能。

PGBackend类

该类主要功能是将请求数据通过事务的形式同步到一个PG的其它从OSD上(注意:主OSD的操作PrimaryLogPG来完成)。
他有两个子类,分别是 ReplicatedBackend和ECBackend,对应着PG的的两种类型的实现。

OSD读写函数调用流程


这里写图片描述

1)OSD::ms_fast_dispatch 函数是接收消息Message的入口函数,他被网络模块的接收线程调用。主要工作是 检查service服务 、把Message封装为OpRequest类型、获取session、获取最新的OSdMap,最后dispatch_session_waiting,进入下一步。

void OSD::ms_fast_dispatch(Message *m)
{
  FUNCTRACE();
  if (service.is_stopping()) {
  //检查service,如果停止了直接返回
    m->put();
    return;
  }
  OpRequestRef op = op_tracker.create_request<OpRequest, Message*>(m);//把Message封装为OpRequest类型
...
...

  if (m->get_connection()->has_features(CEPH_FEATUREMASK_RESEND_ON_SPLIT) ||
      m->get_type() != CEPH_MSG_OSD_OP) {
    // queue it directly直接调用enqueue_op处理
    enqueue_op(
      static_cast<MOSDFastDispatchOp*>(m)->get_spg(),
      op,
      static_cast<MOSDFastDispatchOp*>(m)->get_map_epoch());
  } else {
    Session *session = static_cast<Session*>(m->get_connection()->get_priv());//获取 session 其中包含了一个Connection的相关信息
    if (session) {
      {
    Mutex::Locker l(session->session_dispatch_lock);
    op->get();
    session->waiting_on_map.push_back(*op);//将请求加如waiting_on_map的列表里
    OSDMapRef nextmap = service.get_nextmap_reserved();//获取最新的OSDMAP
    dispatch_session_waiting(session, nextmap);//该函数中 循环处理请求
    service.release_map(nextmap);
      }
      session->put();
    }
  }
  OID_EVENT_TRACE_WITH_MSG(m, "MS_FAST_DISPATCH_END", false); 
}

2)OSD::dispatch_session_waiting 主要工作是循环处理队列waiting_on_map中的元素,对比OSDmap,以及获取他们的pgid,最后调用enqueue_op处理。

void OSD::dispatch_session_waiting(Session *session, OSDMapRef osdmap)
{
  assert(session->session_dispatch_lock.is_locked());

  auto i = session->waiting_on_map.begin();
  while (i != session->waiting_on_map.end()) {
  //循环处理waiting_on_map中的元素
    OpRequestRef op = &(*i);
    assert(ms_can_fast_dispatch(op->get_req()));
    const MOSDFastDispatchOp *m = static_cast<const MOSDFastDispatchOp*>(
      op->get_req());
    if (m->get_min_epoch() > osdmap->get_epoch()) {
  //osdmap版本不对应
      break;
    }
    session->waiting_on_map.erase(i++);
    op->put();

    spg_t pgid;
    if (m->get_type() == CEPH_MSG_OSD_OP) {
      pg_t actual_pgid = osdmap->raw_pg_to_pg(
    static_cast<const MOSDOp*>(m)->get_pg());
      //osdmap->get_primary_shard(actual_pgid, &pgid)获取 pgid  该PG的主OSD
      if (!osdmap->get_primary_shard(actual_pgid, &pgid)) {
    continue;
      }
    } else {
      pgid = m->get_spg();
    }
    enqueue_op(pgid, op, m->get_map_epoch());//获取成功则调用enqueue_op处理
  }

  if (session->waiting_on_map.empty()) {
    clear_session_waiting_on_map(session);
  } else {
    register_session_waiting_on_map(session);
  }
}

3)OSD::enqueue_op 的主要工作是将求情加入到op_shardedwq队列中

void OSD::enqueue_op(spg_t pg, OpRequestRef& op, epoch_t epoch)
{
...
  op->osd_trace.event("enqueue op");
  op->osd_trace.keyval("priority", op->get_req()->get_priority());
  op->osd_trace.keyval("cost", op->get_req()->get_cost());
  op->mark_queued_for_pg();
  logger->tinc(l_osd_op_before_queue_op_lat, latency);
  //加入op_shardedwq队列中
  op_shardedwq.queue(
    OpQueueItem(
      unique_ptr<OpQueueItem::OpQueueable>(new PGOpItem(pg, op)),
      op->get_req()->get_cost(),
      op->get_req()->get_priority(),
      op->get_req()->get_recv_stamp(),
      op->get_req()->get_source().num(),
      epoch));
}

4)OSD::dequeue_op 调用函数进行osdmap的更新,调用do_request进入PG处理流程

void OSD::dequeue_op(
  PGRef pg, OpRequestRef op,
  ThreadPool::TPHandle &handle)
{
...
...
  logger->tinc(l_osd_op_before_dequeue_op_lat, latency);

  Session *session = static_cast<Session *>(
    op->get_req()->get_connection()->get_priv());
  if (session) {
      //调用该函数进行 osdmap的更新
    maybe_share_map(session, op, pg->get_osdmap());
    session->put();
  }
  //正在是删除、直接返回
  if (pg->is_deleting())
    return;

  op->mark_reached_pg();
  op->osd_trace.event("dequeue_op");
  //调用pg的do_request处理
  pg->do_request(op, handle);

  // finish
  dout(10) << "dequeue_op " << op << " finish" << dendl;
  OID_EVENT_TRACE_WITH_MSG(op->get_req(), "DEQUEUE_OP_END", false);
}

5)PrimaryLogPG::do_request该函数 主要你检查PG的状态,以及根据消息类型进行不同处理

void PrimaryLogPG::do_request(
  OpRequestRef& op,
  ThreadPool::TPHandle &handle)
{
...
  // make sure we have a new enough map
  //检查 osdmap
  auto p = waiting_for_map.find(op->get_source());
...

  //是否可以丢弃
  if (can_discard_request(op)) {
    return;
  }
...
...
  //PG还没有peered
  if (!is_peered()) {
    // Delay unless PGBackend says it's ok
      
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值