参考资料:

《Ceph源码分析》

https://my.oschina.net/u/2460844/blog/788172

Cache Tier

一、简介

Cache Tiering是Ceph中一种自动分层存储的技术,其中有两种存储池:高速池(缓存池,由SSD等高速设备组成)作为缓存层、低速池(数据池,由HDD等低速设备组成)作为数据层。对于客户端来说,Cache Tier是无感知的,它们把数据发给Objector Handles,并不关心数据是写到高速池或是低速池。这些内部数据流动由tiering agent来自动处理。数据分层的好处在于提高热点数据存储性能并且降低了存储成本(不需要全部使用SSD就能得到近似SSD性能)。缺点在于占用一定计算性能、数据IO。

图1.1 Cache Tier 原理图

通俗的讲,Cache Tier把用户经常访问的热数据放在高速池,把不经常访问的数据放在低速池,可以类比LRU缓存处理。站在用户的角度,一个访问总是能很快被响应,好像数据都是存放在高速设备一样,极大的提升了用户体验的同时又保证的成本不会太高(使用大量便宜的HDD和少量昂贵的SSD)。

实现这种分层存储的关键在于:

  • 数据访问行为的追踪、统计和分析

  • 数据如何迁移?

Cache Tier有四种模式:writeback、readproxy、readonly、proxy。后文会详细介绍每个模式的读写操作。

二、CacheTier 命令相关源码分析

所有命令都是在OSDMonitor::prepare_command_impl()方法中处理。

首先给出pool中与cache相关的部分参数,后面的命令基本和这些参数有关,在osd_types.h文件中。

