如何在 Logstash 插件中与 Redis Sentinel / Cluster 模式集成?
在生产环境中,Redis 单点存在高可用风险。为了保障日志处理系统的稳定性,Logstash 自定义插件必须支持:
- ✅ Redis Sentinel(哨兵模式):主从高可用 + 自动故障转移
- ✅ Redis Cluster(集群模式):数据分片 + 水平扩展
本文将详细介绍 如何在 Logstash 插件中集成 Redis Sentinel 和 Cluster 模式,并提供完整代码示例、连接池配置、故障恢复机制等企业级实践。
一、Redis 高可用架构对比
| 特性 | Sentinel(哨兵) | Cluster(集群) |
|---|---|---|
| 架构 | 主从 + 哨兵监控 | 分片集群(16384 slots) |
| 数据分布 | 全量复制 | 分片存储 |
| 高可用 | 自动主从切换 | 节点故障自动迁移 |
| 扩展性 | 垂直扩展 | 水平扩展 |
| 适用场景 | 中小规模,高可用优先 | 大规模,高吞吐、大数据量 |
| 客户端要求 | 支持 Sentinel 发现 | 支持 Cluster 路由 |
✅ 生产推荐:
- 中小系统:Sentinel
- 大数据量/高并发:Cluster
二、前提:使用支持 Sentinel/Cluster 的 Redis Gem
Logstash 默认使用的 redis gem(https://github.com/redis/redis-rb)完全支持 Sentinel 和 Cluster。
确保 .gemspec 中依赖版本 ≥ 4.0:
# logstash-filter-redis_ha.gemspec
s.add_runtime_dependency "redis", ">= 4.0", "< 5.0"
s.add_runtime_dependency "connection_pool", "~> 2.3"
安装插件时会自动安装。
三、方案一:集成 Redis Sentinel(哨兵模式)
3.1 Sentinel 架构示意图
[Logstash]
↓ (发现 master)
[Sentinel1] → 自动选举 → [Redis Master]
[Sentinel2] ↗
[Sentinel3] [Redis Slave]
客户端通过哨兵获取当前 master 地址。
3.2 插件配置参数
config :sentinels, :validate => :array, :required => false
# 示例: ["host1:26379", "host2:26379"]
config :master_name, :validate => :string, :required => true
config :redis_password, :validate => :password
config :sentinel_password, :validate => :password # 哨兵可能单独设密
3.3 核心代码实现(带连接池)
# lib/logstash/filters/redis_sentinel.rb
require "logstash/filters/base"
require "logstash/namespace"
require "connection_pool"
require "redis"
class LogStash::Filters::RedisSentinel < LogStash::Filters::Base
config_name "redis_sentinel"
# 配置参数
config :master_name, :validate => :string, :required => true
config :sentinels, :validate => :array, :required => true
config :sentinel_password, :validate => :password
config :redis_password, :validate => :password
config :db, :validate => :number, :default => 0
config :pool_size, :validate => :number, :default => 5
config :pool_timeout, :validate => :number, :default => 5
def register
@logger.info("Connecting to Redis Sentinel",
:master => @master_name,
:sentinels => @sentinels)
# 解析 sentinels 数组为 hash 格式
sentinel_hosts = @sentinels.map do |addr|
host, port = addr.split(":")
{ host: host, port: port.to_i }
end
# 创建连接池
@redis_pool = ConnectionPool.new(size: @pool_size, timeout: @pool_timeout) do
Redis.new(
url: "redis://:#{@redis_password&.value if @redis_password}@#{@master_name}",
sentinels: sentinel_hosts,
role: :master, # 只连接 master
password: @sentinel_password&.value,
db: @db,
reconnect_attempts: 3,
connect_timeout: 2,
read_timeout: 5,
write_timeout: 5
)
end
# 测试连接
@redis_pool.with { |redis| redis.ping }
rescue => e
@logger.error("Failed to connect to Redis Sentinel", :error => e.message)
raise e
end
def filter(event)
key = event.get("lookup_key")
return unless key
begin
result = @redis_pool.with do |redis|
redis.get(key)
end
if result
event.set("lookup_value", result)
filter_matched(event)
end
rescue Redis::CannotConnectError, Redis::ConnectionError => e
@logger.warn("Redis connection failed, will retry", :error => e.message)
# 连接池会自动重试
rescue => e
@logger.warn("Redis lookup failed", :error => e.message)
end
end
def close
@redis_pool&.shutdown do |redis|
redis.quit rescue nil
end
end
end
3.4 配置示例(logstash.conf)
filter {
redis_sentinel {
master_name => "mymaster"
sentinels => ["192.168.1.10:26379", "192.168.1.11:26379", "192.168.1.12:26379"]
redis_password => "strongpass123"
sentinel_password => "sentinel_pass" # 如果哨兵有密码
pool_size => 10
}
}
四、方案二:集成 Redis Cluster(集群模式)
4.1 Cluster 架构特点
- 数据自动分片到 16384 slots
- 至少 3 master 节点
- 客户端需支持 ASK/MOVED 重定向
4.2 插件配置参数
config :cluster_nodes, :validate => :array, :required => true
# 示例: ["node1:6379", "node2:6379", "node3:6379"]
config :cluster_password, :validate => :password
config :cluster_retry_attempts, :validate => :number, :default => 5
4.3 核心代码实现
# lib/logstash/filters/redis_cluster.rb
require "logstash/filters/base"
require "logstash/namespace"
require "connection_pool"
require "redis"
class LogStash::Filters::RedisCluster < LogStash::Filters::Base
config_name "redis_cluster"
config :cluster_nodes, :validate => :array, :required => true
config :cluster_password, :validate => :password
config :db, :validate => :number, :default => 0
config :pool_size, :validate => :number, :default => 5
config :pool_timeout, :validate => :number, :default => 5
config :connect_timeout, :validate => :number, :default => 2
config :read_timeout, :validate => :number, :default => 5
def register
@logger.info("Connecting to Redis Cluster",
:nodes => @cluster_nodes.size)
# 解析节点
nodes = @cluster_nodes.map do |addr|
host, port = addr.split(":")
{ host: host, port: port.to_i }
end
@redis_pool = ConnectionPool.new(size: @pool_size, timeout: @pool_timeout) do
Redis.new(
cluster: nodes,
password: @cluster_password&.value,
db: @db,
connect_timeout: @connect_timeout,
read_timeout: @read_timeout,
write_timeout: @write_timeout,
reconnect_attempts: 3,
timeout: 5
)
end
# 测试连接
@redis_pool.with { |redis| redis.ping }
rescue => e
@logger.error("Failed to connect to Redis Cluster", :error => e.message)
raise e
end
def filter(event)
key = event.get("user_id")
return unless key
full_key = "user:profile:#{key}"
begin
result = @redis_pool.with do |redis|
redis.get(full_key)
end
if result
event.set("user_profile", result)
filter_matched(event)
end
rescue Redis::CommandError => e
if e.message.include?("MOVED") || e.message.include?("ASK")
@logger.debug("Cluster redirection, will retry", :error => e.message)
# redis-rb 会自动处理重试
else
@logger.warn("Cluster command failed", :error => e.message)
end
rescue => e
@logger.warn("Redis cluster error", :error => e.message)
end
end
def close
@redis_pool&.shutdown do |redis|
redis.quit rescue nil
end
end
end
4.4 配置示例
filter {
redis_cluster {
cluster_nodes => ["192.168.2.10:6379", "192.168.2.11:6379", "192.168.2.12:6379"]
cluster_password => "cluster_strong_pass"
pool_size => 8
}
}
五、连接池与高可用最佳实践
5.1 连接池配置建议
| 参数 | Sentinel | Cluster |
|---|---|---|
pool_size | 5~10 | 10~20(因多节点) |
timeout | 5s | 5s |
reconnect_attempts | 3 | 3 |
5.2 故障恢复机制
- ✅
redis-rb自动处理:- Sentinel:自动发现新 master
- Cluster:自动处理 MOVED/ASK 重定向
- ✅ 连接池自动重试获取连接
- ✅ 在
rescue中记录日志,不阻塞事件流
5.3 监控建议
| 指标 | 监控方式 |
|---|---|
| 连接池等待超时 | 日志中 pool timeout |
| Redis 响应延迟 | @redis_pool.with { redis.ping } 计时 |
| Cluster 重定向次数 | 日志中 MOVED/ASK |
| Sentinel 切换事件 | Redis 哨兵日志 |
六、常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
Cannot obtain master address | Sentinel 地址错或密码错 | 检查 sentinels 和 sentinel_password |
No resolvable masters | 所有 Sentinel 不可用 | 检查网络和 Sentinel 状态 |
MOVED xxx 频繁 | Cluster 网络不稳定 | 优化网络,增加超时 |
| 连接池超时 | 并发高或 Redis 慢 | 增大 pool_size 或优化查询 |
| 密码错误 | password.value 未正确获取 | 使用 @password&.value |
七、最佳实践总结
| 项目 | 推荐做法 |
|---|---|
| Sentinel | 用于高可用,3 哨兵 + 1主1从起 |
| Cluster | 用于大数据量,至少 3 master |
| 连接池 | 必用 connection_pool |
| 错误处理 | rescue 所有 Redis 异常,避免阻塞 |
| 日志 | 记录连接状态和关键错误 |
| 测试 | 在真实 Sentinel/Cluster 环境测试 |
八、参考资源
- Redis Sentinel 文档:https://redis.io/topics/sentinel
- Redis Cluster 文档:https://redis.io/topics/cluster-tutorial
redis-rbGitHub:https://github.com/redis/redis-rb- Logstash 插件开发:https://www.elastic.co/guide/en/logstash/current/plugin-development.html
九、结语
通过集成 Redis Sentinel 或 Cluster,你的 Logstash 插件将具备:
- ✅ 高可用性:自动故障转移
- ✅ 可扩展性:支持大数据量
- ✅ 生产就绪:符合企业级要求
是构建 稳定、可靠日志处理系统 的关键一步。
🎁 附:完整插件模板
你可以基于以下仓库创建自己的 HA Redis 插件:
git clone https://github.com/logstash-plugins/logstash-filter-redis.git
# 改造为支持 Sentinel/Cluster
Logstash 插件集成 Redis 哨兵/集群模式
5333

被折叠的 条评论
为什么被折叠?



