ceph的 cache tier实现分析
1 基本介绍
1.1 设计思想
数据的存储可划分为active和inactive两大类,active数据是小部分,会频繁访问,使用更高性能的底层存储介质进行存储;inactive的数据是全集,使用廉价的存储介质存储。这种分冷热的思想与CPU的多级缓存、操作系统的cache、各类软件系统的软件缓存是相通的,但ceph通过软件层面的配合,充分利用不同的硬件介质和软件存储模式,为上层用户提供透明统一的访问接口。
目的:在兼顾存储成本前提下,通过配合使用不同的存储介质,并使用不同的软件存储模式,达到更好的数据存取性能。
说明:cache tier是ceph在其抽象的ObjectStore层面实现的冷热分层,上层的RGW/CEPHFS/RBD均可受益,其中RGW本身还可据此实现生命周期功能。
1.2 实现要点
- CRUSH Map:通过指定不同的root,并创建多个相应的crush_rule,用来从软件上定义如何使用底层存储介质
- pool的crush_rule:创建不同存储池,为各自设置对应的crush_rule
- pool的存储策略:通过crush_rule的类型来指定软件层面的存储模式,包括多副本(副本数可配)、EC(K、M可配)
- tier关联:动态配置两个存储池的关联关系和迁移策略,包括none、writeback、forward、readonly、readforward、proxy、readproxy
- Objecter:屏蔽底层实现,为客户端的读写请求提供统一接口
1.3 总体架构
ceph官网提供的tier存储技术的总体架构如下图:
对于设置了cache tier的存储池,客户的读写请求是无感的,通过单独的objecter模块负责实现cache tier和storage tier的联动,并根据管理员配置的各项cache tier的策略,自动实现数据的更新和同步。
1.4 特殊性
- 适用于热点访问场景
添加tier之后,能够提升总体的性能与具体的数据存取场景高度依赖,因为需要将热存储池的数据迁移到冷存储池,因此对访问小部分热点数据的场景比较适合,绝大多数请求只会访问一小部分数据。 - 通用场景性能较差且benchmark困难
通用的非热点访问的场景下,都不是cache友好的,都会有性能损失。另外通用的benckmark方法无法发挥tier的优势,不会只访问一小部分的数据,因此性能数据也表现不佳。 - 对象遍历操作不稳定
由于tier层的小部分热数据的存在,如果用户直接调用librados库的对象遍历API,可能会得到不一致的结果,但是直接使用RGW/RBD/CephFS没有影响。 - 复杂性提升
使用tier后,会为Rados层带来额外的复杂性,可能会增加出现bug的风险。
2 功能实现分析
cache tier是在ceph抽象的ObjectStore层面,处于底层的统一的KV存储层,其具体实现依附于ceph的存储池,cache tier作为存储池的属性,依据用户配置,存储池在完成具体的读写操作时提供相应的cache tier功能。ceph将存储池进行分片(PG),在具体实现功能时又是基于PG为最基本的单位来实现。
2.1 参数设计
cache tier的参数是存储池的属性,底层数据结构定义为pg_pool_t:
struct pg_pool_t {...typedef enum {CACHEMODE_NONE = 0, /// no cachingCACHEMODE_WRITEBACK = 1, /// write to cache, flush laterCACHEMODE_FORWARD = 2, /// forward if not in cacheCACHEMODE_READONLY = 3, /// handle reads, forward writes [not strongly consiCACHEMODE_READFORWARD = 4, /// forward reads, write to cache flush laterCACHEMODE_READPROXY = 5, /// proxy reads, write to cache flush laterCACHEMODE_PROXY = 6, /// proxy if not in cache} cache_mode_t;...set uint64_t tiers; /// pools that are tiers of usint64_t tier_of; /// pool for which we are a tier(-1为没有tier)// Note that write wins for read+write opsint64_t read_tier; /// pool/tier for objecter to direct reads(-1为没有tier)int64_t write_tier; /// pool/tier for objecter to direct write(-1为没有tier)cache_mode_t cache_mode; /// cache pool modeuint64_t target_max_bytes; /// tiering: target max pool sizeuint64_t target_max_objects; /// tiering: target max pool sizeuint32_t cache_target_dirty_ratio_micro; /// cache: fraction of target to leave dirtyuint32_t cache_target_dirty_high_ratio_micro; /// cache: fraction of target to flush with high speeduint32_t cache_target_full_ratio_micro; /// cache: fraction of target to fill before we evict in earnestuint32_t cache_min_flush_age; /// minimum age (seconds) before we can flushuint32_t cache_min_evict_age; /// minimum age (seconds) before we can evictHitSet::Params hit_set_params; /// The HitSet params to use on this pooluint32_t hit_set_period; /// periodicity of HitSet segments (seconds)uint32_t hit_set_count; /// number of periods to retainbool use_gmt_hitset; /// use gmt to name the hitset archive objectuint32_t min_read_recency_for_promote; /// minimum number of HitSet to check before promote on readuint32_t min_write_recency_for_promote; /// minimum number of HitSet to check before promote on writeuint32_t hit_set_grade_decay_rate; /// current hit_set has highest priority on objects///temperature count,the follow hit_set's priority deca///by this params than pre hit_setuint32_t hit_set_search_last_n; /// accumulate atmost N hit_sets for temperaturebool is_tier() const { return tier_of >= 0; }bool has_tiers() const { return !tiers.empty(); }void clear_tier() {tier_of = -1;clear_read_tier();clear_write_tier();clear_tier_tunables();}bool has_read_tier() const { return read_tier >= 0; }void clear_read_tier() { read_tier = -1; }bool has_write_tier() const { return write_tier >= 0; }void clear_write_tier() { write_tier = -1; }void clear_tier_tunables() {if (cache_mode != CACHEMODE_NONE)flags |= FLAG_INCOMPLETE_CLONES;cache_mode = CACHEMODE_NONE;target_max_bytes = 0;target_max_objects = 0;cache_target_dirty_ratio_micro = 0;cache_target_dirty_high_ratio_micro = 0;cache_target_full_ratio_micro = 0;hit_set_params = HitSet::Params();hit_set_period = 0;hit_set_count = 0;hit_set_grade_decay_rate = 0;hit_set_search_last_n = 0;grade_table.resize(0);}... };
这些参数详细记录了cache tier的具体实现细节,总结如下:
- tier的存储池:自身的tier pool ID(
tier_of
字段),以及以自身作为tier的其他pool的ID集合(tiers
字段) - cache mode:定义了六种cache模式,默认为
CACHEMODE_NONE
,按照用户配置执行相应的操作,为cache tier实现的核心部分 - cache tunable参数:在执行flush和evict操作时,用户可为cache这两种行为设置的多种触发参数,以便和具体的应用场景匹配
2.2 实现主体
基于为cache tier定义的各项参数,在具体实现的时候,依附于PG为主体实现具体的功能。pg_pool_t
作为底层存储的定义,属于PGPool
的info
字段,用来记录一个存储池的详细属性。PG
类定义了在存储池上完成最基本数据读写的实体,包含了一个它所属的存储池的pool
字段。
struct PGPool {CephContext* cct;epoch_t cached_epoch;int64_t id;string name;uint64_t auid;pg_pool_t info;...};class PG : public DoutPrefixProvider {...protected:PGPool pool;...};
PG
类定义了针对全部数据请求的所有功能,主要包括shard分片、recovery和backfill功能、状态收集和统计、blocked请求的等待处理、scrub处理等功能,对于具体的数据读写请求的处理,定义了必须进一步实现的全部抽象接口,其中所有请求的入口接口如下:
virtual void do_request(OpRequestRef& op, ThreadPool::TPHandle &handle) = 0;
目前的PG针对数据读写请求的全部实现都由PrimaryLogPG
类负责,这里主要关注cache tier相关的具体实现。
2.3 Objecter
Objecter本身实现上是一个Dispatcher,对外可作为OSD的一个client,负责向tier的storage层的存储池读写数据;对内作为本存储池的OSD的一个成员,负责在
各个cache mode的具体实现中,生成具体的Operation OP并提交。
2.3.1 注册与启动
OSD的main函数创建了7个messenger用来处理各类网络rpc消息,其中包括为Objecter创建对独立messenger。OSD类为一个Dispatcher,负责实现网络处理的各个接口,其包含一个OSDService对象,负责完成除网络交互之外的具体实现。Objecter为OSDService的一个成员,由OSDService在构造时动态创建Objecter对象,并在构造函数调用Objecter的init函数初始化Objecter的内部数据结构。
在对象创建完成之后,main函数启动这7个messenger,此时还不能无法处理网络请求,随后调用OSD的init函数,其负责将其OSDService成员的Objecter成员注册到相应messenger的dispatcher队列:
objecter_messenger->add_dispatcher_head(service.objecter);
同时,也会将OSD自身添加到其他messenger的Dispatcher队列,并完成一系列的如初始化MON和MGR的client对象、启动OSD的多个工作线程池、启动tick等初始化操作,其中包括连接MON进行鉴权,在鉴权通过之后调用OSDService成员的final_init函数,负责启动Objecter:
void OSDService::final_init() {objecter->start(osdmap.get()); }
2.3.2 Tick与OSDSession
Objecter的start函数用来启动objecter服务,其工作内容为:启动tick并拷贝一份osdmap。tick的间隔时间由配置文件制定:objecter_tick_interval
,默认为5秒。Objecter会通过拷贝的osdmap信息,主动向其他目标OSD发起连接,并以内嵌类OSDSession表示,本身维护了一个osd ID到OSDSession的映射结构
map<int,OSDSession*>
。OSDSession的成员包括目标OSD的ID、底层网络连接等基础信息之外,主要包括到目标OSD的各类OP操作的队列:
struct OSDSession {...map ops;map linger_ops;map command_ops;...int osd;ConnectionRef con;... };
每一次tick的任务就是遍历Objecter维护的OSDSession映射结构,循环检查它的OP队列,包括普通的OP队列、linger OP队列、command OP队列,依据如下标准执行是否发送依次MPing消息:
- 普通OP:配置的
objecter_timeout
,默认10秒,依据OP的开始时间是否超过这个超时时间来决定是否发送 - linger OP(执行比较缓慢的操作):只要存在于队列中就会发送
- command OP:只要存在于队列中就会发送
2.3.3 ObjectOperation
Objecter负责为cache tier的具体实现中需要与其他存储池的OSD进行数据交互时提供支持,其本质就是执行一系列ObjectStore抽象的操作,并为cache tier封装一些特定的操作,这部分统一由ObjectOperation类负责完成,实现非常直接:
struct ObjectOperation {vector ops;int flags;int priority;vector out_bl;vector out_handler;vector out_rval; };
一共就上述6个成员,最重要的就是OSDOp构成的数组,对于一个具体的操作,可能对应多个OSDOp操作,或者可以将多个操作的OP合并后发送,另外包含一个标志位和优先级;同时定义了三个同样与OSDOp对应的输出信息的数组,包括输出内容、输出handler、返回值。
在此基础上,使用一个add_op
函数添加一个新的OSDOp成员到内部的ops
数组中,并返回引用,再定义了大量的针对Object的具体操作,用来支持cache tier的具体实现,主要分为如下几类:
- ObjectStore抽象的对象操作:如
stat
、read
、write
、append
、getxattr
、omap_get_keys
、omap_get_values
等 - PG和Scrub操作:包括
pg_ls
、scrub_ls
,用来从其他OSD获取PG、Scrub信息 - 针对cache tier特殊操作:包括
is_dirty
、undirty
、hit_set_ls/get
、copy_get
、copy_from
、cache_flush/try_flush
、
cache_evict
、cache_pin
、cache_unpin
针对cache tier的操作为实现cache tier的不同模式提供了便利,其中flush和evict直接影响cache tier的行为,其具体处理方式如下:
- flush操作:若给定的cache tier中的对象是dirty的,就将其写入到backing tier;如果对象是clean,则不做任何操作。当该操作与update并发执行时,
cache_flush
将会阻塞update操作,cache_try_flush
则会立即返回一个EAGAIN错误而不会阻塞。 - evict操作:如果给定的cache tier中的对象是clean则将其从cache tier中删除,否则返回EBUSY。
另外提供的cache_pin
、cache_unpin
还可以将某个对象在cache tier中进行锁定和解锁。
3.3.4 具体实现
Objecter要主动向其他OSD发起各类OP操作,封装了具体的方法,包括write
、read
、pg_read
、getxattr
等,每个方法使用的具体OP,通过上述ObjectOperation类封装的工厂方法来构造,创建好之后调用统一的op_submit
函数进行提交,最终从维护的OSDSession映射结构中获取底层网络连接,调用其send_message
方法将OP发送出去。对于read
方法,其具体实现如下:
Op *prepare_read_op(const object_t& oid, const object_locator_t& oloc,ObjectOperation& op,snapid_t snapid, bufferlist *pbl, int flags,Context *onack, version_t *objver = NULL,int *data_offset = NULL,uint64_t features = 0,ZTracer::Trace *parent_trace = nullptr) {Op *o = new Op(oid, oloc, op.ops, flags | global_op_flags |CEPH_OSD_FLAG_READ, onack, objver, data_offset, parent_trace);o->priority = op.priority;o->snapid = snapid;o->outbl = pbl;if (!o->outbl && op.size() == 1 && op.out_bl[0]->length())o->outbl = op.out_bl[0];o->out_bl.swap(op.out_bl);o->out_handler.swap(op.out_handler);o->out_rval.swap(op.out_rval);return o;}ceph_tid_t read(const object_t& oid, const object_locator_t& oloc,ObjectOperation& op,snapid_t snapid, bufferlist *pbl, int flags,Context *onack, version_t *objver = NULL,int *data_offset = NULL,uint64_t features = 0) {Op *o = prepare_read_op(oid, oloc, op, snapid, pbl, flags, onack, objver, data_offset);if (features)o->features = features;ceph_tid_t tid;op_submit(o, &tid);return tid;}void Objecter::op_submit(Op *op, ceph_tid_t *ptid, int *ctx_budget) {shunique_lock rl(rwlock, ceph::acquire_shared);..._op_submit(op, rl, ptid);}void Objecter::_op_submit(Op *op, shunique_lock& sul, ceph_tid_t *ptid) {...MOSDOp * m = _prepare_osd_op(op);..._send_op(op, m);}void Objecter::_send_op(Op *op, MOSDOp *m) {...op->session->con->send_message(m);...}
Objecter作为可与其他OSD进行数据读写交互的模块,除了发送OP之外,还需接收响应,因此实现了Dispatcher的全部接口,重新定义ms_dispatch
函数来处理其他OSD返回给自己的信息。通过接收的消息类型进行分发,只支持如下几种消息:
CEPH_MSG_OSD_OPREPLY
:普通的OSD读写等OP操作的响应,可进行fast dispatch,调用handle_osd_op_reply
处理CEPH_MSG_OSD_BACKOFF
:执行BACKOFF的消息,调用handle_osd_backoff
处理CEPH_MSG_WATCH_NOTIFY
:可进行fast dispatch,调用handle_watch_notify
处理MSG_COMMAND_REPLY
:仅在发送消息的源也是OSD时才会处理,调用handle_command_reply
处理,否则不处理MSG_GETPOOLSTATSREPLY
:获取存储池统计信息的返回,调用handle_get_pool_stats_reply
处理CEPH_MSG_POOLOP_REPLY
:执行存储池操作的返回,调用handle_pool_op_reply
处理CEPH_MSG_STATFS_REPLY
:获取文件系统信息的返回,调用handle_fs_stats_reply
处理CEPH_MSG_OSD_MAP
:交互OSDMAP信息的处理,调用handle_osd_map
处理
这里我们主要关注第一类消息,就是针对OSD普通的读写等OP操作的响应对处理,具体流程如下:
- 从维护的OSDSession映射结构中获取该消息对应的OSDSession
- 判断是否需要重试,如果需要就从OSDSession中删除这个OP,并重新调用
_op_submit
提交该请求 - 获取消息的结果,判断是否需要进行redirect,如果需要就从OSDSession删除该OP,并添加新的redirect目的地后调用
_op_submit
重新提交 - 获取消息的输出数据、返回值,并据此调用这个OP创建时注册的处理完成时的回调handler
2.4 IO请求
由于cache tier依附于PG实现,因此cache tier的IO请求路径就是对OSD的任意一次IO请求路径,在这个路径上会判断PG所在的存储池是否是其他存储池的cache tier或是否有其他存储池为自身的cache tier,如果均没有则执行正常的读写请求;否则就依据具体的策略并基于Objecter提供的方法来完成对cache tier的处理。
2.5 各cache mode处理
对于配置了cache tier存储池,按照3.4节点IO请求路径,具体在maybe_handle_cache_detail
函数中,依据不同的cache模式进行switch-case分别进行处理, 在maybe_handle_cache_detail
函数中具体分为如下六种模式依次处理,详见下述分析。
2.5.1 FORWARD
FORWARD模式表示所有到达cache tier存储池的请求都不会处理,直接将它的后端存储池的ID回复给请求方,并返回-ENOENT
的错误号,具体实现比较简单。
该模式的用途是在删除WRITEBACK
模式的cache tier时,需将其cache mode先设置为FORWARD,并主动调用cache tier的flush和evict操作,确保cache tier存储池的对象全部evict和flush到后端存储池,保证这个过程中不会有新的数据写入。
2.5.2 READONLY
READONLY模式是指对于所有的写请求,都直接调用do_cache_redirect
函数,与FORWARD模式同样处理;对于所有的读请求,会先判断是否存在于cache tier存储池中,如果存在就直接返回,否则会先调用Objecter从后端存储池读取一份数据,并创建一个ObjectContext对象保存,将读取数据返回给客户。
start_copy
会创建一个CopyOp对象,该对象保存了请求的参数、返回值、大小、数据缓冲区、omap和xattr缓冲区等,最终调用OSDService的Objecter成员的read方法向目标存储池的OSD发起读取请求。之后调用wait_for_blocked_object
将该OP加入到内部维护的一个称为waiting_for_blocked_object
的map结构中,key为tid,value为OP。start_copy
在发起请求之前会设置好成功时的回调函数,这个回调函数会调用kick_object_context_blocked
用来从维护的map结构中查询到之前的OP,调用requeue_ops
将这个OP加入到OSD的请求队列中重新执行,并从map结构中删除。注意:requeue_ops
会使用enqueue_front
插入到OSD的ShardedOpWQ的开头。
2.5.3 PROXY
PROXY模式下,针对读写请求都会执行proxy,也就是作为一个代理向后端存储池发起请求并返回给客户端,除非强制要求先进行promote操作。
对于写请求调用do_proxy_write
,则会直接调用会调用OSDService的Objecter成员的mutate方法,将写请求直接写入到后端的存储池中,并记录到内部维护的proxywrite_ops
、in_progress_proxy_ops
两个map结构,另外设置了成功时的回调函数,在写入完成之后从维护的map结构中删除,并返回给客户端CEPH_OSD_FLAG_ACK | CEPH_OSD_FLAG_ONDISK
的响应。对于读请求调用do_proxy_read
,与写请求处理类似,直接作为代理端发送请求到后端存储池并等待结果完成,同样也会分别记录到两个map结构并在完成时删除。
这种模式下,读写请求的对象的数据都不会在cache tier存储池中保存,自身扮演为一个代理(proxy)的角色,这是与FORWARD模式的区别。
2.5.4 WRITEBACK
WRITEBACK模式是最复杂也是最有实用价值的模式,其具体实现会按照请求类型、cache状态综合判断,并复用前三种模式下的一些处理细节进行综合处理。处于这种模式下的cache tier存储池,其处理流程如下:
- 判断cache tier存储池的状态是否已满,如果已满,则对于读请求直接调用
do_proxy_read
,对于写请求直接将OP加入到waiting_for_cache_not_full
队列,并在下一次有新的请求达到时重新放入OP队列处理。 - 在cache tier未满的情况下,先判断是否必须进行promote,如果需要就调用
promote_object
,先阻塞当前请求,从后端存储池读取一份数据到cache tier存储池,并在完成之后再将当前请求加入OP队列 - 在cache tier未满且不会强制promote时,这也是最常见的情况下:对于写入请求,会先阻塞,调用
promote_object
从后端读取一份数据并保存,完成之后将当前请求重新加入OP队列,这样下一次执行这个读请求时,会判断已经存在于cache tier中,就直接写入在cache tier存储池中;对于读请求,则会首先调用do_proxy_read
从后端存储池读取数据但不保存在cache tier存储池中,之后再判断本地读请求是否需要跳过promote,这是在创建该OP时设置的一个flag,通过op->need_skip_promote
来判断,在所有的OP请求中有两种场景会设置不需promote,否则都会执行promote从后端存储池读取一份数据保存在cache tier存储池
其中会设置skip promote标志的两种情况如下:
CEPH_OSD_OP_DELETE
请求会设置skip promote- read、sync_read、sparse_read、checksum、writefull请求若设置了
CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
或CEPH_OSD_OP_FLAG_FADVISE_DONTNEED
标志位就会设置skip promote
2.5.5 READFORWARD
READFORWARD是FORWARD与WRITEBACK模式的综合。对于所有读请求执行与FORWARD一样的处理,调用do_cache_redirect
,直接返回后端存储池给用户,并返回-ENOENT
的错误号;对于写请求则与WRITEBACK模式相同处理,先调用promote_object
从后端读取一份数据保存并加入到OP队列重新执行,把数据写入到cache tier存储池中。
2.5.6 READPROXY
READPROXY是PROXY与WRITEBACK模式的综合。对于所有读请求执行与PROXY模式一样的处理,调用do_proxy_read
,仅从后端存储池读取数据并返回给用户,不存储读取到的对象;对于写请求则与WRITEBACK模式相同处理,先调用promote_object
从后端读取一份数据并保存并加入到OP队列重新执行,把数据写入到cache tier存储池中。
3 总结
cache tier是ceph在底层抽象的统一软件定义存储ObjectStore的基础上,实现的一种缓存存储层,具体依托于ceph的CRUSH MAP和CRUSH RULE,针对不同的存储池配置相应的规则,从而映射到具有存储性能差异的硬件上,从而提升总体性能并降低存储成本。cache tier的实现具体是在底层的存储池层面,因此对于所有基于ObjectStore抽象实现的上层应用都可受惠,包括RGW、CEPHFS、RBD。cache tier本质上可以看做CPU与内存间的高速缓存的一个外延,当数据从内存要写入磁盘时,通过使用性能较高的磁盘作为cache tier层,来弥补内存与普通磁盘间的性能gap,该思想虽然也有如文件系统的page cache、磁盘本身的缓存等实现,但ceph的cache tier相当于是从软件定义存储的角度来对这种思想进行补充。
3.1 实用性
根据上述分析,cache tier虽然提供了六种模式,但FORWARD本身是一种为WRITEBACK切换提供的过渡模式,并无实用价值。PROXY模式则完全充当一个代理来转发请求,同样并无太大的实用价值。另外四种模式,最重要的就是WRITEBACK模式,这是cache tier实现的最具实用性的模式,在这种模式下配置相应的cache tier参数控制其行为。另外三种READONLY、READPROXY、READFORARD三种是针对读请求的比例不同而提供的针对性模式。下面总结了他们的实用场景:
- WRITEBACK:写请求较多或读写比较均匀的场景,读写的数据都会在cache tier存储池中保存,通过配置flush、evict参数执行向后端存储池的更新和剔除
- READONLY:适合以读为主的场景,对于极少量读写请求直接让客户端去写入到后端存储池,而读请求则会将对象缓存起来,提升总体读请求的性能
- READPROXY与READFORWARD:适合以写为主的场景,对于少量的读请求,可以选择使用proxy方式进行处理,也可以选择让客户端直接写入到后端存储池
3.2 局限性
cache tier的实现本身依附于存储池的分片,也就是PG,而PG本身要实现包括副本同步、快照、scrub、recovery等一系列功能,cache tier的实现与他们都混合在一起,大大增加了整体代码实现的复杂性,增加了在极端场景出现bug的可能性,从而对系统稳定性会有一定的影响。因此对于cache tier功能本身需要进行严格的测试,同时对于开启了cache tier的存储池,也需要谨慎的配置各项参数,严密的进行监控。
cache tier提供的多种模式虽然针对不同场景而设置,但并不全面,还有进一步开发的空间。首先可借鉴CPU多级缓存的思想,ceph可支持超过两级的cache tier的配置,但是由于目前的代码实现将其混合在PG中,这种扩展难度很大改动也非常大。其次,对于写请求较少的场景,仅提供了READONLY模式,也可提供类似CPU缓存的write through的模式,同时也还有write allocate等处理方式,均可借鉴,但这些扩展都受目前的实现方式的制约。
ceph的 cache tier实现分析相关推荐
- Ceph Cache Tier中缓存读写流程源码分析
存储系统:ceph-14.2.22 PrimaryLogPG::do_request [ 文件路径 ] ceph/src/osd/PrimaryLogPG.cc OSD在收到客户端发送的请求时,会调用 ...
- Ceph Cache Tier
CacheTier是ceph服务端缓存的一种方案,简单来说就是加一层Cache层,客户端直接跟Cache层打交道,提高访问速度,后端有一个存储层,实际存储大批量的数据. 分层存储的原理,就是存储的数据 ...
- Ceph性能测试(RBD、CephFS、NFS、Cache Tier)
本文是以下两篇文章的后续: 探索fio参数如何选择以及全方位对比HDD和SSD性能:部署Ceph前测试磁盘性能,同时基于fio测试参数的变化深入了解fio原理和磁盘IO特点. CentOS8使用cep ...
- cache tier 分级缓存
一图描述 cache tier: Ceph 缓存层将冷热数据分离,以快速存储设备作为缓存层,低速廉价存储设备作为存储层 提升 IO 性能 使用两个 pool,作为存储层和缓存层,缓存层覆盖在存储层上, ...
- flash cache tier下放flush实验
创建3台vm 分别是ceph01.ceph02.ceph03 a)后台手动部署ceph b)后台部署完毕后创建一个HDD池 rados mkpool HDD 然后定制crushmap 1.ceph o ...
- cache相关命中率的运算_计算机高速缓冲存储器(Cache)命中率的分析
第 21 卷 第 3 期 河南教育学院学报( 自然科学版) Vol. 21 No. 3 2012 年 9 月 Journal of Henan Institute of Education ( Nat ...
- Ceph cache tier 中 flush 和 evict 机制源码分析
存储系统:ceph-14.2.22 操作系统:ubuntu-server-16.04.07 OSDService::agent_entry [ 文件路径 ] ceph/src/osd/OSD.cc O ...
- cephfs:1 clients failing to respond to cache pressure原因分析
问题现象 ceph -s中经常出现报警: 1 clients failing to respond to cache pressure 其大致原因是cephfs的mds让客户端释放部分metadata ...
- Oracle等待事件(一)—— latch cache buffers chains 分析与优化思路
一. 什么是CBC等待 首先我们需要知道CBC等待发生在哪里,为什么会发生,才能理解应该如何定位,如何处理. 首先,CBC latch是用于保护buffer cache的,因此CBC等待一定发生在bu ...
- 【Ceph 】Async 网络通信源代码分析--研读
目录 前言 基本类介绍 连接相关的流程介绍 Server端监听和接受连接的过程 Client端主动连接的过程 消息的接收和发送 消息的接收 消息的发送 Ceph Async 模型 IO 多路复用多线程 ...
最新文章
- 我的商汤实习年末总结
- PHP+MySQL手工注入问题及修复
- 技术工坊|解密区块链DApp的代码逻辑,从请求到数据存储都要经历什么?(上海)...
- 数据中心的供配电与空调
- 若依微服务版在Windows上通过jar包运行业务模块时提示:Failed to determine s suitable driver class
- 三十一、R语言基本语法(上篇)
- PHP的static
- PHP|异常的使用,异常子类化的最佳实践
- 使用Synergy多台电脑共享键盘鼠标和剪贴板
- 【软工3】迭代二 心得体会及感想
- 移动VS.NET2010帮助文档
- 摄像头(WebCam)在Linux操作系统中的驱动方法
- 【终于等到你】微信转发语音的方法 - 语音信息转发
- 【c++思维导图与代码示例】02 函数
- t分布 u分布 卡方分布_卡方分布、t分布和f分布各有哪些重要性质?
- 电磁阀、电磁铁的工作原理说明
- 超详细! 利用Synopsys VCS对Verilog代码加密的四种方法
- 面试如何解释上份工作时间短
- A Creed to Live By
- java.sql.SQLException: Incorrect Integer value:‘****‘ for column ‘id‘ at row 1 解决方案
热门文章
- MAC上报错“The JAVA_HOME environment variable is not defined correctly This environment
- 图像特征与描述子(直方图, 聚类, 边缘检测, 兴趣点/关键点, Harris角点, 斑点(Blob), SIFI, 纹理特征)...
- OMNETPP: tictoc
- 2 数据可视化大屏 - 布局
- 【网络工程】什么是7类网线7类线与超6类线的区别以及它的应用场景
- 解决ROS编译时opml库找不到
- c语言 实现参数值双向传递,基于C语言函数参数传递规律的探讨
- 计算机学院运动会加油,学校运会加油稿
- proc sys文件系统对比
- 论文翻译:2021_Performance optimizations on deep noise suppression models