pg_pool_t{std::set<uint64_t> tiers;   ///< pools that are tiers of usint64_t tier_of = -1;     ///< pool for which we are a tier// Note that write wins for read+write opsint64_t read_tier = -1;    ///< pool/tier for objecter to direct reads toint64_t write_tier = -1;   ///< pool/tier for objecter to direct writes to}

命令1:ceph osd tier add {storagepool} {cachepool}

np是storagepool的pg_pool_t指针,ntp是cachepool的pg_pool_t指针。

 np->tiers.insert(tierpool_id);np->set_snap_epoch(pending_inc.epoch); // tier will update to our snap infontp->tier_of = pool_id;ss << "pool '" << tierpoolstr << "' is now (or already was) a tier of '" << poolstr << "'";

上述代码中,在np中向其tiers队列插入cachepool_id;在ntp中tier_of设置为storagepool_id。

简而言之,在storagepool中添加cachepool_id,在cachepool中添加storagepool_id。分别保存在各自的pg_pool_t::tiers和pg_pool_t::tier_of中。

命令2:ceph osd tier remove/rm {storagepool} {cachepool}

np->tiers.erase(tierpool_id);ntp->clear_tier();ss << "pool '" << tierpoolstr << "' is now (or already was) not a tier of '" << poolstr << "'";

remove操作则是把storagepool的tiers队列中的cachepool_id给删除,同时把cachepool的tier_of给置为-1。

命令3:ceph osd tier set-overlay {storagepool} {cachepool}

read_tier和write_tier分别是读写操作的缓存池id。

pg_pool_t *np = pending_inc.get_new_pool(pool_id, p);np->read_tier = overlaypool_id;np->write_tier = overlaypool_id;np->set_last_force_op_resend(pending_inc.epoch);pg_pool_t *noverlay_p = pending_inc.get_new_pool(overlaypool_id, overlay_p);noverlay_p->set_last_force_op_resend(pending_inc.epoch);ss << "overlay for '" << poolstr << "' is now (or already was) '" << overlaypoolstr << "'";

set-overlay主要工作就是设置storagepool的read_tier和write_tier为cachepool_id。

命令4:ceph osd tier remove-overlay/rm-overlay {storagepool}

np->clear_read_tier();np->clear_write_tier();np->set_last_force_op_resend(pending_inc.epoch);ss << "there is now (or already was) no overlay for '" << poolstr << "'";

remove-overlay把storagepool中的read_tier和write_tier置为-1。

命令5:ceph osd tier cache-mode {cachepool} {cache-mode}

cache_mode表明当前池的缓存模式。目前支持:writeback、readonly、proxy、readproxy、none。

pg_pool_t *np = pending_inc.get_new_pool(pool_id, p);np->cache_mode = mode;// set this both when moving to and from cache_mode NONE. this is to// capture legacy pools that were set up before this flag existed.np->flags |= pg_pool_t::*FLAG_INCOMPLETE_CLONES*;ss << "set cache-mode for pool '" << poolstr<< "' to " << pg_pool_t::get_cache_mode_name(mode);

设置cachepool的cache_mode字段为指定模式。

命令6:ceph osd tier add-cache {storagepool} {cachepool} {cachesize}

pg_pool_t *np = pending_inc.get_new_pool(pool_id, p);pg_pool_t *ntp = pending_inc.get_new_pool(tierpool_id, tp);if (np->tiers.count(tierpool_id) || ntp->is_tier()) {wait_for_finished_proposal(op, new C_RetryMessage(this, op));return true;}np->tiers.insert(tierpool_id);np->read_tier = np->write_tier = tierpool_id;np->set_snap_epoch(pending_inc.epoch); // tier will update to our snap infonp->set_last_force_op_resend(pending_inc.epoch);ntp->set_last_force_op_resend(pending_inc.epoch);ntp->tier_of = pool_id;ntp->cache_mode = mode;ntp->hit_set_count = g_conf().get_val<uint64_t>("osd_tier_default_cache_hit_set_count");ntp->hit_set_period = g_conf().get_val<uint64_t>("osd_tier_default_cache_hit_set_period");ntp->min_read_recency_for_promote = g_conf().get_val<uint64_t>("osd_tier_default_cache_min_read_recency_for_promote");ntp->min_write_recency_for_promote = g_conf().get_val<uint64_t>("osd_tier_default_cache_min_write_recency_for_promote");ntp->hit_set_grade_decay_rate = g_conf().get_val<uint64_t>("osd_tier_default_cache_hit_set_grade_decay_rate");ntp->hit_set_search_last_n = g_conf().get_val<uint64_t>("osd_tier_default_cache_hit_set_search_last_n");ntp->hit_set_params = hsp;ntp->target_max_bytes = size;ss << "pool '" << tierpoolstr << "' is now (or already was) a cache tier of '" << poolstr << "'";

addcache集合了Cache Tier中多个命令,根据默认配置设置了Cache Tier所有参数。命令中必须要指明:storagepool、cachepool和size。size表示存储池最大大小,并不一定和底层block设备大小一致。

以下通过表格的方式展示addcache命令设置的所有参数。

参数名
storagepool
tiers {cachepool_id}
read_tier {cachepool_id}
write_tier {cachepool_id}
cachepool
tier_of {storagepool_id}
cache_mode mode 默认writeback
hit_set_count osd_tier_default_cache_hit_set_count 默认 4
hit_set_period osd_tier_default_cache_hit_set_period 默认1200
min_read_recency_for_promote osd_tier_default_cache_min_read_recency_for_promote 默认1
min_write_recency_for_promote osd_tier_default_cache_min_write_recency_for_promote 默认1
hit_set_grade_decay_rate osd_tier_default_cache_hit_set_grade_decay_rate 默认20
hit_set_search_last_n osd_tier_default_cache_hit_set_search_last_n 默认1
hit_set_params hit_set 可在osd_tier_default_cache_hit_set_type配置参数中设置类型,有bloom、explicit_hash、explicit_object三种,默认为bloom。
target_max_bytes {cachesize}

命令7:ceph osd pool set {cachepool} {key} {value}

set 可以设置pool的属性,这里仅介绍cachepool(非数据池)相关属性。

此命令源码比较简单,即把pool响应的参数改写,这里不贴出源码。

以下给出所有可以通过此命令设置的cachepool相关参数。

参数名 含义
hit_set_type hitset类型
hit_set_period 每过该段时间,系统要重新产生一个新的hitset对象来记录独享的缓存统计信息
hit_set_count 记录系统保存最近的多少个hitset记录
hit_set_fpp 只在hitset类型为bloom时有效,设置其假阳性概率 bloom过滤器仅当判断结果为不在数据集中为100%正确,不能完全肯定一个数据是否在数据集中,因此需要设置fpp参数来手动调整判断存在的概率。
target_max_objects cachepool存储的最大对象数量
target_max_bytes cachepool存储的最大字节数
cache_target_full_ratio 数据满比例,当数据达到这个比例时,就认为cachepool已经满了
cache_target_dirty_ratio 目标脏数据率,当脏数据率达到这个值时,后台cache agent开始flush数据。 脏数据:未写入数据池的数据 flush:把数据从缓存池转移到数据池
cache_target_dirty_high_ratio 高速脏数据比例,当达到此比例时,后台cache agent 高速flush数据
use_gmt_hitset hitset archive对象命名规则
cache_min_flush_age 缓存池脏数据被flush的最小时间,单位秒
cache_min_evict_age 缓存池干净数据被evict的最小时间,单位秒 干净数据:数据已经写入数据池 evict:把数据从缓存池中删除
hit_set_grade_decay_rate hitset每轮衰减比率。 例如衰减率为20,一个hitset刚创建时grade为1M,等到再创建一个hitset时,之前创建的hitset的grade衰减为1M*(1-(rate)/100)=0.8M,上上个hitset则为0.8M*(1-(rate)/100)=0.64M,依次类推
hit_set_search_last_n accumulate atmost N hit_sets for temperature
min_read_recency_for_promote 读操作需要promote时,检查最近的几个hitset,0表示直接通过检查,n表示检查最近的n个hitset。如果在hitset中命中检查的对象,则对对象进行提升操作。
min_write_recency_for_promote 写操作需要promote时,检查最近的几个hitset,0表示直接通过检查,n表示检查最近的n个hitset。如果在hitset中命中检查的对象,则对对象进行提升操作。

三、Cache Tier源码解析

3.1 Cache Tier 的初始化

Cache Tier的初始化有两个时机:

  • on_activate_complete:每个pool在所有PG处于activate状态后会尝试建立cache tier。

  • plgp_on_pool_change:当Monitor通知osdmap相关信息发生变化时,会尝试建立cache tier。

cache tier的初始化包含两部分:hitset初始化和agent初始化。hitset用来记录对象在cachepool中的命中情况,agent用来处理对象的load、flush、evict等操作。

3.1.1 hitset

hitset用来跟踪和统计对象的访问行为。可以把hitset想象成一个set,里面保存了对象的唯一标识记录,set支持插入、查找等功能。cachepool用它来记录池中保存了哪些对象,这样在接到client的读写请求时,可以快速判断对象是否在缓存池中,便于进行后续操作。

目前hitset有三种实现方式:

  • ExplicitObjectHitSet:set保存了hobject整个数据结构,查询正确率100%,但速度慢,占用内存大。
  • ExplicitHashHitSet:set保存了对象32位的哈希值。查询正确率100%,占用空间小,速度较慢。
  • BloomHitSet:默认模式。不再使用set,而是使用Bloom过滤器,速度最快,占用空间最小。只能保证缓存中不存在的判定结果是肯定正确的。

hitset初始化步骤如上图流程图。

3.1.2 agent

agent的建立比较简单,一是创建了 agent_state,其中保存了pg执行flush和evict的相关参数,例如:hitset、flush_mode、num_objects、target_max_bytes、cache_target_dirty_ratio_micro等等;二是把pg加入到agent_queue。

agent_queue是agent线程的工作队列,其中保存了OSD中所有归属于cachepool的PG。agent线程是在OSDService中创建的专门用来处理cache tier数据迁移的线程,线程名叫:osd_srv_agent。其作用就是循环遍历agent_queue中的所有pg,并对他们执行agent_work()操作。

a gent_work()就是遍历PG中所有对象,去寻找已经过期的、失效的需要flush或者evict的对象并对它们执行相应操作。注意:osd_srv_agent线程是一个OSD上所有PG公用的,为了保证效率,设置了严格的限流参数:osd_pool_default_cache_max_evict_check_size限制依次遍历对象的总数,达到后立刻切换退出循环在osd_srv_agent中切换PG;osd_agent_max_ops设置了一个循环中最多能够处理几次flush或者evict操作。

agent_maybe_evict()处理了需要evict的对象。这里再次介绍下evict是针对cachepool中已经过期或过冷的干净数据,只需要把它从cachepool中删除即可。此函数的处理逻辑如下:

  1. 如果对象处于以下情况之一,则不能进行evict操作,直接退出。多数判断在agent_work()中也做过。

    • 脏数据

    • 处于scrubbing状态,或者说等待scrub

    • 处于被监视状态

    • block状态,正在对此对象进行读写操作

    • cache_pinned,被定在cachepool中

    • snap,镜像数据

  2. 当evict_mode为EVICT_MODE_SOME,需要对对象进行判断后决定是否执行evict。判断规则如下:

    • 对象存活时间如果小于cache_min_evict_age,则不做evict。
    • 使用hitset对对象进行打分,计算的分数需要满足(1000000 - temp_upper < evict_effort)(temp_upper为对象热度值,evict_effort为PG在agent队列里的优先级分数),否则不做evict。
  3. 如果evict_mode为EVICT_MODE_FULL,则直接驱逐对象,不做打分。

agent_maybe_flush()中把脏数据刷新到storagepool,脏数据是只保存在cachepool中,还未写入storagepool的数据。此函数处理逻辑如下:

  1. 如果对象处于以下情况之一,则不做flush操作。

    • 不是脏数据。
    • cache_pinned,被定在cachepool中。
    • 对象正在被flushing,只是脏数据状态未更新。
  2. 如果evict_mode不是EVICT_MODE_FULL,对象snap状态为CEPH_NOSNAP,并且对象存活时间小于cache_min_flush_age,则不做flush操作。

  3. 调用start_flush()执行后续操作。

start_flush()具体流程如下:

  1. 获取snapset。在O版之前(不包括O版),需要对snapset做一次get_filtered(),目的是把已经删除的快照过滤掉。O版之后则不需要做过滤操作。
  2. 判断obc->obs.oi.manifest.is_chunked(),如果为true,返回EOPNOTSUPP。
  3. 检查比当前clone对象版本更早的克隆对象:如果该克隆对象为missing状态,返回ENOENT;如果该克隆对象存在,且为脏对象,返回EBUSY。
  4. 设置对象blocked状态为true。
  5. 如果flush_ops队列中已经存在当前对象,则执行try_flush_mark_clean()

3.2 读写流程

接下来介绍Cache Tier是如何在读写过程中起作用的。

3.2.1 client的OSD选择

上图是client写操作的流程图,其中_calc_target()完成了关键的地址寻址工作:通过Crushmap计算出一组OSD,并根据一定规则找出消息的即将发往的主OSD。

这里顺便介绍下_calc_target()。

_calc_target() 是源码中计算主 osd 目标方法,大致流程如下:

  1. 根据 poolid 获取 pool 信息,包括 type、crush id、pg 数量等。
  2. 判断是否强制重发,标志位:force_resend
  3. 判断是否有缓存池,若有,则更新 pool 信息为缓存池信息,若没有,则不操作。
  4. 根据发送对象的信息(name,key,namespce)和 poolid,来计算 pg 信息,得到关键参数 m_seed。
  5. 根据 pg 信息,使用 crush 算法计算对象发送到哪组 osd 以及主 osd。
  6. 根据本次发送的目标是否和上一次发送的一致(对象和 pool 都一样才为一致)以及 any_change 参数,重置 force_resend。
  7. 读取 osd 状态(CEPH_OSDMAP_PAUSERD、CEPH_OSDMAP_PAUSEWR),判断是否暂停发送。
  8. 判断是否合法变更,标志位:legacy_change。
  9. 根据 pool 的 pg 数量是否变化,若变化,则 split_or_merge 标志位置真。
  10. 更新 op_target_t 参数,包括发送主 osd 以及 osd 组,成功返回 RECALC_OP_TARGET_NEED_RESEND。

上述过程中,第3步设置了target_oloc.pool。根据basepool是否有read_tier或者write_tier,把target_oloc.pool设置为对应读或者写操作的pool。这样后续计算出的OSD也是在cachepool中的OSD。

//apply tieringt->target_oid = t->base_oid;t->target_oloc = t->base_oloc;if ((t->flags & *CEPH_OSD_FLAG_IGNORE_OVERLAY*) == 0) {if (is_read && pi->has_read_tier())t->target_oloc.pool = pi->read_tier;if (is_write && pi->has_write_tier())t->target_oloc.pool = pi->write_tier;pi = osdmap->get_pg_pool(t->target_oloc.pool);if (!pi) {t->osd = -1;return *RECALC_OP_TARGET_POOL_DNE*;}}

总结:

client的Cache Tier的应用主要体现在计算OSD的过程中,通过判断basepool的参数,来决定是否要更新targetpool:读操作时,如果有read_tier,则更新为read_tier pool;写操作时,如果有write_tier,则更新为write_tier pool。read_tier和write_tier与pool是否开启Cache Tier有关,第二节有过相关介绍。

3.2.2 server的处理流程

server就是上一节calc_target()中计算出的OSD所在主机。

上图大致描述了OSD处理请求的调用流程,Cache Tier在do_op()函数中体现。

do_request()步骤如下:

  1. 在waiting_for_map中尝试查找当前op的source,如果找到,说明waiting_for_map中有来自相同客户端的旧的op,则把当前op加入wait_for_map中的list队列,并直接返回。如果未找到,执行下一步操作。
  2. 判断op的min_epoch是否大于当前PG保存的OSDmap的epoch,如果大于,说明op的Epoch更新,则把当前op加入waiting_for_map队列,并直接返回,否则,进行下一步操作。
  3. 判断是否可以丢弃(can_discard_request)。如果是,直接返回,否则进行下一步操作。
  4. 执行pg_wide backoffs相关操作。
  5. 检查PG是否处于Peer状态,如果不处于,则判断是否可以由PGBackend处理,如果可以,则交由对应的PGBackend处理(handle_message()),如果不可以,则加入waiting_for_peered队列。如果PG处于Peer状态,则进行下一步操作。
  6. 判断PG是否有正在执行的flush操作,如果由则把当前op加入waiting_for_flush队列,并直接返回。否则进行下一步操作。
  7. 根据op的msg_type执行对应的处理函数。如类型为CEPH_MSG_OSD_OP,则调用do_op()处理op。

如果开启了Cache Tier,将会在do_op中执行以下操作:

  1. 首先判断hit_set中是否包含待操作的对象(hit_set->contains(obc->obs.oi.soid)),如果不包含,则把对象添加到hit_set中。添加对象后,如果hit_set满了,或者hit_set超时,则调用hit_set_persist()。
  2. 执行agent_choose_mode(),设置agent相关参数,如flush_mode、num_objects、num_bytes等。
  3. 执行maybe_handle_cache()。这里处理cache执行逻辑。
  4. 如果maybe_handle_cache()中调用maybe_handle_cache_detail(),如果成功处理了op请求,则直接return,否则会继续执行后续操作(说明不需要从datapool读取数据或者转发请求到datapool,可以直接在此osd命中查询的对象),由本OSD执行读取操作。

3.2.3 agent_choose_mode()

此函数中计算了一个PG的flush和evict行为的相关参数。

  • dirty_micro与full_micro,分别是脏数据的比率和数据满的比率。

    1. 如果设置了target_max_bytes,就按照字节数计算:

      dirty_micro = 脏对象数目 × 每个对象的平均大小 / 每个PG的平均字节数 × 100000

      full_micro = 用户对象数目 × 每个对象平均大小 / 每个PG的平均字节数 × 1000000

    2. 如果设置了target_max_objects,则按照对象数量计算:

      dirty_micro = 脏对象数目 / 每个PG的平均对象数量 × 100000

      full_micro = 用户对象数目 / 每个PG的平均对象数量 × 1000000

    3. 如果同时设置了以上两个参数,则dirty_micro和full_micro为1)、2)中的最大值。

  • flush_target、flush_high_target、flush_slop,分别是执行flush的脏数据率,高速flush的脏数据率和修正参数

    1. 先获取初始值:

      flush_target = cache_target_dirty_ratio_micro

      flush_high_target = cache_target_dirty_high_ratio_micro

      flush_slop = osd_agent_slop

    2. 执行修正操作:

      a. 如果restart或者flush_mode == FLUSH_MODE_IDLE

      flush_target = flush_target + flush_slop

      flush_high_target = flush_high_target + flush_slop

      b. !restart 并且 flush_mode != FLUSH_MODE_IDLE

      flush_target = flush_target – min(flush_target, flush_slop)

      flush_high_target = flush_high_target – min(flush_high_target, flush_slop)

  • 重新设置flush_mode

    1. 如果dirty_micro > flush_high_target,flush_mode设为FLUSH_MODE_HIGH。
    2. 如果dirty_micro < flush_high_target,并且dirty_micro > flush_target,flush_mode设为FLUSH_MODE_LOW。
  • evict_target、evict_slop,分别是evict操作的满数据率和evict修正参数

  1. 获取初始值

    evict_target = cache_target_full_ratio_micro

    evict_slop = osd_agent_slop

  2. 执行修正操作

    a. 如果(restart || evict_mode == EVICT_MODE_IDLE)

    evict_target = evict_target + evict_slop

    b. 否则

    evict_target = evict_target – min(evict_target, evict_slop)

  • 重新设置evict_mode,计算evict_effort(PG在agent工作队列里的优先级)

    1. 如果full_micro > 1000000

      evict_mode = EVICT_MODE_FULL

      evict_effort = 1000000

    2. 如果full_micro > evict_target

      evict_mode = EVICT_MODE_SOME

      over = full_micro – evict_target

      span = 1000000 – evict_target

      evict_effort = max((over * 1000000 / span), (osd_agent_min_evict_effort * 1000000))

      inc = cct->_conf->osd_agent_quantize_effort * 1000000

      was = evict_effort

      evict_effort = evict_effort - evict_effort % inc

      evict_effort = max(evict_effort, inc)

