十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

Envoy Redis Proxy 网络过滤器详解:RESP3 协议协商、故障注入与上游认证配置指南

Envoy Redis Proxy 网络过滤器详解:RESP3 协议协商、故障注入与上游认证配置指南 Envoy Redis Proxy 网络过滤器详解RESP3 协议协商、故障注入与上游认证配置指南【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本篇以 Envoy 官方文档中的 Redis proxy 网络过滤器配置说明为主体系统讲解该过滤器在监听器上的配置方式、统计指标体系、故障注入机制、RESP2/RESP3 协议版本协商行为、MOVED/ASK 重定向的 DNS 解析以及上游 Redis 认证与 AWS IAM 认证的完整配置方法。结合仓库中 api/envoy/extensions/filters/network/redis_proxy/v3/redis_proxy.proto 的字段定义与 source/extensions/filters/network/redis_proxy/config.cc 的工厂实现帮助你在生产环境中正确配置并验证 Redis 代理链路。过滤器定位与基础配置Redis proxy 是 Envoy 的一个 L4 网络过滤器在监听器上对 RedisRESP 协议流量进行解码、路由到上游 Redis 兼容后端、统计与故障注入。官方架构说明见 Redis 代理架构概览。该过滤器需以类型 URLtype.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy配置。以下是一个可直接运行的最小静态配置取自仓库示例 redis-fault-injection.yaml 的监听器与集群骨架static_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 6379 filter_chains: - filters: - name: envoy.filters.network.redis_proxy typed_config: type: type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy stat_prefix: redis_stats prefix_routes: catch_all_route: cluster: redis_cluster settings: op_timeout: 5s clusters: - name: redis_cluster connect_timeout: 1s type: STRICT_DNS load_assignment: cluster_name: redis_cluster endpoints: - lb_endpoints: - endpoint: address: socket_address: address: redis.example.com port_value: 6379几个必填约束值得注意对应 redis_proxy.proto 中的 validate 规则stat_prefix为必填字符串是所有过滤器的统计前缀settingsConnPoolSettings为必填消息其中op_timeout是必填 Duration。从 proto 注释看计时器在 pipeline 首条命令写入后端连接时启动之后每收到一个 Redis 响应就重置计时器若连接尚未建立则由集群的connect_timeout接管超时逻辑必须至少配置一条前缀路由或 catch-all 路由否则在过滤器工厂中会直接抛出异常。在 config.cc 中可以看到当prefix_routes.routes_size() 0 !prefix_routes.has_catch_all_route()时会抛出cannot configure a redis-proxy without any upstream。prefix_routes采用最长前缀匹配多条路由重叠时 Envoy 始终优先选择最长匹配的前缀。proto 中给出的例子是ab→cluster_a、abc→cluster_b时get abc:users命中cluster_b、get ab:users命中cluster_a、不匹配的键返回 NoUpstreamHost 错误若配置了 catch-all 则转发过去。统计指标体系过滤器级统计redis.stat_prefix.*每个配置的 Redis proxy 过滤器都在redis.stat_prefix.*命名空间下暴露如下统计名称类型描述downstream_cx_activeGauge当前活跃连接总数downstream_cx_protocol_errorCounter协议错误总数downstream_cx_rx_bytes_bufferedGauge当前已缓冲的接收字节数downstream_cx_rx_bytes_totalCounter接收字节总数downstream_cx_totalCounter连接总数downstream_cx_tx_bytes_bufferedGauge当前已缓冲的发送字节数downstream_cx_tx_bytes_totalCounter发送字节总数downstream_cx_drain_closeCounter因 draining 而关闭的连接数downstream_rq_activeGauge当前活跃请求数downstream_rq_noprotoCounter在protocol_version: RESP3监听器上、先于HELLO 3握手到达而被以-NOPROTO拒绝的数据命令数downstream_rq_totalCounter请求总数其中downstream_rq_noproto是 RESP3 模式特有的观测点当客户端未完成HELLO 3握手就发送数据命令时包括未知命令详见下文协议版本一节该计数器递增。命令拆分器统计redis.stat_prefix.splitter.*过滤器会为命令拆分器command splitter收集如下统计名称类型描述invalid_requestCounter参数个数不正确的请求数unsupported_commandCounter拆分器不识别的命令数按命令统计redis.stat_prefix.command..*过滤器会为每条 Redis 命令收集以下统计命名空间为redis.stat_prefix.command.command.*。延迟统计默认以毫秒为单位将配置参数latency_in_micros设为 true 后可改为微秒见 RedisProxy.latency_in_micros 字段其注释说明该设置目前不适用于上游命令统计名称类型描述totalCounter命令数successCounter成功的命令数errorCounter返回部分或完整错误响应的命令数latencyHistogram命令执行时间毫秒含延迟故障注入的时间error_faultCounter被注入错误故障的命令数delay_faultCounter被注入延迟故障的命令数注意一个细节当HELLO由外部认证服务external auth provider裁决时其结果在延迟认证往返完成后才从过滤器发出因此只会递增command.hello.total不会递增command.hello.success与command.hello.error。所以对纯HELLO命令total可能大于success error认证结果需通过外部认证服务自身的指标和下游响应来观察。Runtime 运行时开关Redis proxy 过滤器支持以下运行时设置redis.drain_close_enabled当服务器处于 draining 状态且本应尝试 drain close 时对多少比例的连接执行 drain close。默认值为 100百分比。该值可通过 runtime 在运行中动态调整无需重启便于在滚动发布/缩容时精细控制下游连接的收敛速度。故障注入Fault InjectionRedis 过滤器支持故障注入目前支持 Delay 与 Error 两种故障Delay 故障延迟请求Error 故障以错误响应应答且错误故障可以附带延迟。关键约束与官方文档一致过滤器不对配置正确性做校验。由于百分比可以在运行时修改请求时验证正确性开销太大因此保证默认百分比与 runtime 百分比都正确是用户的责任。同一命令组合的故障注入百分比之和不应超过 100%。例如两条故障一条对 GET 以 60% 注入另一条对所有命令以 50% 注入——这是错误配置因为 GET 命令将有 110% 的概率被注入故障等价于每个请求都有故障。延迟是可加和的。如果请求本身耗时 400ms注入 100ms 延迟则总延迟为 500ms。另外由于 Redis 协议的实现约束代理必须保持收到命令的顺序被延迟的请求会连带延迟其后到达的所有请求。故障必须显式设置fault_enabled字段默认不启用既不设默认值也不设 runtime key 时故障不生效。示例配置完整示例见 redis-fault-injection.yamlstatic_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 6379 filter_chains: - filters: - name: envoy.filters.network.redis_proxy typed_config: type: type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy stat_prefix: redis_stats prefix_routes: catch_all_route: cluster: redis_cluster settings: op_timeout: 5s faults: - fault_type: ERROR fault_enabled: default_value: numerator: 10 denominator: HUNDRED runtime_key: bogus_key commands: - GET - fault_type: DELAY fault_enabled: default_value: numerator: 10 denominator: HUNDRED runtime_key: bogus_key delay: 2s该配置创建两条故障一条仅作用于 GET 命令的错误故障10%一条作用于所有命令的延迟故障10%。按上文叠加规则20% 的 GET 命令会被注入故障。从实现看faults配置在过滤器工厂中被组装为FaultManagerImpl并交给命令拆分器持有见 config.cc延迟/错误的实际执行发生在拆分器路由命令的链路上这也解释了为什么延迟统计中的latency直方图包含延迟故障时间。另外proto 中RedisFault.commands字段注释指出未指定commands时故障作用于除 AUTH 与 PING 之外的所有命令因为这两个命令在 Envoy 内部有专门处理路径。RESP 协议版本protocol_versionprotocol_version字段见 redis_proxy.proto定义监听器使用的 RESP 协议版本且该值同时约束下游客户端连接与所有被路由的上游连接池——不存在按集群单独设置 RESP 版本的旋钮也没有跨集群的隐式最低版本。在上游路由的数据路径上下游与上游使用同一 RESP 版本本地生成的响应——AUTH/QUIT/NOPROTO——按下游协商出的版本编码。RESP2默认protocol_version未设置或为RESP2默认时协商出的线上版本为 RESP2不向上游发送HELLO 3下游的HELLO 3会被以-NOPROTO拒绝。需要强调的是RESP3 感知能力本地HELLO应答、CLIENT SETINFO/SETNAME的接受、RESP3 解码器无论该值取什么都始终存在RESP2只控制协商出的线上版本。RESP3 模式的行为约定当protocol_version为RESP3时上游必须支持 RESP3。所有被路由的上游 Redis 兼容后端都必须支持HELLO 3/ RESP3Redis 6.0RESP3 的引入版本。配置错误时每条连接的 HELLO 3 协商都会失败表现为集群作用域下upstream_resp3_hello_failure计数器的递增。上游连接建立时发送 HELLO 3。上游客户端在每条新的上游连接上发送HELLO 3配置了静态凭据或 AWS IAM 认证时会与AUTH合并发送。协商完成前提交的用户请求会被缓冲在HELLO与对非 Primary 读策略需要的READONLY都成功后按序重放。若上游拒绝 RESP3连接被关闭缓冲中的请求在上游侧失败以便调用方在新连接上重试并重新协商。下游客户端必须先显式HELLO 3握手。在未协商 RESP3 的连接上除HELLO、AUTH、QUIT之外的任何命令都会被以-NOPROTO拒绝——包括未知命令。未知命令此时也显示为-NOPROTO而非拆分器惯常的ERR unknown command目的是让运维侧的错误信息始终指向客户端未完成握手而不是掩盖缺失握手的问题。裸HELLO与HELLO N都会与监听器的protocol_version做精确匹配在刚建立的 RESP3 监听器连接上发送裸HELLO会被拒绝因为连接当前版本默认2与要求的3不匹配HELLO 3成功后再发裸HELLO则确认reaffirm已协商的版本。HELLO 携带认证与本地合成响应下游HELLO N AUTH user pass既支持与本地配置的凭据downstream_auth_passwords/downstream_auth_username做匹配也支持与外部认证服务external auth provider交互后者会延迟往返并在认证服务响应后发出延迟的HELLOMap或错误。返回给下游客户端的HELLO响应是代理本地合成的不来自、也不反映任何上游 Redis 服务器。多个字段因此是固定的代理特定值而非后端值server为envoy-redis-proxy、version是固定的 Redis 兼容版本号6.0.0为客户端库兼容性而宣告而非 Envoy 构建版本、id为0、mode为standalone、role为master、modules为空。只有proto是动态的——它反映协商出的版本2或3。依赖这些字段的客户端例如按server版本号或连接id做行为分支的客户端不应期望它们与数据命令实际路由到的上游 Redis 一致。代理不在 RESP2 与 RESP3 之间做上游响应的交叉编码。由于监听器强制上游路由数据路径使用单一 RESP 版本上游响应总是以它到达时的 RESP 版本原样发往下游不做透明重构例如 RESP3 Map → 扁平 RESP2 数组从而避免ZRANGE WITHSCORES这类命令在 RESP3 下返回嵌套成对数组、RESP2 下返回扁平数组的结构分歧。唯一的例外是跨分片聚合的集群作用域命令例如 Redis Cluster 上的CONFIG GET与KEYS它们的响应总是以扁平数组发出即便某个 RESP3 上游分片返回的是 Map。将分片响应聚合进一个 Map 会迫使客户端处理跨分片的重复键因此对 RESP2 与 RESP3 下游都发出稳定的扁平数组。MOVED/ASK 重定向上的 DNS 解析架构概览中说明过当 Envoy 看到包含主机名的 MOVED 或 ASK 响应时默认不做 DNS 解析而是把错误原样冒泡给客户端。以下配置开启了对此类响应的 DNS 解析从而避免客户端收到错误、由 Envoy 自身完成重定向完整示例见 redis-dns-lookups.yamlstatic_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 6379 filter_chains: - filters: - name: envoy.filters.network.redis_proxy typed_config: type: type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy stat_prefix: redis_stats prefix_routes: catch_all_route: cluster: redis_cluster settings: op_timeout: 5s enable_redirection: true dns_cache_config: name: dns_cache_for_redis dns_lookup_family: V4_ONLY max_hosts: 100对应字段说明见 ConnPoolSettingsenable_redirection默认 false接受上游 Redis 服务器返回的 MOVED/ASK 重定向错误并重试到目标服务器目标服务器无需被集群管理器知晓若命令无法重定向原始错误原样向下游传递dns_cache_configenable_redirection为 true 时配置连接池用于解析 MOVED/ASK 响应中主机名的 DNS 缓存。若不提供该配置则不做 DNS 解析MOVED/ASK 错误原样传给用户max_upstream_unknown_connections控制任意给定 worker 线程对未知主机可创建的在途上游连接上限默认 100达到上限时重定向失败原始重定向错误原样下发。上游 Redis 认证Redis proxy 过滤器支持对上游 Redis 集群进行认证。当配置了多个上游集群时它们可以使用同一组用户名/密码也可以按集群分别配置只要凭据能与对应集群关联过滤器会分别正确认证。两种方式对应 RedisProtocolOptions 消息所有上游集群共用同一凭据使用集群typed_extension_protocol_options中RedisProtocolOptions顶层的auth_username与auth_password按端点分别配置凭据使用RedisProtocolOptions顶层的credentials字段。每条Credential的address字段用于把凭据关联到load_assignment.endpoints.lb_endpoints.endpoint中的具体上游端点两处的address取值必须一致且该模式只支持 socket 地址。若credentials中没有与某端点匹配条目则回退使用顶层auth_password/auth_username作为默认值同一address有多条条目时取第一条。完整示例见 redis-upstream-auth.yamlstatic_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 6379 filter_chains: - filters: - name: envoy.filters.network.redis_proxy typed_config: type: type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy stat_prefix: egress_redis settings: op_timeout: 5s prefix_routes: catch_all_route: cluster: redis_cluster clusters: - name: redis_cluster connect_timeout: 1s type: STRICT_DNS load_assignment: cluster_name: redis_cluster endpoints: - lb_endpoints: - endpoint: address: socket_address: address: endpoint_1 port_value: 6380 - endpoint: address: socket_address: address: endpoint_2 port_value: 6381 - endpoint: address: socket_address: address: endpoint_3 port_value: 6382 typed_extension_protocol_options: envoy.filters.network.redis_proxy: type: type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProtocolOptions auth_username: inline_string: default_username auth_password: inline_string: default_password credentials: - address: socket_address: address: endpoint_1 port_value: 6380 auth_username: inline_string: endpoint_1_username auth_password: inline_string: endpoint_1_password - address: socket_address: address: endpoint_2 port_value: 6381 auth_username: inline_string: endpoint_2_username auth_password: inline_string: endpoint_2_password - address: socket_address: address: endpoint_3 port_value: 6382 auth_username: inline_string: endpoint_3_username auth_password: inline_string: endpoint_3_passwordRedisProtocolOptions挂在集群的typed_extension_protocol_options下键名为envoy.filters.network.redis_proxy。AWS IAM 认证ElastiCache / MemoryDBRedis proxy 过滤器还支持使用 AWS IAM 凭据认证到 ElastiCache 与 MemoryDB 实例相关字段提供在集群的 Redis 设置中即上一节的typed_extension_protocol_options。要点对照 AwsIam 消息定义region未指定时region 会按 AWS 区域提供者链推断cache_name必填设置为你的 cache 名称auth_username与cache_name都会参与 IAM 认证令牌的计算auth_password在 AWS IAM 配置中不被使用密码值由 Envoy 自动计算上游集群中auth_username字段必须配置为已加入你 cache 的用户按 AWS 侧 IAM 认证 Setup 流程创建 IAM-enabled 用户不同上游可以使用不同用户名与不同 cache 名称凭据会按流量目标集群正确生成service_name对 valkey 或 Redis OSS 模式的 ElastiCache cache 应为elasticache对 MemoryDB 集群应为memorydb。service_name与关联 IAM 策略中添加的服务一致——例如service_name: memorydb对应包含memorydb:ConnectAction 的 AWS IAM 策略且该策略必须附加到 Envoy 所使用的 IAM principal 上proto 中还定义了credential_provider可指定具体的 AWS 凭据提供者链或特定提供者设置与expiration_timeIAM 令牌到期秒数默认 60s最大 900s到期后自动触发新令牌生成。配置示例见 redis-aws-iam-auth.yamlstatic_resources: listeners: - name: listener_0 address: socket_address: address: 0.0.0.0 port_value: 6379 filter_chains: - filters: - name: envoy.filters.network.redis_proxy typed_config: type: type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxy stat_prefix: egress_redis settings: op_timeout: 5s prefix_routes: catch_all_route: cluster: redis_cluster clusters: - name: redis_cluster connect_timeout: 1s type: STRICT_DNS load_assignment: cluster_name: redis_cluster endpoints: - lb_endpoints: - endpoint: address: socket_address: address: testcache-7dh4z9.serverless.apse2.cache.amazonaws.com port_value: 6379 typed_extension_protocol_options: envoy.filters.network.redis_proxy: type: type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProtocolOptions auth_username: inline_string: test aws_iam: region: ap-southeast-2 service_name: elasticache cache_name: testcache expiration_time: 900s从工厂实现看AWS IAM 认证器在过滤器构建阶段逐集群装配config.cc 对prefix_routes中出现的每个唯一集群检查其是否携带AwsIam元素若存在且顶层auth_username非空则通过AwsIamAuthenticatorFactory::initAwsIamAuthenticator为该连接池创建认证器若缺少auth_username则输出警告No auth_username found for cluster {}, AWS IAM Authentication will be disabled for this cluster并禁用该集群的 IAM 认证。实现结构与源码索引结合仓库源码结构Redis proxy 过滤器的核心实现集中在 source/extensions/filters/network/redis_proxy/ 目录config.cc过滤器工厂。收集路由涉及的全部唯一集群含镜像与读命令策略集群为每个集群创建ConnPool::InstanceImpl注入集群统计作用域cluster.name.redis_cluster、DNS 缓存、AWS IAM 认证器、监听器级protocol_version组装PrefixRoutes路由器、FaultManagerImpl与命令拆分器最终为每个下游连接挂接ProxyFilter读过滤器。外部认证服务external_auth_provider的 gRPC 客户端同样在此创建默认超时 200msproxy_filter.cc / proxy_filter.h下游连接的解码/编码与统计计数入口redis.stat_prefix.*过滤器级统计在此维护command_splitter_impl.cc命令拆分与路由splitter.*统计及按命令统计在此收集故障注入也在这条链路上生效conn_pool_impl.cc / router_impl.cc上游连接池含 MOVED/ASK 重定向、读策略路由与前缀路由匹配external_auth.cc外部 gRPC 认证客户端对应RedisExternalAuthProvider配置共享的客户端、编解码器与 AWS IAM 实现位于 source/extensions/filters/network/common/redis/如aws_iam_authenticator_impl.h、RESP 编解码器。API 定义统一在 redis_proxy.proto关键消息为RedisProxy监听器级配置含stat_prefix、settings、prefix_routes、faults、protocol_version、下游认证与custom_commands等 12 个字段、RedisProtocolOptions集群级认证含credentials与aws_iam与AwsIam。测试用例覆盖在 test/extensions/filters/network/redis_proxy/ 目录验证路由、故障注入、重定向等行为的正确性。适用前提与限制小结本文所有配置基于当前仓库中 v3 APIenvoy.extensions.filters.network.redis_proxy.v3过滤器注册名为envoy.filters.network.redis_proxy另保留旧名envoy.redis_proxy的兼容注册见 config.ccprotocol_version: RESP3要求所有被路由的上游后端支持 RESP3Redis 6.0上游配置错误时以upstream_resp3_hello_failure计数器暴露缓冲中的下游请求随连接关闭而失败故障注入的百分比正确性由用户负责过滤器不做运行时校验延迟注入受命令顺序约束会级联延迟后续请求按端点区分凭据credentials字段仅支持 socket 地址且必须与集群lb_endpoints中的地址逐字段一致latency_in_micros只影响过滤器级按命令延迟统计不影响上游命令统计的单位。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表