真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Ceph中容量計(jì)算與管理的示例分析

這篇文章主要介紹Ceph中容量計(jì)算與管理的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

站在用戶的角度思考問題,與客戶深入溝通,找到丹陽網(wǎng)站設(shè)計(jì)與丹陽網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶體驗(yàn)好的作品,建站類型包括:成都網(wǎng)站建設(shè)、做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名注冊(cè)、雅安服務(wù)器托管、企業(yè)郵箱。業(yè)務(wù)覆蓋丹陽地區(qū)。

Ceph中的容量計(jì)算與管理

在部署完Ceph集群之后,一般地我們可以通過Ceph df這個(gè)命令來查看集群的容量狀態(tài),但是Ceph是如何計(jì)算和管理的呢?相信大家都比較好奇。因?yàn)橛眠^ ceph df這個(gè)命令的人都會(huì)有這個(gè)疑問,它的輸出到底是怎么計(jì)算的呢?為什么所有pool的可用空間有時(shí)候等于GLOBAL中的可用空間,有時(shí)候不等呢? 帶著這些疑問我們可以通過分析ceph df的實(shí)現(xiàn),來看看Ceph是如何計(jì)算容量和管理容量的。

一般情況下ceph df的輸出如下所示:

ceph-df

[root@study-1 ~]# ceph df
GLOBAL:
    SIZE     AVAIL      RAW USED     %RAW USED 
    196G     99350M       91706M         45.55 
POOLS:
    NAME           ID     USED       %USED     MAX AVAIL     OBJECTS 
    rbd            1      20480k      0.02        49675M          11 
    x              2         522         0        49675M          11

GLOBAL 維度中有SIZE,AVAIL,RAW USED,%RAW USED。從上面的輸出可以看到,ceph對(duì)容量的計(jì)算其實(shí)是分為兩個(gè)維度的。一個(gè)是GLOBAL維度,一個(gè)是POOLS的維度。

POOLS 維度中有 USED,%USED,MAX AVAIL,OBJECTS。

我們這里先把注意力放在RAW USED,和AVAIL上。這個(gè)兩個(gè)分析清楚之后,其它的也就迎刃而解了。

這里我們粗略算一下GLOBAL中的RAW USED 為91706M,明顯大于下面pool 中USED 20480k*3 + 522bytes*3啊。而且各個(gè)pool的MAX AVAIL 相加并不等于GLOBAL中的AVAIL。我們需要深入代碼分析一下為什么。

分析

Ceph 命令基本上都是首先到Montior這里,如何Monitor能處理請(qǐng)求,就直接處理,不能就轉(zhuǎn)發(fā)。

我們看看Monitor是如何處理ceph df這個(gè)命令的。Monitor處理命令主要是在Monitor::hanlde_command函數(shù)里。

handle_command

else if (prefix == "df") {
      bool verbose = (detail == "detail");
      if (f)
        f->open_object_section("stats");
      pgmon()->dump_fs_stats(ds, f.get(), verbose);
      if (!f)
        ds << '\n';
      pgmon()->dump_pool_stats(ds, f.get(), verbose);
      if (f) {
        f->close_section();
        f->flush(ds);
        ds << '\n';
      }
    }

dump_fs_stats 對(duì)應(yīng)GLOBAL這個(gè)維度。dump_pool_stats對(duì)應(yīng)POOLS這個(gè)維度。從上面的代碼可以知道,主要是兩個(gè)函數(shù)完成了df命令的輸出。一個(gè)是pgmon()->dump_fs_stats,另一個(gè)是pgmon()->dump_pool_stats。

  • GLOBAL維度

從PGMonitor::dump_fs_stats開始:

dump_fs_stats