3.2.4 maybe_handle_cache_detail

maybe_handle_cache_detail()首先对传进来的op做了一系列的判断,如果可以直接由当前OSD处理的(缓存命中),则直接返回NOOP;如果当前OSD不是主OSD,则由osd报告给client一个错误,要求重发消息给正确的主osd;如果以上两种情况都不满足,则需要处理cache的细节,如请求转发,提升对象等,具体操作由cache_mode决定。

先介绍几个后续用到的处理请求的方式:

  1. do_proxy_read():cachepool向datapool请求数据,并把获得的数据返回给cli ent。注意:cachepool不会保存请求的数据。

  1. do_proxy_write():cachepool把写请求转发给datapool。注意:cachepool中没有写入该对象。

  1. block_write_on_full_cache():因为cachepool已满,所以把请求加入请求等待队列,把要改写的对象加入对象阻塞队列,并标记op为delayed延迟操作。
void PrimaryLogPG::block_write_on_full_cache(const hobject_t &_oid, OpRequestRef op) {objects_blocked_on_cache_full.insert(oid);waiting_for_cache_not_full.push_back(op);op->mark_delayed("waiting for cache not full");}

在PG运行过程中,每次涉及到evict_mode变化的时候,都会尝试把waiting_for_cache_not_full中被阻塞的请求重新添加到OSD的op_shardedwq队列中,再由OSD重发给对应的pg实例去执行op操作。

  1. promote_object():从datapool中读取指定对象并写入cachepool中。

  1. do_cache_direct():把client请求转发给datapool,cachepool不接收返回的消息。
