注意
本文档适用于 Ceph 的开发版本。
MDS 缓存配置
元数据服务器在所有 MDS 和 CephFS 客户端之间协调一个分布式缓存。缓存用于提高元数据访问延迟,并允许客户端安全地(一致地)修改元数据状态(例如,通过 chmod)。MDS 发放能力(capabilities)和目录条目租约(directory entry leases)来指示客户端可以缓存什么状态以及可以执行什么操作(例如,写入文件)。
MDS 和客户端都试图强制执行缓存大小。下面描述了指定 MDS 缓存大小的机制。请注意,MDS 缓存大小不是硬限制。MDS 始终允许客户端查找加载到缓存中的新元数据。这是一个基本策略,因为它可以避免客户端请求中的死锁(某些请求可能依赖于持有的能力,直到能力被释放)。
当 MDS 缓存过大时,MDS 将回收客户端状态,以便缓存项变为未固定状态并有资格被丢弃。MDS 只能在没有客户端引用要丢弃的元数据时丢弃缓存状态。下面还描述了如何根据您的工作负载需求配置 MDS 回收设置。如果 MDS 回收的内部限制无法跟上客户端工作负载,则这是必需的。
MDS 缓存大小
您可以通过字节计数来限制元数据服务器 (MDS) 缓存的大小。这是通过 mds_cache_memory_limit 配置完成的
- mds_cache_memory_limit
这设置了 MDS 缓存的目标最大内存使用量,是限制 MDS 内存使用的主要可调参数。MDS 将尝试保持在此限制的保留范围内(默认为 95%;1 - mds_cache_reservation),方法是修剪缓存中未使用的元数据并回收客户端缓存中的缓存项。由于客户端回收缓慢,MDS 有可能超出此限制。mds_health_cache_threshold (150%) 设置了一个缓存满阈值,当 MDS 达到该阈值时会发出集群健康警告。
- 类型:
大小- 默认值:
4Gi
此外,您可以使用 mds_cache_reservation 参数指定 MDS 操作的缓存保留
- mds_cache_reservation
配置的缓存大小的保留百分比。一旦 MDS 开始使用其保留空间,它将回收客户端状态,直到其缓存大小缩小以恢复保留空间。换句话说,(1 - 此值) 是缓存饱满的高水位线,超过该水位线将回收客户端 cap。
- 类型:
float- 默认值:
0.05
缓存保留被限制为内存的百分比,默认设置为 5%。此参数的目的是让 MDS 为其缓存维护额外的内存储备,供新的元数据操作使用。因此,MDS 通常应在其内存限制以下运行,因为它会从客户端回收旧状态,以便丢弃缓存中未使用的元数据。
如果 MDS 无法将其缓存保持在目标大小以下,MDS 将向 Monitors 发送健康警报,指示缓存过大。这由 mds_health_cache_threshold 配置控制,默认情况下为最大缓存大小的 150%
- mds_health_cache_threshold
生成健康警告的缓存大小阈值
- 类型:
float- 默认值:
1.5
由于缓存限制不是硬限制,CephFS 客户端、MDS 中潜在的错误或行为不当的应用程序可能导致 MDS 超出其缓存大小。健康警告旨在帮助操作员检测这种情况并进行必要的调整或调查有错误的客户端。
MDS 缓存修剪
MDS 中有两个配置用于限制缓存修剪的速度
- mds_cache_trim_threshold
可以修剪的目录条目数量阈值
- 类型:
大小- 默认值:
256Ki
- mds_cache_trim_decay_rate
修剪 MDS 缓存限制的衰减率
- 类型:
float- 默认值:
1.0
限制的目的是防止 MDS 花费太多时间修剪其缓存。这可能会限制它处理客户端请求或执行其他维护的能力。
修剪配置控制一个内部衰减计数器(decay counter)。每当元数据从缓存中修剪时,计数器就会递增。阈值设置计数器的最大大小,而衰减率指示计数器的指数半衰期。如果 MDS 不断从其缓存中删除项目,它将达到 -ln(0.5)/rate*threshold 个项目/秒的稳定状态。
注意
增加配置设置 mds_cache_trim_decay_rate 的值会导致 MDS 花费更少的时间修剪缓存。要增加缓存修剪率,请设置较低的值。
默认值是保守的,对于具有大缓存大小的生产 MDS 可能需要更改。
MDS 回收
MDS 限制其对客户端状态(能力/租约)的回收,以防止为自己处理来自客户端的释放消息而创建过多工作。这通过以下核心配置选项控制
- mds_recall_max_caps
在单次回收中从客户端会话回收的最大 cap 数。请注意,这是一个整数,尽管默认值可能显示 B 后缀。
- 类型:
大小- 默认值:
30000B
- mds_recall_max_decay_threshold
会话上回收 cap 限制的衰减阈值
- 类型:
大小- 默认值:
128Ki
- mds_recall_max_decay_rate
会话上回收 cap 限制的衰减率
- 类型:
float- 默认值:
1.5
会话衰减计数器控制单个会话的回收率。计数器的行为与上面的缓存修剪相同。回收的每个能力都会使计数器递增。
还有一个全局衰减计数器,用于限制所有会话回收
- mds_recall_global_max_decay_threshold
全局回收 cap 限制的衰减阈值
- 类型:
大小- 默认值:
128Ki
其衰减率与 mds_recall_max_decay_rate 相同。任何会话的任何回收能力也会使此计数器递增。
如果客户端释放状态缓慢,将报告警告“failing to respond to cache pressure”(未响应缓存压力)或 MDS_HEALTH_CLIENT_RECALL。每个会话的释放率由另一个衰减计数器监控,该计数器由以下配置配置
- mds_recall_warning_threshold
慢速会话 cap 回收警告的衰减阈值
- 类型:
大小- 默认值:
256Ki
- mds_recall_warning_decay_rate
慢速会话 cap 回收警告的衰减率
- 类型:
float- 默认值:
60.0
每次释放能力时,计数器都会递增。如果客户端释放能力不够快并且存在缓存压力,计数器将指示客户端释放状态是否缓慢。
某些工作负载和客户端行为可能需要更快地回收客户端状态才能跟上能力获取。建议根据需要增加上述计数器以解决集群健康状态中的任何慢速回收警告。
MDS Cap 获取限制
在大型目录层次结构上执行简单的“find”命令将导致客户端接收 cap 的速度明显快于其释放速度。MDS 将尝试让客户端将其 cap 减少到 mds_max_caps_per_client 限制以下,但回收限制会阻止它赶上获取的速度。因此,readdir 通过以下配置被限制以控制 cap 获取
readdir cap 获取衰减计数器的阈值和衰减率
- mds_session_cap_acquisition_throttle
cap 获取衰减计数器限制的阈值
- 类型:
uint- 默认值:
100000
- mds_session_cap_acquisition_decay_rate
通过 readdir 获取的 cap 的会话 cap 获取计数器的半衰期。这用于限制来自客户端的 readdir 请求。
- 类型:
float- 默认值:
30.0
cap 获取衰减计数器控制通过 readdir 获取 cap 的速率。衰减计数器的行为与缓存修剪或 cap 回收相同。每个 readdir 调用都会使计数器增加结果中的文件数。
- mds_session_max_caps_throttle_ratio
客户端必须超过 mds_max_caps_per_client 的比例,然后 readdir 才能被 cap 获取限制限制
- 类型:
float- 默认值:
1.1
- mds_cap_acquisition_throttle_retry_request_timeout
由于 cap 获取限制而重试客户端请求的超时时间(以秒为单位)
- 类型:
float- 默认值:
0.5
如果客户端每会话获取的 cap 数大于 mds_session_max_caps_throttle_ratio 并且 cap 获取衰减计数器大于 mds_session_cap_acquisition_throttle,则 readdir 被限制。readdir 请求将在 mds_cap_acquisition_throttle_retry_request_timeout 秒后重试。
会话活跃度
MDS 还跟踪会话是否处于静止状态。如果客户端会话没有使用其能力或处于安静状态,MDS 将开始从会话回收状态,即使它没有缓存压力。这有助于 MDS 在集群工作负载很热且缓存压力迫使 MDS 回收状态时避免未来的工作。期望是,不使用其能力的客户端不太可能在不久的将来使用这些能力。
确定给定会话是否静止由以下配置变量控制
- mds_session_cache_liveness_magnitude
这是内部活跃度衰减计数器与会话持有的能力数量的量级差异(以 2 为底)。当发生这种差异时,MDS 将会话视为静止并开始回收能力。
- 类型:
大小- 默认值:
10B- 另请参阅:
- mds_session_cache_liveness_decay_rate
这决定了会话需要静止多长时间才能让 MDS 开始抢先回收能力。默认的 5 分钟将导致衰减计数器在 1 小时后减半 10 次,即 1/1024。选择默认量级 10 (1^10 或 1024),以便 MDS 在 1 小时后将以前繁忙的会话(大约)视为静止。
- 类型:
float- 默认值:
5 minutes- 另请参阅:
配置 mds_session_cache_liveness_decay_rate 指示跟踪客户端使用能力情况的衰减计数器的半衰期。每当客户端操作或获取能力时,MDS 都会增加计数器。这是一种粗略但有效的方法来监控客户端缓存的利用率。
mds_session_cache_liveness_magnitude 是活跃度衰减计数器与会话未决能力数量的以 2 为底的量级差异。因此,如果客户端有 1*2^20 (1M) 个未决能力并且仅使用少于 1*2^(20-mds_session_cache_liveness_magnitude) (使用默认值时为 1K),MDS 会将客户端视为静止并开始回收。
能力限制
MDS 还尝试阻止单个客户端获取过多能力。这有助于防止在某些情况下恢复需要很长时间。通常不需要客户端拥有如此大的缓存。限制通过以下方式配置
- mds_max_caps_per_client
客户端可能持有的最大能力数
- 类型:
uint- 默认值:
1Mi
不建议将此值设置为高于 5M,但这可能对某些工作负载有所帮助。
处理“客户端未响应缓存压力”消息
每秒(或由 mds_cache_trim_interval 配置参数设置的间隔),MDS 运行“缓存修剪”过程。此过程的步骤之一是“回收客户端状态”。在此步骤中,MDS 检查每个客户端(会话)以确定是否需要回收 cap。如果以下任一情况属实,则 MDS 需要回收 cap
缓存已满(已超出
mds_cache_memory_limit),需要释放一些 inode客户端超过
mds_max_caps_per_client(默认为 1M)客户端不活跃
要确定客户端(会话)是否不活跃,会检查会话的 cache_liveness 参数并将其与值进行比较
(num_caps >> mds_session_cache_liveness_magnitude)
其中 mds_session_cache_liveness_magnitude 是一个配置参数(默认为 10)。如果 cache_liveness 小于此计算值,则该会话被视为不活跃,并且 MDS 发送所有缓存 cap 的“回收 cap”请求(实际回收值为 num_caps - mds_min_caps_per_client(100))。
在某些情况下,许多“回收 cap”请求可以发送得如此之快,以至于生成健康警告:“clients failing to respond to cache pressure”(客户端未响应缓存压力)。如果客户端释放 cap 不够快,MDS 会在一秒钟后重复“回收 cap”请求。这意味着 MDS 将一遍又一遍地发送“回收 cap”。会话的“回收 cap”的“总”计数器将不断增长,最终将超过“监视器警告限制”。
有一种由 mds_recall_max_decay_threshold 参数(默认为 126K)控制的限制机制可用于降低“回收 cap”计数器增长的速度,但有时不足以减缓“回收 cap”计数器的增长率。如果更改 mds_recall_max_decay_threshold 值不足以降低“回收 cap”计数器的增长率,请逐渐减小 mds_recall_max_caps,直到日志中不再出现“clients failing to respond to cache pressure”消息。
示例场景
这是一个例子。客户端缓存了 20k 个 cap。在某个时刻,服务器决定客户端不活跃(因为会话的 cache_liveness 值很低)。它开始要求客户端将 cap 释放到 mds_min_caps_per_client 值(默认为 100)。每秒,它都会发送 recall_caps,要求释放 caps_num - mds_min_caps_per_client 个 cap(但不超过 mds_recall_max_caps,默认为 30k)。客户端开始释放,但释放速度(例如)仅为每秒 100 个 cap。
因此,在第一秒,mds 发送 recall_caps = 20k - 100;第二秒 recall_caps = (20k - 100) - 100;第三秒 recall_caps = (20k - 200) - 100,依此类推。每次发送 recall_caps 时,它都会更新会话的 recall_caps 值,该值计算的是最后一分钟发送了多少 recall_caps。即,计数器增长很快,最终超过 mds_recall_warning_threshold,默认为 128K,ceph 开始在状态中报告“failing to respond to cache pressure”警告。现在,在我们设置 mds_recall_max_caps = 3K 之后,在这种情况下,mds 服务器每秒仅发送 3K recall_caps,并且会话的 recall_caps 值可能具有的最大值(如果 mds 至少每秒发送 3K 持续一分钟)为 60 * 3K = 180K。这意味着仍然有可能达到 mds_recall_warning_threshold,但前提是客户端长时间不“响应”,正如您的实验所示,情况并非如此。