CEPH 心跳机制osd-heartbeat

osd heartbeat流程分析:
ceph_osd.cc开始, 也就是ceph-osd服务启动开始:

 Messenger *ms_hb_back_client = Messenger::create(g_ceph_context, cluster_msg_type,
                         entity_name_t::OSD(whoami), "hb_back_client",
                         getpid(), Messenger::HEARTBEAT);
  Messenger *ms_hb_front_client = Messenger::create(g_ceph_context, public_msg_type,
                         entity_name_t::OSD(whoami), "hb_front_client",
                         getpid(), Messenger::HEARTBEAT);
  Messenger *ms_hb_back_server = Messenger::create(g_ceph_context, cluster_msg_type,
                           entity_name_t::OSD(whoami), "hb_back_server",
                           getpid(), Messenger::HEARTBEAT);
  Messenger *ms_hb_front_server = Messenger::create(g_ceph_context, public_msg_type,
                            entity_name_t::OSD(whoami), "hb_front_server",
                            getpid(), Messenger::HEARTBEAT);

hb_back_client/hb_front_client/ms_hb_back_server/ms_hb_front_server

[Messenger] 先定义了4个Messenger对象, 其中, hb client是osd发送ping心跳的messenger, hb_back_server是集群网络服务,接收ping心跳, hb_front_server是公开网络接收ping.

Messenger::create() [Messenger] SimpleMessenger() [SimpleMessenger]

现在默认的消息系统是SimpleMessenger。

init_local_connection() [SimpleMessenger]设置了peer_addr为自己的ip, 设置了peer_type, 在msg/msg_types.h中定义, type包括:mon/osd/mds/client

ms_deliver_handle_fast_connect() [Messenger]通知fast dispatcher有新的connection, 这个函数在一个新的链接初始化或者重新链接的时候调用; 会循环fast_dispatcher list, 然后分别通知, 10.2.5中看到只有osd, objecter, heartbeat实现了这个函数;fast_dispatcher这个list会在add_dispatcher_tailadd_dispatcher_head中更新, 更新方法是调用dispatcher(所有继承Dispatcher的类)自己的ms_can_fast_dispatch_any()函数, 这个函数由dispatcher自己实现, 就是返回true或false;

所以要想某个msg需要fast_dispatch, 需要实现ms_can_fast_dispatch_any()ms_fast_dispatch(); 但不是所有的msg都可以fast, 要满足3个要求:

  1. 能够快速处理消息, 不会长时间拿某个lock; 后面两点还没弄明白
    ms_handle_fast_connect() [Dispatcher] 虚函数
    ms_handle_fast_connect() [OSD] 具体实现
    new Session() 并设置了session的一些属性 这块应该还有一些其他动作, 但是没有找到, 我觉得应该建立一个connection [????]


定义了几个hb messenger之后, 会建立网络链接:
ms_hb_back_server/ms_hb_front_server->bind() [SimpleMessenger] 绑定ip port, 进而走accepter那一套, 我们在这里不再分析

osd = new OSD() [OSD] new OSD对象

ms_hbclient/ms_hb_back_server/ms_hb_front_server->start() SimpleMessenger的start(), 也没干啥, 就是起了一个回收pipe的线程, 是一直在回收吗???

osd->init()[OSD] 这个是OSD服务真正初始化的地方, 会做很多处理, 我们在这里先只关注heartbeat的几个初始化

heartbeat_thread.create() [T_Heartbeat] 该类继承的Thread类, 也就是创建了一个单独的heartbeat线程, 该线程的入口函数是heartbeat_entry()

heartbeat_entry() [OSD]一直轮训的发送heartbeat, 时间间隔是wait = .5 + ((float)(rand() % 10)/10.0) * (float)cct->_conf->osd_heartbeat_interval [这个算法有什么含义吗? 没搞懂???]

