某次ceph中rgw對象存儲異常的分析

2016-06-22 11:40:17.639591 2b067aa0e700 10 adding .rgw+.bucket.meta.im-core-prd-aa-s100-30:mzone.1461106.2611 to cache LRU end安全

2016-06-22 11:40:17.639593 2b067aa0e700 10 updating xattr: name=user.rgw.acl bl.length()=163
2016-06-22 11:40:17.639596 2b067aa0e700 20 get_obj_state: s->obj_tag was set empty
2016-06-22 11:40:17.639598 2b067aa0e700 20 Read xattr: user.rgw.acl
2016-06-22 11:40:17.639599 2b067aa0e700 20 Read xattr: user.rgw.idtag
2016-06-22 11:40:17.639600 2b067aa0e700 20 Read xattr: user.rgw.manifest
2016-06-22 11:40:17.639604 2b067aa0e700 10 cache get: name=.rgw+.bucket.meta.im-core-prd-aa-s100-30:mzone.1461106.2611 :type miss (requested=17, cached=22)
2016-06-22 11:40:17.639607 2b067aa0e700 20 get_obj_state: rctx=0x2b067aa0d0e0 obj=.rgw:.bucket.meta.im-core-prd-aa-s100-30:mzone.1461106.2611 state=0x2b06681eda90 s->prefetch_data=0
2016-06-22 11:40:17.639621 2b067aa0e700 20 rados->read ofs=0 len=524288
2016-06-22 11:40:17.640115 2b067aa0e700 20 rados->read r=0 bl.length=226函數

2016-06-22 11:40:17.640128 2b067aa0e700 10 cache put: name=.rgw+.bucket.meta.im-core-prd-aa-s100-30:mzone.1461106.2611
2016-06-22 11:40:17.640130 2b067aa0e700 10 moving .rgw+.bucket.meta.im-core-prd-aa-s100-30:mzone.1461106.2611 to cache LRU endfetch

2016-06-22 11:40:17.640138 2b067aa0e700 10 chain_cache_entry: cache_locator=.rgw+im-core-prd-aa-s100-30
2016-06-22 11:40:17.640138 2b067aa0e700 10 chain_cache_entry: cache_locator=.rgw+im-core-prd-aa-s100-30
2016-06-22 11:40:17.640140 2b067aa0e700 10 chain_cache_entry: cache_locator=.rgw+.bucket.meta.im-core-prd-aa-s100-30:mzone.1461106.2611那我ui


異常分析:
異常點分析1:
在bucket建立失敗後再次建立的狀況下,日誌顯示:
cache_map中對應bucket的mzone元數據,名字存在,但對應的cache 實體信息爲全0(懷疑,由於flags=0)
因此,引用cache put操做來更新它的mzone元數據時,由於entry裏面的lru_iter指針的值其實是0,表明NULL,與
lru中記錄的lru.end不等
故而調用了對應的moving方法而不是adding方法
調用moving方法的時候,由於lru是list<string>結構,先對其(原來的信息--原來的entry.iter執行的那個name作了)作移除,
再將新的name加入的lru隊列 
可是因爲,entry.iter其實是NULL,因此並無移除什麼東西,而name實實在在是加入了lru,不過lru.size的值卻沒有所以增長
就會出現lru記錄的長度和實際的長度不等的狀況。而adding操做的話不會出現這種狀況。指針

