Ceph 读写流程

本文将梳理Ceph的读写流程,希望帮助希望了解Ceph的人。

概述

Ceph的读写流程是由OSD和PG共同完成的,对于OSD而言,OSD的主要任务是进行消息的接收分发,最终将消息存到队列op_wq中。接下来交由ShardedThreadPool线程池中的线程来处理读写,线程会将请求从op_wq中取出,做如下操作。

写操作相对于读操作复杂很多,这是由于Ceph采用副本的高可用机制。一份完整的数据需要存放在多个OSD上面,只有当所有从都确认数据存储到本地,这时候主才可以向client发送写操作成功消息。在[RADOS: A Scalable, Reliable Storage Service for Petabyte-scale Storage Clusters]中对于写消息提出了primary-copy, chain, splay三个副本策略。 Ceph目前(v10.2.10)采用primary-copy策略。如下图所示

osd1是主osd,在第一个RTT收到client写请求时,向从发送写请求,主在RTT3收到osd2和osd3的ack的时候向client发送ack。

具体读写流程:

  1. OSD接收消息到消息进入op_wq

    如下图所示

    ms_fast_dispatch函数是OSD中线程处理client请求的入口函数,接下来进行一系列的调用,进入到op_wq中等待其它线程调用。

  2. ####op_wq出队列线程调用

    ShardedThreadPool线程池会选取线程调用shardedthreadpool_worker函数对入队列的operations进行处理。最终调用ReplicatedPG::do_reequest对于客户端的请求进行分类处理。

  3. 调用ReplicatedPG::execute_ctx(OpContext *ctx)处理读写

    1. 对于读请求来说,在execute_ctx()函数中会调用ReplicatedPGBackend类中的函数objects_read_sync读入数据,然后在后续的流程中调用complete_read_ctx()向client回复。
    2. 对于写请求来说
      • 如果log过多,需要整理 log 调用calc_trim_to()
      • 调用ReplicatedPGBackend类中issue_op() 向所有从osd发送写请求
      • 主处理从的写完成消息,如果所有的从都完成了写请求,调用回调函数ReplicatedPG::eval_repop()向client发送消息完成写操作

    下图是写操作的示意图:

    图中第二步,主向从发写消息的消息类型是MSG_OSD_REPOP, 第三步从回复的消息类型是MSG_OSD_REPOPREPLY,所带的CEPH_OSD_FLAG_ONDISK标识位为1,表示数据已经写到disk上。

Reference

RADOS: A Scalable, Reliable Storage Service for Petabyte-scale Storage Clusters

Source Code v10.2.10

Ceph源码分析