本文的所有的分析仅基于个人理解,代码基于ceph nautilus版本

文章目录

  • MDSDaemon Start
  • MDSDaemon Init
  • 定时器
    • 消息接收和处理
  • 总结

MDSDaemon Start

首先一切的开始自然是mds进程的上电过程:

src/ceph_mds.cc

int main(int argc, const char **argv)
{// 全局初始化,任何类型ceph daemon启动时都需要调用global_init来完成一些初始化工作auto cct = global_init(NULL, args,CEPH_ENTITY_TYPE_MDS, CODE_ENVIRONMENT_DAEMON,0, "mds_data");// 初始化堆栈分析器,如果设置了CEPH_HEAP_PROFILER_INIT的环境变量后才会启动,且需要google-perftools才能使用// 默认情况下是不启动的,后续可以通过ceph tell mds.$name heap start_profiler来启动ceph_heap_profiler_init();// 对fork的封装Preforker forker;entity_addrvec_t addrs;pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC, &addrs);// Normal startupif (g_conf()->name.has_default_id()) {derr << "must specify '-i name' with the ceph-mds instance name" << dendl;exit(1);}if (g_conf()->name.get_id().empty() ||(g_conf()->name.get_id()[0] >= '0' && g_conf()->name.get_id()[0] <= '9')) {derr << "MDS id '" << g_conf()->name << "' is invalid. ""MDS names may not start with a numeric digit." << dendl;exit(1);}// fork子进程并等待子进程退出??if (global_init_prefork(g_ceph_context) >= 0) {std::string err;int r = forker.prefork(err);if (r < 0) {cerr << err << std::endl;return r;}if (forker.is_parent()) {if (forker.parent_wait(err) != 0) {return -ENXIO;}return 0;}// 为子进程执行global_initglobal_init_postfork_start(g_ceph_context);}common_init_finish(g_ceph_context);global_init_chdir(g_ceph_context);auto nonce = ceph::util::generate_random_number<uint64_t>();// 创建一个Messenger实例并进行相关配置std::string public_msgr_type = g_conf()->ms_public_type.empty() ? g_conf().get_val<std::string>("ms_type") : g_conf()->ms_public_type;Messenger *msgr = Messenger::create(g_ceph_context, public_msgr_type,entity_name_t::MDS(-1), "mds",nonce, Messenger::HAS_MANY_CONNECTIONS);if (!msgr)forker.exit(1);msgr->set_cluster_protocol(CEPH_MDS_PROTOCOL);cout << "starting " << g_conf()->name << " at " << msgr->get_myaddrs()<< std::endl;uint64_t required =CEPH_FEATURE_OSDREPLYMUX;msgr->set_default_policy(Messenger::Policy::lossy_client(required));msgr->set_policy(entity_name_t::TYPE_MON,Messenger::Policy::lossy_client(CEPH_FEATURE_UID |CEPH_FEATURE_PGID64));msgr->set_policy(entity_name_t::TYPE_MDS,Messenger::Policy::lossless_peer(CEPH_FEATURE_UID));msgr->set_policy(entity_name_t::TYPE_CLIENT,Messenger::Policy::stateful_server(0));int r = msgr->bindv(addrs);if (r < 0)forker.exit(1);// get monmap/* monmap内容如下,记录了mon节点的ip/port,名称等信息fsid d60bfa64-9f2c-42c4-ad33-d964eab9e7fclast_changed 2019-10-10 10:16:41.683766created 2019-10-10 10:16:41.6837660: 192.168.2.41:6789/0 mon.um11: 192.168.2.42:6789/0 mon.um22: 192.168.2.43:6789/0 mon.um3具体解释见https://docs.ceph.com/docs/master/architecture/*/MonClient mc(g_ceph_context);if (mc.build_initial_monmap() < 0)forker.exit(1);global_init_chdir(g_ceph_context);msgr->start();// start mds// 新建一个mds实例并初始化,至此mds常规启动完成,可接受消息并分发处理mds = new MDSDaemon(g_conf()->name.get_id().c_str(), msgr, &mc);r = mds->init();if (r < 0) {msgr->wait();goto shutdown;}msgr->wait();shutdown:// 优雅退出流程return 0;
}