void PrimaryLogPG::do_cache_redirect(OpRequestRef op) {auto m = op->get_req<MOSDOp>();int flags = m->get_flags() & (*CEPH_OSD_FLAG_ACK* | *CEPH_OSD_FLAG_ONDISK*);MOSDOpReply *reply = new MOSDOpReply(m, -ENOENT, get_osdmap_epoch(),flags, false);request_redirect_t redir(m->get_object_locator(), pool.info.tier_of);reply->set_redirect(redir);dout(10) << "sending redirect to pool " << pool.info.tier_of << " for op "<< op << dendl;m->get_connection()->send_message(reply);return;}
  • WRITEBACK

    1. evict_mode == EVICT_MODE_FULL,此参数在agent_choose_mode()中设定,说明cache pool需要全速evict对象,池使用量接近满了。

      读操作:do_proxy_read()

      写操作:block_write_on_full_cache()

    2. 写操作

      首先do_proxy_write(),然后maybe_promote()。

      maybe_promote()中对对象做了一个判断:是否把该对象从datapool中提取到cachepool?如果是,则执行promote_object();如果否,则return false。

      判断的规则:1. 检查recency标志位,其数值表示promote操作需要检查多少个hit_set,0表示直接判定提升无需检查,n表示检查当前的最近的n个hit_set。2. 如果在hit_set中命中了改对象,则执行提升,否则return false。3. 做最后的限流检查(osd->promote_throttle()),通过后执行promote_object(),并return true。

    3. 读操作

      首先do_proxy_read(),然后maybe_promote()。

  • READONLY

    读操作:promote_object()

    写操作:do_cache_redirect()

  • PROXY

    1. must_promote == false

      写操作:do_proxy_write()

      读操作:do_proxy_read()

    2. evict_mode == EVICT_MODE_FULL

      block_write_on_full_cache(),阻塞op,等待后续cachepool空间释放。

    3. 以上两种情况都不符合

    4. promote_object(),直接提升对象,在cachepool中读写操作,后续由angent保证datapool数据一致。

  • READPROXY

    1. 写操作或者must_promote == true

      如果evict_mode == EVICT_MODE_FULL,则block_write_on_full_cache()。

      否则直接提升,promote_object()。

