Cache Tiering

article/2025/10/18 8:38:00

参考资料:

《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_modemode 默认writeback
hit_set_countosd_tier_default_cache_hit_set_count 默认 4
hit_set_periodosd_tier_default_cache_hit_set_period 默认1200
min_read_recency_for_promoteosd_tier_default_cache_min_read_recency_for_promote 默认1
min_write_recency_for_promoteosd_tier_default_cache_min_write_recency_for_promote 默认1
hit_set_grade_decay_rateosd_tier_default_cache_hit_set_grade_decay_rate 默认20
hit_set_search_last_nosd_tier_default_cache_hit_set_search_last_n 默认1
hit_set_paramshit_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_typehitset类型
hit_set_period每过该段时间,系统要重新产生一个新的hitset对象来记录独享的缓存统计信息
hit_set_count记录系统保存最近的多少个hitset记录
hit_set_fpp只在hitset类型为bloom时有效,设置其假阳性概率 bloom过滤器仅当判断结果为不在数据集中为100%正确,不能完全肯定一个数据是否在数据集中,因此需要设置fpp参数来手动调整判断存在的概率。
target_max_objectscachepool存储的最大对象数量
target_max_bytescachepool存储的最大字节数
cache_target_full_ratio数据满比例,当数据达到这个比例时,就认为cachepool已经满了
cache_target_dirty_ratio目标脏数据率,当脏数据率达到这个值时,后台cache agent开始flush数据。 脏数据:未写入数据池的数据 flush:把数据从缓存池转移到数据池
cache_target_dirty_high_ratio高速脏数据比例,当达到此比例时,后台cache agent 高速flush数据
use_gmt_hitsethitset archive对象命名规则
cache_min_flush_age缓存池脏数据被flush的最小时间,单位秒
cache_min_evict_age缓存池干净数据被evict的最小时间,单位秒 干净数据:数据已经写入数据池 evict:把数据从缓存池中删除
hit_set_grade_decay_ratehitset每轮衰减比率。 例如衰减率为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_naccumulate 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()。


http://chatgpt.dhexx.cn/article/rX5yZphs.shtml

相关文章

cache介绍

原帖地址&#xff1a; http://www.wowotech.net/memory_management/458.html?fromtimeline 今天探究的主题是cache。我们围绕几个问题展开。为什么需要cache&#xff1f;如何判断一个数据在cache中是否命中&#xff1f;cache的种类有哪些&#xff0c;区别是什么&#xff1f; …

cachecloud:安装部署(一)

下载源码 可以本地调试、打包。 源码下载&#xff1a;https://github.com/sohutv/cachecloud.git 创建数据库 cachecloud持久化基于mysql&#xff0c;缓存使用redis。 新建一个数据库&#xff0c;如cachecloud分别使用cachecloud/cachecloud-web/sql/2.0.sql和update2.0-2…

Cache简介

1. Cache Cache一词来源于法语&#xff0c;其原意是“藏匿处&#xff0c;隐秘的地方”&#xff0c;而自从被应用于计算机科学之后&#xff0c;就已经成为了英语中的一个计算机体系结构专有名词。 Sun Microsystems的前首席科学家Billy Joy&#xff0c;作为BSD …

Redis入门完整教程:CacheCloud是什么?

如果让你去运维大规模的Redis节点&#xff0c;例如数千个 Redis节点、数百台机器、数百个业务支撑&#xff0c;会遇到什么问题吗&#xff1f;很明显就 是缺少一个好的可视化运维平台。本节首先分析如果没有好的运维平台可能 存在的问题&#xff0c;接着介绍Redis开源私有云平台…

CacheCloud详解(一)----------CacheCloud搭建(Redis云平台)

目标&#xff1a; redis作为流行的缓存数据库&#xff0c;被众多企业使用&#xff0c;但是对于中小型企业来说&#xff0c;日益增多的redis服务器&#xff0c;如何管理是个问题。本系列文章就搜狐视频开源的CacheCloud云平台进行深入讲解。通过从安装到源码讲解&#xff0c;让…

分享kubernetes部署:cachecloud部署说明

cachecloud部署 cachecloud是搜狐视频(sohutv)Redis私有云平台 已省略~ 挑选一台服务器部署cachecloud-web 将cachecloud-web打成war包&#xff0c;可以在服务器上打包&#xff0c;也可以在本地打包&#xff0c;这里举一个在服务器上打包的例子。 将源代码下载到/opt下 已省略~…

CacheCloud搭建(Redis云平台)

下载源代码启动Server 1、初始化MySQL数据库2、启动&#xff08;本地&#xff09; 登录系统Redis 机器环境初始化普通用户注册应用申请客户端连接 在中小型互联网公司里面&#xff0c;对于运维使用的监控系统不是很完善。今天介绍一下 CacheCloud&#xff0c;是搜狐视频开源的 …