至此,新建了一个MDSDaemon实例,MDSDaemon是mds进程的抽象,继承自Dispatcher类,负责mds和外界(其他ceph daemon、cephfs client)的交互,下面重点关注MDSDaemon的初始化

MDSDaemon Init

src/mds/MDSDaemon.cc

int MDSDaemon::init()
{// 注册到Messenger的订阅者列表中,ceph网络模块的代码此次不关注// 只要知道这里是和收发消息有关即可messenger->add_dispatcher_tail(&beacon);messenger->add_dispatcher_tail(this);// 初始化monclientr = monc->init();// 初始化mgrclientmgrc.init();messenger->add_dispatcher_head(&mgrc);// 想要订阅mdsmap和mgrmap,mdsmap用户维护状态,mgrmap还未研究monc->sub_want("mdsmap", 0, 0);monc->sub_want("mgrmap", 0, 0);monc->renew_subs();mds_lock.Unlock();/*admin socket相关,完成的工作有:|__创建AdminSocket类实例|__创建MDSSocketHook类实例|__调用AdminSocket->register_command()来注册MDSDaemon支持的命令*/set_up_admin_socket();g_conf().add_observer(this);mds_lock.Lock();if (beacon.get_want_state() == MDSMap::STATE_DNE) {suicide();  // we could do something more graceful heredout(4) << __func__ << ": terminated already, dropping out" << dendl;mds_lock.Unlock();return 0; }// 初始化SafeTimer定时器timer.init();// 初始化Beaconbeacon.init(*mdsmap);// 设置Messenger名称messenger->set_myname(entity_name_t::MDS(MDS_RANK_NONE));// schedule tick// 开始定时器调度reset_tick();mds_lock.Unlock();return 0;
}

定时器

从MDSDaemon的init过程可以看到,会开启一个定时器,之后在mds的生命周期内,该定时器会不断触发并进行一些工作,这里再简单介绍下ceph中定时器的用法:

void MDSDaemon::reset_tick()
{// cancel oldif (tick_event) timer.cancel_event(tick_event);// schedule// 开启定时器,当定时器时间到后调用MDSDaemon::tick()tick_event = timer.add_event_after(g_conf()->mds_tick_interval,new FunctionContext([this](int) {ceph_assert(mds_lock.is_locked_by_me());tick();}));
}// 定时器时间到时执行该函数:先重置定时器,再调度MDSRank::tick()
// 默认定时器时间为mds_tick_interval:5s
void MDSDaemon::tick()
{// reschedulereset_tick();// Call through to subsystems' tick functionsif (mds_rank) {mds_rank->tick();}
}

消息接收和处理

mds收到外部消息后通过MDSDaemon::ms_dispatch2来进行分发处理,这里又分为core msg和client msg两类。

bool MDSDaemon::ms_dispatch2(const Message::ref &m)
{std::lock_guard l(mds_lock);if (stopping) {return false;}// Drop out early if shutting down// 如果mds进程已经处于shutdown状态,则不能处理消息if (beacon.get_want_state() == CEPH_MDS_STATE_DNE) {dout(10) << " stopping, discarding " << *m << dendl;return true;}// First see if it's a daemon message// 优先处理其他daemon的msg(mon,osd等)const bool handled_core = handle_core_message(m);if (handled_core) {return true;}// Not core, try it as a rank message// 如果不是daemon msg,则交由MDSRankDispatcher::ms_dispatch()来处理if (mds_rank) {return mds_rank->ms_dispatch(m);} else {return false;}
}

MDS消息处理流程总结概括为下图:

总结

  1. MDS的启动过程大致如下:

    1. 命令行参数解析
    2. 全局初始化工作
    3. 初始化堆栈分析器,需设置CEPH_HEAP_PROFILER_INIT的env
    4. fork子进程并等待子进程退出
    5. 创建一个Messenger实例并进行相关配置,用于消息的收发
    6. monmap的获取
    7. 新建一个MDSDaemon实例并初始化
  2. mds启动后默认开一个启定时器,间隔为mds_tick_interval(默认5s)
  3. mds的消息处理入口为ms_dispatch2