(),然后maybe_promote()。

  • READONLY

    读操作:promote_object()

    写操作:do_cache_redirect()

  • PROXY

    1. must_promote == false

      写操作:do_proxy_write()

      读操作:do_proxy_read()

    2. evict_mode == EVICT_MODE_FULL

      block_write_on_full_cache(),阻塞op,等待后续cachepool空间释放。

    3. 以上两种情况都不符合

    4. promote_object(),直接提升对象,在cachepool中读写操作,后续由angent保证datapool数据一致。

  • READPROXY

    1. 写操作或者must_promote == true

      如果evict_mode == EVICT_MODE_FULL,则block_write_on_full_cache()。

      否则直接提升,promote_object()。

    2. 读操作:do_proxy_read()。

Cache Tiering相关推荐

  1. cache tier 分级缓存

    一图描述 cache tier: Ceph 缓存层将冷热数据分离,以快速存储设备作为缓存层,低速廉价存储设备作为存储层 提升 IO 性能 使用两个 pool,作为存储层和缓存层,缓存层覆盖在存储层上, ...

  2. Ceph性能测试(RBD、CephFS、NFS、Cache Tier)

    本文是以下两篇文章的后续: 探索fio参数如何选择以及全方位对比HDD和SSD性能:部署Ceph前测试磁盘性能,同时基于fio测试参数的变化深入了解fio原理和磁盘IO特点. CentOS8使用cep ...

  3. ceph存储原理_赠书 | Linux 开源存储全栈详解——从Ceph到容器存储

    // 留言点赞赠书我有书,你有故事么?留言说出你的存储故事留言点赞前两名,免费送此书截止日期12.27号12.30号公布名单 // 内容简介 本书致力于帮助读者形成有关Linux开源存储世界的细致的拓 ...

  4. Linux开源存储全栈详解:从Ceph到容器存储

    内容简介 本书致力于帮助读者形成有关Linux开源存储世界的细致的拓扑,从存储硬件.Linux存储堆栈.存储加速.存储安全.存储管理.分布式存储.云存储等各个角度与层次展开讨论,同时对处于主导地位的. ...

  5. 分布式存储系统中的数据高效缓存方法

    点击上方蓝字关注我们 分布式存储系统中的数据高效缓存方法 杨青霖, 吴桂勇, 张广艳 清华大学计算机科学与技术系,北京 100084 摘要:针对典型分布式存储系统存在的写放大.I/O路径过长.响应时延 ...

  6. SSD固态盘应用于Ceph集群的四种典型使用场景

    在虚拟化及云计算技术大规模应用于企业数据中心的科技潮流中,存储性能无疑是企业核心应用是否虚拟化.云化的关键指标之一.传统的做法是升级存储设备,但这没解决根本问题,性能和容量不能兼顾,并且解决不好设备利 ...

  7. MULTI-CLOCK: Dynamic Tiering for Hybrid Memory Systems(动态分层混合存储系统)

    文章目录 背景知识补充 1.存储金字塔 2.频率和带宽 3.Page 页 4.持久内存PM 5.LRU等页面置换算法 6.字节寻址 7.预取Prefetching 8.UMA与NUMA 9.持久化指令 ...

  8. CPU Cache原理与示例

    CPU Cache原理与示例 基础知识 现在的 CPU 多核技术,都会有几级缓存,老的 CPU 会有两级内存(L1 和 L2),新的CPU会有三级内存(L1,L2,L3 ),如下图所示: 其中:  ...

  9. Cache Memory技术示例

    Cache Memory技术示例 为什么需要cache?如何判断一个数据在cache中是否命中?cache的种类有哪些,区别是什么? 为什么需要cache memory 先思考第一个问题:程序是如何运 ...