修復方法1:
用list.contain判斷lru中是否有該對象,有的話再刪除:
list.contains("對象name"))
修改後代碼:
函數:void ObjectCache::touch_lru
原代碼:
 
  else
  {
    ldout(cct, 10) << "moving " << name << " to cache LRU end" << dendl;
    lru.erase(lru_iter);
    lru.push_back(name);
    lru_iter = lru.end();
    --lru_iter;
  }
  
  修改後:
   
  else
  {
    ldout(cct, 10) << "moving " << name << " to cache LRU end" << dendl;
    if(lru.contains(lru_iter))
    { 
        lru.erase(lru_iter);
        lru_size--;
    }
   
    lru.push_back(name);
    lru_iter = lru.end();
    lru_iter--;
    lru_size++;
  }
  //lru.end不必定是NULL
  修改目的: 保證lru的size和實際內容協調。若是lru_iter是空,那麼就徹底至關於新增。
  可是這也不是問題的關鍵。
  關鍵是,當lru_iter是空的時候,不該該將指針傳入cache_lru函數,因此,須要改:
  並且指針的++和--操做的安全性也沒有判斷啊)
 
 在ObjectCache::touch_lru函數的去重操做後,adding或moving前,加入地址指針有消息判斷:
 if(lru_iter == NULL)
 {
    ldout(cct,20) << "ERR! entry name="<<name<<"iter is empty"<<endl;
    return;
 }
 
  
  異常分析2:
  異常1出現的本質緣由是cache_map中,mzone對應的name的實體entry是全0(懷疑),因此,排查cache_map中entry填充信rgw_cache_lru_size息。
  那麼,就是mzone的放入cache_map出了問題。。
  
  放入:
  1. cache put
  放入lru_iter的信息正常狀況是lru的末尾指針,
  異常的話,若是cache_map中有值,但爲0,就不等於end
  entry就會是這個0,就是cache_map中有,可是全0
  
  第一次:
  指針=lru的end,通過touch_lru後,指向lru的尾部,若是爲0,說明,lru的尾部就是0了
  
  注意:list的end指向的不是NULL(能夠不是),而是list中末尾元素的下一個,
  而end地址--就是末尾信息
  
  
  異常分析3:
  lru_size與lru信息長度不一致時,會出現什麼狀況:排查:
  1.touch_lru的去重過程當中,若總長度大於配置長度rgw_cache_lru_size(默認1000)時,觸發!
  操做:當lru_size大於設置值,而且,當前lru指針(從頭/最舊的開始)不等於須要加入的name指針,那麼修建cache_map,這裏由於iter是從lru裏面取出來的,作pop_front的時候,卻是真的能夠不用判斷的。
  
  然而lru_size除了這次外,並無作循環變量用,因此應該不會形成危害。
  
  問題: 
  若是name還有須要處理的項,也就是在name以前的,可是沒有有效使用()
 好比存盤,好比其餘處理,怎麼辦?這就被清理了?日誌

 定位方式:
 全局查找:removing entry: name=看有沒有對應的name
 。。。。。
 正常狀況下,cache_map中的mzone應該已經存在了,那麼,get的時候,獲取name對應的entry就是存在的。
 
 
 //int ObjectCache::get(string& name, ObjectCacheInfo& info, uint32_t mask, rgw_cache_entry_info *cache_info)對象

 
 待改進3:
 cacahe中寫入和修改元數據的時候有日誌,怎麼寫入說數據的時候不打日誌啊
 日誌啊。。很重要的啊
 
 定位到:
 寫入數據的時候,已經將name加入了cache map 可是沒有將元數據加入
 
 get_obj_ref
---都是本地基本操做,失敗的機率小,由於沒有特定性,如
pool_create
open_bucket_pool_ctx隊列

只多是IO或者POOL建立失敗
並且返回值=不存在-EONETrem

最大可能性:
ObjectReadOperation操做執行失敗
返回值=不存在
rgw_rados_ref.ioctx.operateget

*****************************
create_bucket
get_bucket_info

在循環中,必然是get_bucket_entrypoint_info
中返回的,可是該函數在以前被其餘流程調用過
在獲取實例信息的時候是OK的


get_bucket_instance_from_oid

get_bucket_instance_from_oid
    rgw_get_system_obj

    step1  int ret = rop.stat(objv_tracker);     if (ret < 0)       return ret;               store->stat_system_obj                RGWRados::get_obj_state_impl                raw_obj_stat             if (r == -ENOENT)   {     s->exists = false;     s->has_attrs = true;     s->mtime = 0;     return 0;   }      step2 由於在enoent的狀況下,返回的是0,因此繼續read   ret = rop.read(0, request_len - 1, bl, objv_tracker);      進入get_system_obj第一步:執行get_obj_state   失敗,返回      stat_system_obj在astate的exists爲false的時候,也會返回enoent,因此。。這樣也能夠,可能會。。。         get_bucket_entrypoint_info   調入      

相關文章
相關標籤/搜索