概述
Solr允许按请求类型进行速率限制。每个请求类型可以分配允许同时活跃的并发请求的最大数量。默认情况下实现了对更新和搜索的速率限制。
当请求超过请求配额时,进一步的传入请求将被拒绝,并返回HTTP错误代码429(Too Many Requests)。
核心概念
实例级限制
速率限制在实例(JVM)级别工作,而不是在集合或核心级别。在规划容量时需要考虑这一点。未来计划在此处实现更细粒度的执行(SOLR-14710)。
请求类型识别
请求的速率限制桶由该请求的唯一Solr-Request-Type
HTTP标头的值确定。没有Solr-Request-Type
标头的请求将被接受并处理,不受速率限制。
当前支持的请求类型
目前只有一个Solr-Request-Type
值被识别用于速率限制:字面字符串值QUERY
。只有指定标头Solr-Request-Type: QUERY
的请求将受到速率限制。
注意:在支持多个请求类型之前,其他
Solr-Request-Type
规范完全不受速率限制,”槽位借用”和”保证槽位”的概念(仅在多个请求类型间才有意义)没有实际效果。
何时使用速率限制器
速率限制器应该在用户希望为特定请求类型分配请求线程池的保证容量时使用。索引和搜索请求主要在CPU资源方面相互竞争。这在生产工作负载的高压力下变得尤其明显。当前实现具有查询速率限制器,可以为索引释放资源。
速率限制器配置
默认的速率限制器是搜索速率限制器。可以使用以下命令进行配置:
1 | curl -X POST -H 'Content-type:application/json' -d '{ |
配置参数详解
enabled:启用查询速率限制器
- 类型:布尔值
- 默认值:
false
- 说明:控制查询速率限制器的启用状态
1 | "enabled": true |
allowedRequests:最大并发请求数
- 类型:整数
- 默认值:核心数 × 3
- 说明:允许在给定时间点设置最大并发搜索请求数
1 | "allowedRequests": 20 |
容量规划建议:
- 轻量级查询:可以设置较高的并发数
- 复杂查询:应该设置较低的并发数以避免资源耗尽
- 混合负载:根据查询复杂度和硬件资源平衡设置
slotAcquisitionTimeoutInMS:请求槽位分配等待时间
- 类型:整数(毫秒)
- 默认值:
-1
(表示不等待) - 说明:当所有槽位都满时,请求在进入等待队列之前等待槽位可用的时间
1 | "slotAcquisitionTimeoutInMS": 70 |
超时设置策略:
-1
或0
:不等待,立即进入队列或拒绝- 短超时(10-50ms):适用于实时性要求高的场景
- 中等超时(50-200ms):平衡响应时间和成功率
- 长超时(>200ms):可能导致查询响应时间过长
注意:较高的请求分配时间可能导致更大的队列时间,并可能导致查询等待时间更长。
slotBorrowingEnabled:槽位借用启用
- 类型:布尔值
- 默认值:
false
- 说明:是否启用槽位借用机制
1 | "slotBorrowingEnabled": true |
实验性功能:此功能是实验性的,如果借用请求是长期存在的,可能导致槽位被阻塞。
guaranteedSlots:保证槽位
- 类型:整数
- 默认值:允许的并发请求数 / 2
- 说明:查询速率限制器将保留的保证槽位数量,无论查询请求的负载如何
1 | "guaranteedSlots": 5 |
使用场景:
- 仅在启用槽位借用时使用
- 作为查询速率限制器不允许其他请求类型从其配额借用槽位的阈值
- 确保关键查询始终有可用资源
实验性功能:此功能是实验性的,如果借用请求是长期存在的,可能导致槽位被阻塞。
重要特性和注意事项
超额订阅(Over Subscribing)
可以为请求类型定义超过可用线程池大小的配额大小。Solr不会强制执行可为请求类型定义的配额大小规则。这是故意这样做的,以允许用户完全控制其配额分配。
影响:
- 如果配额超过可用线程池的大小,线程池的标准队列策略将启动
- 可能导致请求排队等待而不是立即执行
- 需要根据实际硬件资源合理设置配额
槽位借用(Slot Borrowing)
如果某个配额没有积压但其他配额有积压,那么相对较不繁忙的配额可以从较繁忙的配额”借用”槽位。目前这是基于轮询方式完成的,未来计划将其改为基于优先级的模型(SOLR-14709)。
机制说明:
- 负载检测:系统监控各请求类型的负载情况
- 槽位分配:空闲的请求类型可以借用繁忙请求类型的槽位
- 轮询分配:按照轮询方式分配借用的槽位
- 动态调整:根据负载变化动态调整槽位分配
限制:
- 这是实验性功能,不保证借用的槽位能及时返还
- 长期运行的借用请求可能导致槽位长期被占用
- 可能影响原配额的性能表现
配置示例和使用场景
基础配置示例
保守配置(适用于稳定环境)
1 | curl -X POST -H 'Content-type:application/json' -d '{ |
平衡配置(适用于混合负载)
1 | curl -X POST -H 'Content-type:application/json' -d '{ |
激进配置(适用于高吞吐环境)
1 | curl -X POST -H 'Content-type:application/json' -d '{ |
不同场景的配置策略
读多写少场景
1 | { |
特点:
- 较高的并发查询数
- 不启用借用机制,确保查询性能稳定
- 保证足够的槽位用于查询
写多读少场景
1 | { |
特点:
- 较少的并发查询数,为写入预留资源
- 启用借用机制,允许查询在负载低时使用更多资源
- 保证最小查询能力
实时分析场景
1 | { |
特点:
- 中等并发查询数
- 短等待时间,保证实时响应
- 启用借用机制,优化资源利用
监控和调优
关键指标监控
请求队列长度
- 指标:等待队列中的请求数量
- 阈值:建议保持在较低水平(<10)
- 调优:如果队列长度持续较高,考虑增加
allowedRequests
请求拒绝率
- 指标:返回429错误的请求比例
- 阈值:建议保持在1%以下
- 调优:如果拒绝率过高,需要优化配置或增加硬件资源
平均响应时间
- 指标:查询平均执行时间
- 阈值:根据业务需求设定
- 调优:如果响应时间过长,可能需要降低并发数
槽位利用率
- 指标:活跃槽位数 / 总槽位数
- 阈值:建议保持在70-90%
- 调优:利用率过低浪费资源,过高可能导致排队
性能调优建议
渐进式调优
- 基线测试:从保守配置开始,建立性能基线
- 逐步优化:逐步增加并发数,观察性能变化
- 压力测试:在接近生产负载的条件下测试
- 持续监控:部署后持续监控关键指标
配置优化策略
硬件资源评估:
- CPU核心数:影响并发处理能力
- 内存大小:影响缓存和处理复杂查询的能力
- 磁盘I/O:影响索引访问速度
查询模式分析:
- 查询复杂度:复杂查询需要更多资源
- 查询频率:高频查询需要更多并发槽位
- 查询时间分布:了解峰值时间模式
业务需求平衡:
- 响应时间要求:实时性要求影响超时设置
- 吞吐量要求:大批量处理需要更高并发
- 可用性要求:高可用性需要保守的配置
故障排除
常见问题和解决方案
问题1:大量429错误
现象:客户端收到大量”Too Many Requests”错误
原因分析:
allowedRequests
设置过低- 查询复杂度过高,处理时间过长
- 客户端并发请求过多
解决方案:
- 增加
allowedRequests
值 - 优化查询性能,减少处理时间
- 在客户端实现重试和退避策略
- 启用
slotAcquisitionTimeoutInMS
给予短暂等待时间
问题2:查询响应时间过长
现象:查询响应时间明显增加
原因分析:
slotAcquisitionTimeoutInMS
设置过高- 槽位被长期占用
- 槽位借用导致的延迟
解决方案:
- 减少
slotAcquisitionTimeoutInMS
值 - 禁用
slotBorrowingEnabled
- 增加
guaranteedSlots
确保核心查询不受影响
问题3:资源利用率不足
现象:系统资源充足但并发度不高
原因分析:
allowedRequests
设置过于保守- 没有启用槽位借用机制
解决方案:
- 逐步增加
allowedRequests
- 启用
slotBorrowingEnabled
- 调整
guaranteedSlots
平衡不同请求类型
最佳实践总结
配置原则
- 渐进调优:从保守配置开始,逐步优化
- 监控驱动:基于实际监控数据做调整决策
- 业务导向:配置应该服务于具体业务需求
- 测试验证:任何配置变更都应该经过充分测试
运维建议
- 建立基线:记录默认配置下的性能表现
- 设置告警:对关键指标设置监控告警
- 定期审查:定期审查配置是否仍然适合当前负载
- 文档记录:详细记录配置变更的原因和效果
容量规划
- 硬件匹配:配置应该与硬件能力匹配
- 负载预测:基于历史数据预测未来负载增长
- 弹性设计:配置应该能够适应负载波动
- 预留空间:为突发负载预留一定的处理能力
速率限制器是SolrCloud中重要的资源管理工具,正确配置和使用可以有效提高系统稳定性和性能表现。通过合理的配置策略和持续的监控优化,可以在保证服务质量的同时最大化系统资源利用率。