heartbeat() [OSD]

  • getloadavg() 先获取一下当前系统CPU 1m load, system CPU load有1m, 5m, 15m
    con_back/con_front->send_message() [SimpleMessenger] for循环, 分别向heartbeat_peers中的元素发送MOSDPING::PING message, 就是走messenger的send_message发送到目标osd上.
    heartbeat_check() [OSD] 检查peer osd的heartbeat info
    is_unhealthy() [HeatbeatInfo] 检查ping reply是否超时, 超时: False, 否则: True
    如果超时, 或者没有收到ping reply, failure_queue会更新, 也就是将该osd都加入failure queue.
    heartbeat_peers.empty() 还会检查heartbeat_peers是否为空, 如果为空, 并且, 和monitor的心跳超过了配置的interval, 但是自己还是active的, 就会去更新一下osdmap

下面分析osd对于ping心跳的消息分发及处理:

osd->init() [OSD]

hbclient_messenger->add_dispatcher_head(&heartbeat_dispatcher) heartbeat采用单独的heartbeat dispatcher, 并不是和osd用同一个dispatcher

ms_dispatch() [HeartbeatDispatcher]

osd->heartbeat_dispatch() [OSD] 进入MSG_OSD_PING分支

handle_osd_ping() [OSD]

is_healthy() [HeartbeatMap] 检查本osd内部状态, 不正常的时候, 直接丢弃心跳消息, 处理心跳已经没有意义了; 这个函数后续再研究一下, 在common/HeartbeatMap.cc
send_message() 发送MOSDPing::PING_REPLY的消息, 但是并没有结束, 还会查看当前osdmap, 如果发现osdmap中已经标记收到消息的那个osd为down了, 要去告诉那个osd, 也就是会再发一个MOSDPing::YOU_DIED的message

下面分析收到ping reply消息的处理:

更新peer osd的那些last_rx_front/back到reply的时间戳, 然后检查健康状况:
is_healthy() [HeartbeatInfo], 因为要看收到reply的时间是否超时, 如果健康, 并且之前已经将这个osd加入了failure队列或者正在等待加入failure队列, 会去擦除这个osd

下面分析收到MOSDPing::YOU_DIED的消息处理:

osdmap_subscribe() 自己去订阅osdmap, 我理解的就是更新一下osdmap, 告诉monitor我活了

下面来分析osd将timeout的peer osd加入failure queue后的处理:

(通过查找failure_queue的调用来追踪)

osd->init() [OSD]

tick_timer_without_osd_lock.add_event_after(new C_Tick_WithoutOSDLock) 启动timer, 回调函数是C_Tick_WithoutOSDLock类, 该类中实现finish()函数,

finish() [C_Tick_WithoutOSDLock]

tick_without_osd_lock() [OSD] 这个函数中会在最后又起一个timer, 和上面的timer一模一样, timer就这样有了;

send_failures() [OSD] 除了上面那个函数有调用send_failures(), 还有ms_handle_connect()也调用了, 后续再分析这个分支 ??

monc->send_mon_message() [MonClient]从failure_queue中遍历fail osd, 向monitor发送osd id失败的消息, 然后将osd id从failure queue删除

下面来分析peer osd list的更新:

heartbeat_peers是一个osd idheartbeat info的map关系, 该map会更新的情况: tick()/_committed_osd_maps()/handle_pg_create(), 这几函数都会调用maybe_update_heartbeat_peers(), 进而来更新heatbeat_peers

tick() / _committed_osd_maps() / handle_pg_create()什么时候需要更新peers集合,也即这个函数什么时候会被调用?从实现看,影响peers集合主要是pgmap的变化,那什么时候pgmap可能改变呢?

  1. tick线程中周期性的检查,主要是因为osd启动过程中,会load_pg
  2. osdmap变更的时候,osd承载的pg可能需要重新peering,导致osd状态可能会变为STATE_WAITING_FOR_HEALTHY
  3. pg创建的时候,参考函数
handle_pg_create maybe_update_heartbeat_peers() [OSD]

