1. 程式人生 > >ceph儲存 ceph叢集osd故障自我檢測

ceph儲存 ceph叢集osd故障自我檢測

心跳是用於OSD節點間檢測對方是否故障的,以便及時發現故障節點進入相應的故障處理流程。故障檢測需要在故障的發現時間和心跳帶來的負載之間做權衡,如果心跳頻率太高則過多的心跳報文會影響系統性能,如果心跳頻率過低則會延長髮現故障節點的時間,從而影響系統的可用性。

建立連線

在大規模部署的場景中,如果任意兩個OSD節點間都建立心跳連線將帶來巨大的負擔。尤其,當新加入一個OSD節點時這個負擔就會幾倍地增加。Ceph中每個OSD只和以下兩類節點建立心跳連線:一類是同個PG下的OSD節點之間,因為屬於同個PG的OSD節點會儲存同份資料的副本,如若出現故障則會直接影響資料的可用性。另一類是OSD的左右兩個相鄰的節點,這兩個節點同自己物理上存在比較緊密的聯絡,例如可能連線在同臺交換機。另外,如果建立心跳的Peer數目少於osd_heartbeat_min_peers,那麼OSD會繼續同離他較近的幾個OSD建立心跳連線。

OSD節點會監聽public、cluster、front和back四個埠,其中front和back兩個埠都是用於心跳的,cluster埠用來監聽來自OSD Peer的連線,public用來監聽來自Monitor和Client的連線。如果啟動OSD時沒有提供back的IP地址,則back使用cluster的IP地址;而front不單獨提供IP地址,直接使用public的IP地址。另外,OSD單獨建立了一個名為hbclient的Messenger,作為心跳的客戶端,單獨用來建立連線傳送心跳報文。心跳報文優先發送給back連線。

程式碼註釋

// ceph-osd.cc 啟動osd時建立Messengers
OSD::maybe_update_heartbeat_peers() 確定同哪些peer建立心跳連線,剔除已經down掉的節點的心跳連線 OSD::_add_heartbeat_peer() 同給定的peer建立心跳連線 OSDServeice::get_con_osd_hb() 獲取peer的front和back連線

配置

OPTION(public_network, OPT_STR, "")
OPTION(cluster_network, OPT_STR, "")
OPTION(osd_heartbeat_min_peers, OPT_INT, 10)     // minimum number of peers

檢測故障

OSD使用T_Heartbeat執行緒定時向Peer OSDs傳送心跳報文,傳送報文的時間間隔在0.5~6.5之間,由osd_heartbeat_interval配置選項決定。心跳報文會同時向Peer OSD的front和back埠傳送。心跳報文分兩種型別一種是Ping型別,另一種是Reply型別。Ping型別的報文是OSD主動傳送給Peer OSD的報文,而Reply是Peer OSD迴應給自己的報文。兩種型別的心跳報文都攜帶時間戳,但它們的時間戳代表的含義不一樣。Ping型別報文的時間戳是傳送報文時的時間,而Reply型別報文的時間戳是從Ping報文中讀取出來的,不是代表它自己的傳送時間而是代表它對應的Ping報文的傳送時間。OSD接收到Reply報文時將記錄報文的時間戳,並以此來判斷是否超時。

對每個Peer節點,如果其最近的應答的時間(最近的Reply報文的時間戳)位於cutoff之前(即超時grace秒),則將其加入到failure_queue佇列。OSD會定時向Monitor彙報自己的狀態,在彙報狀態時將failure_queue佇列中Peer傳送給Monitor,由Monitor將其標記為down狀態。Monitor在接收到OSD對Peer的故障報告後,通過PAXOS演算法決定是否將Peer OSD標記為Down狀態。如果將Peer OSD標記為Down狀態,那麼將更新OSD MAP,OSD接收到OSD Map更新的訊息後,斷開和Peer OSD的心跳連線。

如果在向Monitor報告故障之後但在接收到OSD Down訊息之前,再次接收到Peer OSD對心跳報文的迴應,則將Peer OSD從failure_queue佇列中移除,並通知Monitor該節點依舊存活著。

程式碼註釋

void OSD::heartbeat_entry() // T_Heartbeat執行緒入口函式,定時向心跳Peers傳送心跳報文
void OSD::heartbeat()
map<int,utime_t> failure_queue; // 檢測到peer長時間沒心跳時,將peer加入到failure_queue佇列
map<int,entity_inst_t> failure_pending; // 故障報告給Monitor的Peer OSD
void send_failures();
void send_still_alive(epoch_t epoch, const entity_inst_t &i);
void OSD::note_down_osd(int peer)
void OSD::handle_osd_ping(MOSDPing *m) // 處理MOSDPing訊息

配置

OPTION(osd_heartbeat_interval, OPT_INT, 6)       // (seconds) how often we ping peers
OPTION(osd_heartbeat_grace, OPT_INT, 20)         // (seconds) how long before we decide a peer has failed