ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ceph RGW速率限制实战:从bucket级到用户级限速配置

Ceph RGW速率限制实战:从bucket级到用户级限速配置 先说个背景。我们这边有一套面向多个业务部门提供对象存储服务的Ceph集群对外入口就是RGW。去年线上出过一次事故某个业务部门做数据回迁把一台共享型RGW实例的出向带宽直接打满其他部门的请求延迟从几十毫秒涨到几十秒小文件读写基本不可用。当时集群里没开任何限速策略我除了让业务方停任务没有别的办法。后来改造清单里第一条就是给RGW加限速。Ceph RGW速率限制简单说就是在RGW层面对特定用户或特定bucket的请求频率和吞吐做限制避免单一租户、单一桶把整个网关拖垮。它和存储配额是两回事配额管的是“能存多少”限速管的是“能跑多快”。这篇文章我会结合线上配置的实操过程把版本前提、bucket级限速、用户级限速、踩坑经验一次性讲清楚。适合正在维护Ceph RGW、被多租户流量干扰搞到头大的存储运维和SRE参考。1. Ceph RGW速率限制能解决什么问题1.1 多租户场景下的“噪音邻居”问题很多人对Ceph的第一印象是RBD块存储但RGW对象网关也是对外服务的重要入口。多租户共用一套RGW时资源争抢是必然的。某个租户跑了高并发批量任务请求量大、流量猛RGW的CPU、网卡、底层OSD都会被打高。其他租户的正常业务如果也在同一个RGW上延迟和吞吐都会受影响。这种问题在TCP/IP层面解决不了。对象存储协议本身没有“优先级”概念S3请求发到RGW就是同等的。如果不在RGW内部加一层节流那只能眼睁睁看着一个租户把所有人的体验拉低。RGW速率限制的核心价值就在这里它能在应用层约定一个速率上限让每个用户或每个桶的请求频率、吞吐都被限制在一个设定范围里。限制之后即使某个业务方突发流量冲过来RGW也会先把流量控制在阈值以内其他租户的请求有相对稳定的资源可用。1.2 RGW限速的两个维度bucket级和用户级RGW的限速能力是分阶段引入的不同版本的颗粒度不一样。第一个阶段是bucket级限速从Nautilus14.x开始支持。它控制的是单个bucket的读写Ops和读写带宽。如果你的问题很单纯就是某个桶被高频读写那用bucket级限速就够了。缺点是用户如果有多个bucket他可以新建bucket绕过单桶限速把流量分散到其他桶里。第二个阶段是用户级限速从Quincy17.x开始支持。它控制的是某个用户在其所有bucket上的总请求速率也可以针对该用户下某一个bucket做独立限制。这样用户就无法通过多建bucket绕开限制。实际使用中两者可以同时配置。RGW在处理请求时会分别检查bucket级限制和用户级限制只要任何一个超了请求就会被节流。我遇到的场景大多是先按用户设置一个总带宽上限再对几个核心业务桶单独设更严格或更宽松的策略。1.3 底层是怎么实现的令牌桶与dmclockbucket级限速的实现用的是典型的令牌桶算法。每个bucket会维护一组令牌桶读操作和写操作各有自己的令牌桶。令牌按固定速率生成桶里最多攒下一定数量的令牌。请求进来时要消耗对应数量的令牌令牌不够就排队等。这里有一个关键点RGW的限速是“节流”而不是“拒流”。请求超速后不会被直接丢掉而是被hold住等令牌补充够了再继续处理。所以从客户端看表现不是立刻收到错误码而是请求变慢、耗时变高。用户级限速走的是dmclock算法。dmclock是Ceph生态中用于QoS的分布式时钟调度算法核心参数包括reservation、limit、weight。RGW用户限速主要用limit部分来控制最大速率同时可以配置全局限制和独立限制。dmclock的另一个好处是支持在多个RGW实例之间协同让限速状态不是单机孤岛。我自己理解这两种算法的差别时习惯打个比方令牌桶像一个匀速滴水的漏斗水龙头持续加水杯子一次能接多少取决于杯口大小dmclock更像一个交通信号灯系统它站在更宏观的角度协调多个路口的车流。实际使用中我们不Care算法细节只需要知道两者的目的都是让请求速率“可预期”。2. 动手之前版本前提与开启开关2.1 先确认你的Ceph版本支持到什么程度版本这一步最容易踩坑。我见过有人拿着文档配置用户级限速结果生产环境是Pacific16.xrgw_user_rate_limit_enabled这个参数根本不认识配置直接报错。按版本梳理一下版本支持能力说明14.x Nautilusbucket级限速需要手开rgw_bucket_rate_limit_enabled16.x Pacificbucket级限速建议至少到16.2.x修复不少问题17.x Quincybucket级限速、用户级限速用户级限速的第一个可用版本18.x Reefbucket级限速、用户级限速功能延续更推荐生产使用如果你的集群是离线部署的三节点环境我建议直接上17.2.x或18.2.x的长期支持版本。虽然离线部署时获取软件包会比在线环境麻烦一些但后续功能完整度差很多。我知道有些团队还在用Mimic或Luminous那种版本做不了RGW原生限速只能依赖前置负载均衡层做流量控制方案复杂度会高不少。2.2 在ceph.conf中开启限速开关RGW限速默认是关闭的需要在ceph.conf中对应RGW实例的配置段打开开关。[client.rgw.rgw1] rgw_bucket_rate_limit_enabled true rgw_user_rate_limit_enabled true注意rgw_user_rate_limit_enabled这个参数只在Quincy及以后版本里存在。Nautilus和Pacific版本认不出来配置了会报参数错误。如果你只需要bucket级限速只用开第一个开关就够。多实例环境要特别注意集群如果起了多个RGW实例比如rgw1、rgw2、rgw3所有实例的配置段都要统一开启这两个开关。否则请求被负载均衡轮询到没开限速的实例限速策略就形同虚设。RGW的限速状态是进程内的不是全局共享一个令牌池这一点和Ceph Monitor的选举机制完全不一样。2.3 重启RGW的节奏修改ceph.conf之后需要重启RGW进程让配置生效。systemctl restart ceph-radosgwrgw1多实例环境建议逐台滚动重启不要一次性把所有RGW全部重启。RGW重启期间对应实例的请求会断掉如果前端负载均衡有健康检查通常会摘除节点但全部重启的话客户端会集体报错。我更习惯的做法是先重启一台观察几分钟确认RGW起得来、请求正常再重启下一台。重启前顺手看一眼集群状态。如果此时正在做PG recovery或者有OSD处于down状态重启RGW会额外增加元数据访问压力虽然影响不算大但能避开就避开。3. 实操给Bucket配置速率限制3.1 确认目标和参数含义我在线上做过一次比较典型的限速配置。场景是某个业务方有一个大桶每天凌晨跑批任务经常把整台RGW的读带宽打满。我给这个桶设置了读带宽上限和读Ops上限。先明确一下bucket级限速的四个核心参数参数含义建议单位max-read-ops每秒最大读请求数ops/smax-write-ops每秒最大写请求数ops/smax-read-bytes每秒最大读吞吐字节/smax-write-bytes每秒最大写吞吐字节/s这里最容易踩坑的是字节单位。max-read-bytes和max-write-bytes的单位是byte不是KB也不是MB。设置100MB/s要写104857600不是100。我见过有人设置成100然后一直疑惑为什么限速不生效因为100字节每秒对于实际流量来说几乎等于完全断流但请求量小的时候又看不出来。3.2 执行bucket limit set命令先创建一个验证用的bucket或者直接用现成的bucket。我这边用test-app这个桶做验证。radosgw-admin bucket limit set \ --buckettest-app \ --max-read-ops100 \ --max-write-ops50 \ --max-read-bytes104857600 \ --max-write-bytes52428800这条命令的意思是test-app这个桶每秒最多处理100个读请求、50个写请求读带宽最大100MiB/s写带宽最大50MiB/s。注意几个细节命令执行后配置会持久化到bucket的元数据里不需要额外写文件。所以正常来说重启RGW不会丢配置。如果某个参数不想限制可以不传或者设置为0。RGW对读和写的分类按操作类型区分。GET、HEAD、ListObjects这类算读操作PUT、POST、DELETE这类算写操作。注意DELETE对象是写操作高并发删除任务也会消耗写令牌。3.3 验证限速是否真正生效设置完之后用check命令查看当前限速配置radosgw-admin bucket limit check --buckettest-app这个命令会显示bucket当前的限速配置项。如果输出的字段都是0说明没设置上如果显示了你设置的值说明配置已经写进去了。验证限速效果我建议直接用并发下载或上传脚本压一下。分享一个我常用的简单验证方法用curl并发下载同一个对象观察总吞吐。比如用10个并发去下载如果限速配置是100MiB/s在机器网络链路足够的前提下总吞吐应该被限制在100MiB/s附近不会冲上去。如果发现限速没有生效第一步先看RGW日志里有没有相关报错。很多情况下是版本不支持或者参数没有写到正确的RGW实例段。3.4 调整、关闭和清除限速业务需求是动态的限速策略也经常要调整。重新执行bucket limit set命令并传入新值会覆盖旧配置。彻底清除限速把对应参数设置为0即可radosgw-admin bucket limit set \ --buckettest-app \ --max-read-ops0 \ --max-write-ops0 \ --max-read-bytes0 \ --max-write-bytes00在这里表示不限制不是限制为0。我一开始也搞混过这个概念以为设置0就是完全禁止访问结果是限速被清掉了。如果你真想禁止访问某个bucket应该用bucket policy或者权限控制而不是限速。3.5 bucket级限速的边界bucket级限速有一个绕不开的边界就是它只能限制“已经定位到bucket”的请求。像ListBuckets这类用户级操作走的是用户维度不归bucket限速管。所以如果恶意用户频繁ListBuckets你靠bucket级限速是挡不住的得靠用户级限速或者网关前面的访问控制策略。另外bucket级限速是进程内存态元数据持久化的组合限速状态会实时变化但配置本身是存在bucket元数据里的。如果某个bucket数量极其庞大比如上百万个bucket那么为每个bucket维护令牌桶状态会带来额外内存消耗。线上如果遇到RGW RSS上涨明显可以把限速只开在真正需要控制的业务桶上不要全量铺开。4. 实操配置用户级速率限制Quincy4.1 用户级限速的设计思路用户级限速解决的是bucket级限速“可绕过”的问题。用户把流量分散到多个bucket后单桶限速就失效了。用户级限速直接盯住用户维度无论请求打到这个用户的哪个bucket都会计入用户总速率。用户级限速支持两种模式全局限制global限制该用户在所有bucket上的总速率独立限制standalone限制该用户下某一个bucket的独立速率全局限制和独立限制可以同时存在。RGW在限速判断时会先看独立限制再看全局限制。只要任何一个超限请求就会被节流。这种设计很适合“用户整体限速但个别业务桶单独强调控”的场景。4.2 开启用户限速并确认命令和bucket级限速一样先要在ceph.conf中开启[client.rgw.rgw1] rgw_user_rate_limit_enabled true然后重启RGW实例。这部分和前面一样逐台滚动重启。用户级限速的命令入口是radosgw-admin的user rate-limit子命令。不同的Ceph小版本参数名和用法可能略有差异所以执行之前建议先看一遍帮助信息radosgw-admin user rate-limit --help不要嫌这一步多余。我遇到过一次版本差异参数名从max-read-bytes变成了其它写法直接按老版本命令敲报错报得很莫名。先看help能省很多排查时间。4.3 给用户配置全局限速假设用户johndoe有多个bucket我需要限制他在所有bucket上的总读带宽100MiB/s、写带宽50MiB/s以及整体请求频率radosgw-admin user rate-limit set \ --uidjohndoe \ --ratelimit-scopeuser \ --ratelimit-typeglobal \ --max-read-ops500 \ --max-read-bytes104857600 \ --max-write-ops200 \ --max-write-bytes52428800这些参数的含义和bucket限速基本一致区别只是作用范围从单个bucket变成了用户所有bucket。配置成功后johndoe无论从哪个bucket发起请求总速率都会被限制在这个范围内。这里有一个值得注意的地方用户级限速按用户维度建桶如果该用户下同时有很多客户端在并发访问总速率是多个客户端共享的不是每个客户端单独100MiB/s。这个逻辑要提前跟业务方说清楚否则他们会误以为每个客户端都有100MiB/s的带宽。4.4 给用户下某个bucket配置独立限速再举一个独立限速的例子。某个用户整体是放开的但其中一个bucket承担了核心生产业务需要单独限制避免这个bucket的突发流量影响用户其他普通业务。radosgw-admin user rate-limit set \ --uidjohndoe \ --buckettest-app \ --ratelimit-scopeuser \ --ratelimit-typestandalone \ --max-read-ops100 \ --max-read-bytes10485760 \ --max-write-ops50 \ --max-write-bytes5242880配置之后johndoe在test-app这个bucket上的读写速率会被单独限制而他的其他bucket不受这个限制影响。如果此时还配置了全局限制那么独立限制和全局限制会双重判断取更严格的效果。我是这么理解这两种模式的全局限制像是整栋楼的总进水管独立限制像是某一个房间里的分水阀。你可以在总进水管上设一个整体流量上限也可以在某一个房间里单独装一个阀两个可以同时存在谁先超了水就变小。4.5 查看和移除用户限速配置查看用户限速配置可以通过user info命令也可以看看有没有独立的get子命令radosgw-admin user info --uidjohndoe输出里如果包含rate limit相关字段就说明配置已经生效。不同的Ceph版本输出格式会有差别但基本都能看到scope、type、max-read-ops这些字段。移除某个限速做法和设置类似把对应的值设置为0或者执行对应的remove命令。具体用哪个同样以radosgw-admin user rate-limit --help的输出为准。4.6 和quotas的配合使用用户级限速和用户配额其实是两个互补的工具。quota控制的是用户可以占用多少存储空间和多少个对象限速控制的是用户请求的速率。实际运维中我通常会给一个租户同时设置存储配额和速率限制配额防止他把集群空间写满限速防止他在短时间内把集群IO打爆。quota设置的命令是radosgw-admin quota set和限速是两套独立机制。这里不展开但可以把两种手段理解成“容量闸门”和“流量闸门”配合使用才完整。5. 常见问题与排查技巧实录5.1 限速配置了但流量还是冲上去这个问题排第一我遇到太多次。大多数时候排查顺序是这样的检查所有RGW实例是否都开启了对应的开关。多实例环境下只要有一个实例没配置负载均衡把请求打到它那里就不会限速。检查是否重启过RGW实例。ceph.conf的参数修改不重启不会生效。检查参数是否设置成0了。0代表不限速不是禁止。检查版本是否支持。在Pacific上配用户级限速会直接报错。检查限速值是不是比实际带宽还大。比如你给用户限了1000MiB/s但实际流量只有200MiB/s当然看不到限速效果。排查时我习惯先用bucket limit check确认配置确实写进去了再到RGW日志里看有没有限速相关记录。如果配置显示正常但流量依然高基本上就是多实例配置不一致的问题。5.2 重启RGW之后限速配置丢失这听起来像是bug但大概率是元数据同步的问题。bucket limit set写入的是bucket元数据正常情况重启不会丢失。如果多个zone或者多个zonegroup之间存在元数据同步延迟你在一个RGW实例上配置的限速可能不会立刻同步到另一个实例。检查思路确认配置的RGW实例和承载请求的RGW实例是不是同一个zone。多zone环境下检查zone间元数据同步是否正常用radosgw-admin sync status看看。如果是单zone多实例一般不存在同步问题。还有一种情况就是命令执行的时候没有指定正确的bucket。比如bucket名写错或者bucket属于其他用户命令返回成功但实际什么都没改。所以配置后一定要用check或info确认。5.3 限速后客户端表现是超时而不是报错很多刚接触RGW限速的人会以为超速会立刻收到403或者503实际不是。RGW的限速是延迟式节流超速请求会被暂时hold住等令牌补充够再继续处理。客户端看到的现象是请求耗时明显变长极端情况下会超时。所以在验证限速是否生效时不要只看错误码要看请求的完成耗时。用并发脚本压测的时候观察平均响应时间是否显著上升。如果并发上去但总吞吐被压在设定值附近说明限速是生效的。5.4 限速在集群恢复期间的作用这里分享一个实用经验。有一次集群有一块OSD掉盘进入recovery状态。正常情况下recovery会占用大量磁盘IO但如果此时客户端还在全速读写recovery速度会被拖得很慢。我的做法是在recovery期间临时给几个重客户端加限速把带宽让给底层OSD恢复。等集群状态恢复正常再把这些临时限速清掉。这个操作比停业务温和得多业务方基本无感。只需要几条radosgw-admin命令就能完成不需要业务方改任何代码。对于小规模三节点集群来说这种临时限速在故障运维里很实用。磁盘故障本身已经让集群性能下降了再叠加客户端突发流量很容易把集群拖到不可用状态。5.5 限速状态的内存与性能开销bucket限速和用户限速都不是零成本。每个被限速的bucket需要维护令牌桶状态每个被限速的用户也需要维护对应的速率计数器。如果集群规模很大bucket数量几百万限速带来的内存开销就不能忽略。我建议的落地方式只在真正有SLA保障需求的业务桶上开启限速不要在全局所有桶上无脑铺开。尤其对于内部测试桶、低频访问桶没必要浪费这部分资源。限速的本质是给流量设边界需要边界的地方才需要它。5.6 关于限速值设定的建议最后聊一下限速值怎么定。我踩过几次坑之后总结了一个比较稳的流程先不设限速观察目标bucket或用户一周的监控数据记录峰值带宽、峰值Ops、日均负载。然后取峰值值的80%到90%作为初始上限。不要凭空拍脑袋设一个很小的值那样会误伤正常业务尤其是一些周期性跑批业务。限速配置好后观察几天。如果业务方反馈正常且峰值确实被压住就维持如果正常业务都被影响适当放宽一点。限速不是一次配置就一劳永逸业务增长、新任务上线都会让流量模型变化每季度复查一次限速值是必要的。根据我个人经验限速策略最忌讳的是“拍脑袋定值”。我见过有人把某业务的带宽从1GiB/s直接压到10MiB/s结果业务方第二天就来投诉。比较好的做法是循序渐进先松后紧给业务方一段适应期再逐步调整到目标值。这样既达到保护集群的目的也不会让限速变成业务事故的导火索。
返回列表