void PGMonitor::dump_fs_stats(stringstream &ss, Formatter *f, bool verbose) const
{
  if (f) {
    f->open_object_section("stats");
    f->dump_int("total_bytes", pg_map.osd_sum.kb * 1024ull);
    f->dump_int("total_used_bytes", pg_map.osd_sum.kb_used * 1024ull);
    f->dump_int("total_avail_bytes", pg_map.osd_sum.kb_avail * 1024ull);
    if (verbose) {
      f->dump_int("total_objects", pg_map.pg_sum.stats.sum.num_objects);
    }
    f->close_section();
  }

stat_pg_update

void OSDService::update_osd_stat(vector& hb_peers)
{
  Mutex::Locker lock(stat_lock);
  osd_stat.hb_in.swap(hb_peers);
  osd_stat.hb_out.clear();
  osd->op_tracker.get_age_ms_histogram(&osd_stat.op_queue_age_hist);
  // fill in osd stats too
  struct statfs stbuf;
  int r = osd->store->statfs(&stbuf);
  if (r < 0) {
    derr << "statfs() failed: " << cpp_strerror(r) << dendl;
    return;
  }
  uint64_t bytes = stbuf.f_blocks * stbuf.f_bsize;
  uint64_t used = (stbuf.f_blocks - stbuf.f_bfree) * stbuf.f_bsize;
  uint64_t avail = stbuf.f_bavail * stbuf.f_bsize;
  osd_stat.kb = bytes >> 10;
  osd_stat.kb_used = used >> 10;
  osd_stat.kb_avail = avail >> 10;
  osd->logger->set(l_osd_stat_bytes, bytes);
  osd->logger->set(l_osd_stat_bytes_used, used);
  osd->logger->set(l_osd_stat_bytes_avail, avail);
  check_nearfull_warning(osd_stat);
  dout(20) << "update_osd_stat " << osd_stat << dendl;

可以看到相關(guān)字段數(shù)值的輸出主要依賴pg_map.osd_sum的值,而osd_sum是各個(gè)osd_stat的總和。所以我們需要知道單個(gè)osd的osd_stat_t是如何計(jì)算的。


FIleStore::statfs從上面我們可以看到update_osd_stat 主要是通過osd->store->statfs(&stbuf),來更新osd_stat的。因?yàn)檫@里使用的是Filestore,所以需要進(jìn)入FileStore看其是如何statfs的。

int FileStore::statfs(struct statfs *buf)
{
  if (::statfs(basedir.c_str(), buf) < 0) {
    int r = -errno;
    assert(!m_filestore_fail_eio || r != -EIO);
    assert(r != -ENOENT);
    return r;
  }
  return 0;
}

可以看到上面FileStore主要是通過::statfs()這個(gè)系統(tǒng)調(diào)用來獲取信息的。這里的basedir.c_str()就是data目錄。所以osd_sum計(jì)算的就是將所有osd 數(shù)據(jù)目錄的磁盤使用量加起來?;氐缴厦娴妮敵?,因?yàn)槲沂褂玫氖且粋€(gè)磁盤上的目錄,所以在statfs的時(shí)候,會(huì)把該磁盤上的其它目錄也算到Raw Used中?;氐缴厦娴妮敵?,因?yàn)槭褂脙蓚€(gè)OSD,且每個(gè)OSD都在同一個(gè)磁盤下,所以GLOBAL是這么算的

Ceph中容量計(jì)算與管理的示例分析

同上,就知道Ceph如何算Raw Used,AVAIL的。

  • POOLS維度

從PGMonitor::dump_pool_stats()來看,該函數(shù)以pool為粒度進(jìn)行循環(huán),通過 pg_map.pg_pool_sum來獲取pool的信息。其中USED,%USED,OBJECTS是根據(jù)pg_pool_sum的信息算出來的。而MAX AVAIL 是單獨(dú)算出來的。

這里有一張圖,可以幫助同學(xué)們梳理整個(gè)的流程。中間僅取了一些關(guān)鍵節(jié)點(diǎn)。有一些省略,如想知道全貌,可以在PGMonitor::dump_pool_stats查閱。

Ceph中容量計(jì)算與管理的示例分析

通過分析代碼我們知道,pool的使用空間(USED)是通過osd來更新的,因?yàn)橛衭pdate(write,truncate,delete等)操作的的時(shí)候,會(huì)更新ctx->delta_stats,具體請(qǐng)見ReplicatedPG::do_osd_ops。舉例的話,可以從處理WRITE的op為入手點(diǎn),當(dāng)處理CEPH_OSD_OP_WRITE類型的op的時(shí)候,會(huì)調(diào)用write_update_size_and_usage()。里面會(huì)更新ctx->delta_stats。當(dāng)IO處理完,也就是applied和commited之后,會(huì)publish_stats_to_osd()。

這里會(huì)將變化的pg的stat_queue_item入隊(duì)到pg_stat_queue中。然后設(shè)置osd_stat_updated為True。入隊(duì)之后,由tick_timer在C_Tick_WithoutOSDLock這個(gè)ctx中通過send_pg_stats()將PG的狀態(tài)發(fā)送給Monitor。這樣Monitor就可以知道pg的的變化了。

可用空間,即MAX AVAIL的值,計(jì)算稍微有點(diǎn)復(fù)雜。Ceph是先計(jì)算Available的值,然后根據(jù)副本策略再計(jì)算MAX AVAIL的值。Available的值是在get_rule_avail()中計(jì)算的。在該函數(shù)中通過get_rule_weight_osd_map()算出來一個(gè)有weight的osd列表。