heartbeat_peers_need_update() [OSD] 先判断一下是否需要更新, 这个是否需要更新, 是看OSD是否处于STATE_WAITING_FOR_HEALTHY状态, 是的话, 如果last_heartbeat_resample(utime_t类型的)是0, 就设置为True(需要更新); 还有一种情况是: last_heartbeat_resample这个时间在osd_heartbeat_grace(默认值20s)范围外, 就去强制更新; 注意前提都是osd处于waiting_for_healthy状态; 什么时候会处于这种状态呢? 一般有: a. 在osd启动的过程中; b.在osd收到更新osdmap的消息,osd状态可能变为waiting
接下来有几个不同维度的更新osd peers, 我们一个一个分析:

  1. 遍历pg, 然后遍历pg的heartbeat peers, 然后从osdmap中检查该osd是否up, 如果up, 就加入本osd的heartbeat peers

  2. 遍历pg, 遍历pg的probe targets peers, 然后检查osd是否up, 然后加入peers

  3. 定义了两个集合, 一个是want, 一个是extras, 然后更新want和extras, want集合中都是什么呢? want中放的是osd的相邻osd id, 那什么算相邻osd呢? 有两个函数: get_next_up_osd_after(whoami),get_previous_up_osd_before(whoami), 分别是比当前osd id大的处于up的第一个osd(for循环, 查osd id, 从osd_id + 1开始找; 并且, osd id的大小判断标准是一个循环的, 最大的osd id的后一个是osd id最小的那个); 比osd id小的第一个up osd, want集合中的osd都是extras(额外的), 然后将额外的加入heartbeat peers中.

    不是简单的加入heartbeat peers就结束了, 还要做一轮检查:

  4. 遍历heartbeat peers, 如果peer osd down了, 就从peers中剔出.

  5. 如果heartbeat peers的总数小于osd_heartbeat_min_peers(配置文件中的, 默认值是10), 就继续将比当前osd id大的up osd加入extras集合中, 并且加入heartbeat peers

  6. 但是如果heartbeat peers的总数大于osd_heartbeat_min_peers(还是那个参数, 也就是没有max, 这个min硬性指标), 会从heartbeat peers中剔除那些, 是extras集合中的, 但不是want集合(相邻的)的osd

  7. 当然, 如果osd一共就比osd_heartbeat_min_peers少, 那也是没办法了.

综上分析:

1.osd heartbeat是单独的线程,单独的dispatcher来分发, 处理的.

  1. osd的heartbeat是一直保持的, 时间间隔是osd_heartbeat_interval(默认是6s)
  2. heartbeat peers是分别从pg heartbeat peers, 相邻osd, 及其他额外相邻的osd中更新的, 但都是up的.
  3. heartbeat发送的是Ping message, peers收到后需要回复ping reply
  4. heartbeat peers更新的时机包括: osd处于waiting_for_healthy的状态时, 也就是osd启动时, 或osdmap有更新时; 新创建pg时;

调优:

  1. 大规模部署情况下,压测的时候(比如1000 vm 跑fio),心跳可能会出问题,可能需要将grace时间调大,避免误报, 如果调大后,interval也应相应增大,避免发送频率太高,保证至少发送过3次心跳后没有回包才上报,比如目前grace为20, interval为6,如果grace为30,则interval建议为9比较合适.
  2. grace调大,也有副作用,如果某个osd异常退出,等待其他osd上报的时间必须为grace,在这段时间段内,这个osd负责的pg的io会hang住。 可以采用我之前的优化的patch,尽量不要将grace调的太大。
  3. 如果集群存在大规模的顺序读写,网络成为瓶颈的时候,可以通过下面这个参数调高心跳消息在内核网络层的优先级: osd_heartbeat_use_min_delay_socket
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容

  • OSD心跳: Heartbeat 主要用于及时发现OSD的变化(down/up), 并且通知Monitor去更新O...
    东京的雨不会淋湿首尔阅读 1,227评论 0 0
  • OSDMap 机制是 Ceph 架构中非常重要的部分,PG 在 OSD 上的分布和监控由 OSDMap 机制执行。...
    lihanglucien阅读 2,725评论 0 1
  • 1. 心跳介绍 心跳是用于节点间检测对方是否故障的,以便及时发现故障节点进入相应的故障处理流程。 问题: 故障检测...
    lihanglucien阅读 3,338评论 0 8
  • 一、如果出现 osd启动报try_get_map错误,可以从正常的osd去导出对应版本的epoch,然后导回就可以...
    zcking阅读 7,212评论 0 1
  • 1. 节点故障检测概述 节点的故障检测是分布式系统无法回避的问题,集群需要感知节点的存活,并作出适当的调整。通常我...
    lihanglucien阅读 1,351评论 0 2