ceph mds启动流程相关推荐

  1. ceph进程启动流程

    2019独角兽企业重金招聘Python工程师标准>>> 转载于:https://my.oschina.net/u/2874260/blog/1592612

  2. 【ceph】ceph命令处理流程代码分析(终端敲命令之后发生的事)

    目录 后端部分 Admin Socket 前端部分 python ceph 命令下发流程:命令行/usr/bin/ceph-->python 前端部分处理-->Admin Socket后端 ...

  3. 源码分析-Activity的启动流程

    以android 6.0源码为参考,其他版本api会稍有不同 在Activity中,启动一个Activity的方法 @Override public void startActivity(Intent ...

  4. Centos 6启动流程详解

    author:JevonWei 版权声明:原创作品 Centos6 启动流程 POST开机自检 当按下电源键后,会启动ROM芯片中的CMOS程序检查CPU.内存等硬件设备是否正常运行,CMOS中的程序 ...

  5. 2014.4新版uboot启动流程分析

    原文 http://blog.csdn.net/skyflying2012/article/details/25804209 此处转载有稍作修改 最近开始接触uboot,现在需要将2014.4版本ub ...

  6. 解析并符号 读取dll_Spring IOC容器之XmlBeanFactory启动流程分析和源码解析

    一. 前言 Spring容器主要分为两类BeanFactory和ApplicationContext,后者是基于前者的功能扩展,也就是一个基础容器和一个高级容器的区别.本篇就以BeanFactory基 ...

  7. leveldb源码分析:Open启动流程

    leveldb概述 Leveldb 是一个持久化的KV存储系统,主要将大部分数据存储在磁盘上,在存储数据的过程中,根据记录的key值有序存储,当然使用者也可以自定义Key大小比较函数,一个leveld ...

  8. Nginx源码分析:启动流程

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> nginx简介 Nginx的作为服务端软件,表现的主要特点是更快.高扩展.高可靠性.低内存消 ...

  9. JVM启动流程和内存结构

    "Great haste makes great waste" JVM启动流程 JVM是Java程序运行的环境,同时是一个操作系统的一个应用程序进程,因此它有自己的生命周期,也有自 ...

最新文章

  1. 实战:使用 OpenCV 的自动驾驶汽车车道检测(附代码)
  2. 鸿蒙电视哔哩哔哩,[4K视频] 65寸智能电视只要3299元?荣耀智慧屏X1开箱
  3. FCKeditor的使用说明
  4. 【SLAM】gradslam(∇SLAM)开源:论文、代码全都有
  5. 游戏玩家的留存率统计SQL实现
  6. Spring管理的Hibernate事件监听器
  7. 使用Unsafe真的是关于速度或功能吗?
  8. 【PAT - 甲级1006】Sign In and Sign Out (25分)(STLmap)
  9. 2019icpc南京网络赛 A The beautiful values of the palace(离线+树状数组)
  10. PHPstorm链接服务器自动保存
  11. Unity url编码转换
  12. 你知道微服务如何拆分,能解决哪些问题?
  13. 八、python爬虫伪装 [免费伪装ip伪装请求头]
  14. bh1750采集流程图_基于BH1750的光照度检测)报告方案.doc
  15. ipad照片文件删除了怎么恢复
  16. java设计九宫格拼图软件哪个好用_抖音超火的朋友圈九宫格用什么软件做的? 抖音九宫格图片制作教程...
  17. Text to face:寻找黛玉-从语言描述到人脸图像生成
  18. 最新学习笔记 2022-04-04
  19. IT行业技术知识分享说明
  20. android wifi驱动加载失败怎么办,请教WIFI连接失败问题,如何解决

热门文章

  1. 4K工业级高清2进1出HDMI自动USB KVM多电脑切换器(MT-HK201)
  2. C语言蓝桥杯刷题:数字三角形
  3. sqlzoo刷题——select from nobel(诺贝尔获奖查询)
  4. MySQL 自增长主键 在删除数据后依然接着删除的数据增长
  5. 2022年大数据BI工程师项目实训介绍
  6. 【ArcGIS】利用字段计算器按 OSM 道路等级生成道路速度
  7. android 清除通知栏,android startForeground去除通知栏
  8. gb2818的学习第一课
  9. 一键查询自己名下所有微信账户
  10. 自己写一个strcmp函数(C++)