【Linux】Cachecloud安装部署图文并茂

搭建环境 cachecloudJDKMavenMySQLRedis是是是是是 cachecloud安装 说明&#xff1a;安装cachecloud之前需要在机器上安装maven、jdk、mysql软件的步骤不做说明&#xff0c;测试软件安装路径为:/usr/local。 下载 https://github.com/sohutv/cachecloud 下载CacheCloud-mas…

Redis监控运维平台-CacheCloud

一、CacheCloud 1、出现问题 当Redis达到一定规模&#xff0c;容易出现以下问题&#xff1a; 运维部署成本高&#xff0c;手动部署&#xff0c;容易出现错误。实例碎片化&#xff0c;机器利用率较低&#xff0c;可能出现大量闲置资源。监控&#xff0c;统计&#xff0c;管理…

Redis入门完整教程:CacheCloud快速部署

13.2.1 CacheCloud环境需求 安装部署CacheCloud需要以下环境&#xff1a; JDK7&#xff1a;CacheCloud使用Java语言开发&#xff0c;并使用了JDK7的一些特性。 Maven3&#xff1a;CacheCloud使用Maven3作为开发构建工具。 MySQL5.5&#xff1a;CacheCloud需要Redis的相关元信息…

Redis入门完整教程:CacheCloud运维功能

13.6 运维功能 CacheCloud作为Redis的运维工具&#xff0c;包含了Redis日常运维的常用功能&#xff0c; 本节将对如下功能进行介绍&#xff1a; 1&#xff09;应用运维&#xff1a;Redis节点的上下线、手动故障转移、配置管理、扩容 等。 2&#xff09;接入已存在的Redis&…

一文解决IDEA中文乱码问题

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;JAVA开发者…

idea中中文字体设置

此次设置idea中字体为中文雅黑字体 1.找到安装的idea路径中jdr的lib文件进去 E:\IntelliJ IDEA 2019.2\jbr\lib2.创建文件名及格式为fontconfig.properties的文件 3.复制以下代码进文件 # Versionversion1# Component Font Mappingsallfonts.chinese-ms936Microsoft Yahei a…

IDEA--解决IntelliJ IDEA中文乱码问题

1.首先是编辑器的乱码&#xff0c;这个很好解决&#xff0c;file->settings->appearence里面有个Name设置成支持中文的字 体(这个很重要) 同样还要再settings中的Eidtor->File Encodings里面设置字体编码格式&#xff0c;一般都是UTF-8&#xff0c;GBK什么的也行。 2.…

彻底解决Intellij IDEA中文乱码问题

关于JAVA IDE开发工具&#xff0c;Eclipse系列和Intelli IDEA是大部分公司的主要选择&#xff0c;从开发者的选择角度&#xff0c;Intellij IDEA似乎比Eclipse系列更受欢迎一些。当我们使用Intellij IDEA开发时&#xff0c;我们发现出现中文乱码问题&#xff0c;造成中文乱码的…

彻底解决idea中文乱码问题(不易发现的点,jdk问题)

这里提出一个由于jdk问题导致的中文乱码问题。 1.Setting中的各项都设置为utf-8 2.这里设置成这样&#xff0c;极低概率是这里的问题 3.右下角设置utf-8 4.Help-Edit custom VM options后面加上Dfile.encodingUTF-8 5.idea安装目录的bin文件中两个文件idea.exe.vmoptions 和…

IDEA:IDEA中文翻译插件的安装与使用

IDEA安装中文插件 一、打开设置 二、安装插件 三、插件设置 设置自己喜欢的翻译引擎 勾选翻译文档 四、效果 鼠标光标放上去就可以查看中文文档了 Shift Ctrl O&#xff1a;可以弹出翻译框 选中要翻译的文本&#xff0c;右键选择翻译或者使用快捷键&#xff1a;Shift Ctr…

2020版的idea中文插件安装

2020版的idea中文插件安装 1. 打开idea&#xff0c;进入创建project界面 2.选择中文插件 3.搜索Chinese插件 4.重启IDE 5.重新打开就是中文界面

idea无法识别中文

开始修改idea之前&#xff0c;建议先查看自己代码的编码格式&#xff0c;用Notepad打开之后&#xff0c;点击上方编码&#xff0c;就能看到编码格式。我是因为git的原因&#xff0c;导致拉下来的代码是默认编码&#xff0c;一个文件一个格式。修改git编码的方法自行百度。 在解…

IDEA更改中文字体

初始&#xff1a; 效果&#xff1a; 更改&#xff1a;file-settings&#xff0c;左侧搜索框中直接输入font&#xff0c;然后如下图&#xff0c;将字体改为SimHei&#xff0c;应用保存即可