最新文章

  1. Scrapy框架的使用之Scrapy对接Selenium
  2. Centos 7 安装 gcc-5.5
  3. XAML 布局StackPanel
  4. [vue] ajax、fetch、axios这三都有什么区别?
  5. web应用自动化测试的演进
  6. Vivado生成bit文件出现error解决
  7. Mysql学习总结(42)——MySql常用脚本大全
  8. PyTorch 学习笔记(三):transforms的二十二个方法
  9. blob 按换行 分裂_Blob对象介绍
  10. activemq之Windows安装
  11. python最常用的版本是_在下列选项中,( ) 是最常用的 Python版本,也称之为CIassicPython。_学小易找答案...
  12. php qrcode 生成二维码 中间加logo的二维码
  13. 【Elasticsearch源码】 更新性能分析
  14. JavaFX Effect
  15. 奇迹mu技术分享:奇迹服务端中的【DATA】文件详细说明
  16. 一、计算机网络的作用和认识互联网
  17. 【微信小程序】用户授权及getUserProfile接口使用
  18. 交换机ftp将文件传到服务器,如何用FTP实现交换机间配置文件复制?
  19. iOS 偏好设置 NSUserDefault
  20. * What went wrong:A problem occurred evaluating project ‘:app‘.> Failed to apply plugin ‘com.andro

热门文章

  1. 8种微信小程序赚钱方式
  2. 程序员的小幽默:让你笑到肚子痛的搞笑动图
  3. 东西归置20210815
  4. mac播客播放器:Moon FM for Mac
  5. 软考下午题第1题——数据流,题目分析与案例解析:
  6. 大漠Android模拟器中控,最新如意大漠多线程中控模板,适用于手游模拟器脚本...
  7. Java--字符串反转函数
  8. Linux rsync命令用法
  9. 照明控制系统在呼和浩特商场楼宇的应用
  10. class文件格式解析