某次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   调入      

相关文章
相关标签/搜索