注意這里的weight一般是小于1的,因?yàn)樗粤藄um。而sum就是pool中所有osd weight的總和。在拿到weight列表后,就會(huì)根據(jù)pg_map.osd_stat中kb_avail的值進(jìn)行除以weight,選出其中最小的,作為Available的值。

這么描述有些抽象了,具體舉一個(gè)例子。比如這里我們的pool中有三個(gè)osd,假設(shè)kb_avail都是400G

即,

{osd_0: 0.9, osd_1, 0.8, osd_2: 0.7}。計(jì)算出來的weight值是{osd_0: 0.9/2.4,osd_1: 0.8/2.4,osd_2: 0.7/2.4}

這樣后面用osd的available 空間除以這里的weight值,這里的Available的值就是400G*0.7/2.4。這里附上一個(gè)公式,可能更直觀一些。

Ceph中容量計(jì)算與管理的示例分析

然后根據(jù)你的POOL的副本策略不同,POOL的AVAL計(jì)算方式也不同。如果是REP模式,就是直接除以副本數(shù)。如果是EC模式,則POOL的AVAL是Available * k / (m + k)。

所以一般情況下,各個(gè)POOL的MAX AVAIL之和與GLOBAL的AVAIL是不相等的,但是可以很接近(相差在G級(jí)別可以忽略為接近)。

總結(jié)

分析到這里,我們知道CEPH中容量的計(jì)算是分維度的,如果是GLOBAL維度的話,因?yàn)槭褂玫氖莖sd的所在磁盤的statfs來計(jì)算所以還是比較準(zhǔn)確的。而另一個(gè)維度POOLS

由于需要考慮到POOL的副本策略,CRUSH RULE,OSD WEIGHT,計(jì)算起來還是比較復(fù)雜的。容量的管理主要是在OSD端,且OSD會(huì)把信息傳遞給MON,讓MON來維護(hù)。

計(jì)算osd weight值比較復(fù)雜,這里附上算weight的函數(shù),添加了一些注釋,有助于感興趣的同學(xué)一起分析。

int CrushWrapper::get_rule_weight_osd_map(unsigned ruleno, map *pmap)
{
  if (ruleno >= crush->max_rules)
    return -ENOENT;
  if (crush->rules[ruleno] == NULL)
    return -ENOENT;
  crush_rule *rule = crush->rules[ruleno];
  // build a weight map for each TAKE in the rule, and then merge them
  for (unsigned i=0; ilen; ++i) {
    map m;
    float sum = 0;
    if (rule->steps[i].op == CRUSH_RULE_TAKE) {//如果是take的話,則進(jìn)入
      int n = rule->steps[i].arg1;
      if (n >= 0) { // n如果大于等于0的話是osd,否則是buckets
    m[n] = 1.0; // 如果是osd的話,因?yàn)檫@里是直接take osd,所有有沒有權(quán)重已經(jīng)不重要了
    sum = 1.0;
      } else { // 不是osd,是buckets的話
    list q;
    q.push_back(n); // buckets 的id 入隊(duì)
    //breadth first iterate the OSD tree
    while (!q.empty()) {
      int bno = q.front(); // 取出buckets的id
      q.pop_front();  // 出隊(duì)
      crush_bucket *b = crush->buckets[-1-bno]; // 根據(jù)序號(hào)拿到buckets
      assert(b); // 這個(gè)buckets必須是存在的
      for (unsigned j=0; jsize; ++j) { // 從buckets的items數(shù)組中拿相應(yīng)的bucket
        int item_id = b->items[j];  
        if (item_id >= 0) { //it's an OSD
          float w = crush_get_bucket_item_weight(b, j);  // 拿出該osd的weight
          m[item_id] = w; // m 入隊(duì)
          sum += w; // weight加和
        } else { //not an OSD, expand the child later
          q.push_back(item_id);  // 如果不是osd,則添加其item_id,所以這里是一個(gè)樹的深度遍歷
        }
      }
    }
      }
    }
    for (map::iterator p = m.begin(); p != m.end(); ++p) {
      map::iterator q = pmap->find(p->first);
      // 因?yàn)槲覀冞@里傳入的pmap是沒有數(shù)據(jù)的
      // 所以第一次必中,
      if (q == pmap->end()) {
    (*pmap)[p->first] = p->second / sum;
      } else {
    // 這里還需要考慮osd在不同的buckets里的情況
    q->second += p->second / sum;
      }
    }
  }
  return 0;
}

以上是“Ceph中容量計(jì)算與管理的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


網(wǎng)頁題目:Ceph中容量計(jì)算與管理的示例分析
文章轉(zhuǎn)載:http://weahome.cn/article/jpseic.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部