- 通过 HTTP/HTTPS,使用
X-ClickHouse-Replica-Tag请求头。 - 通过原生协议,使用 TLS 服务器名称指示 (SNI) 覆盖。
前置条件
- 你的服务需要有 2 个或更多副本。如果服务只有单个副本,就没有可固定到的副本。
- 需要 Enterprise 层级的服务。
- 此功能适用于标准 ClickHouse Cloud 服务以及 BYOC
配置副本感知路由
Enterprise 客户可在 ClickHouse Cloud 控制台的服务设置页面启用副本感知路由。打开你的服务,进入 Settings,然后为需要的接口打开相应开关:- 一个开关用于基于
X-ClickHouse-Replica-Tag请求头启用 HTTP 路由。 - 另一个开关用于基于 SNI override 启用原生协议路由。
基于 HTTP 的路由
要将工作负载固定到某个副本,请在 HTTPS 接口中发送X-ClickHouse-Replica-Tag 请求头。代理会根据请求头的值进行一致性哈希,因此只要副本数量不变,具有相同请求头值的请求就会被路由到同一副本。不同的值会独立进行哈希,可能会落到相同或不同的副本,但您无法指定某个值映射到哪个副本。
使用现有服务的主机名即可,无需使用特殊的粘性主机名或更改 DNS。请求头的值可以是您选择的任意字符串,例如应用程序名称、用户 ID 或工作负载标签。不带该请求头的请求仍会使用常规负载均衡。
在每个请求中设置 X-ClickHouse-Replica-Tag 请求头:
Protocol: clickhouse.HTTP,并通过 HttpHeaders 连接选项传入请求头。
X-ClickHouse-Replica-Tag 无需创建 ClickHouse HTTP 会话即可实现副本亲和性。并发请求可复用同一标签,不会触发 SESSION_IS_LOCKED。原生协议路由
使用原生协议时,将路由值以<routing-value>.sticky.<host> 形式的 TLS 服务器名称传入,并照常连接到常规的服务 hostname。ClickHouse Client 通过 --tls-sni-override 接收路由值:
--host 是常规的服务主机名,--secure 用于启用 TLS,--tls-sni-override 用于传递路由值。TLS 是必需的。无需额外的证书或 DNS 记录。
写后读一致性
在多副本 service 上,某个副本上的写入可能要等到 replication 追赶完成后,才能在其他副本上可见。发送写入时附带路由值,并在后续读取中复用同一个值。proxy 会将二者路由到同一个副本,因此即使其他副本仍有延迟,你也能读到自己刚写入的数据。该模式适用于写入后立即读回相同数据的工作负载,例如交互式应用,或在继续后续步骤前先 validate inserts 的 ETL jobs。 在 schema 变更尚未 replicated 完成时,这种方式同样有帮助:复用路由值 可以让 inserts 始终落在已具备新 schema 的副本上。 通过 HTTP 时,复用该请求头的值:select_sequential_consistency 设置为 1。
检查命中了哪个副本
使用相同的路由值再次运行其中一个SELECT hostName() 示例。只要副本数量不变,您应会获得相同的主机名。不同的路由值可能会映射到不同的副本。
副本感知路由的局限性
副本数量变化时粘性会改变
扩缩容会改变路由哈希环。共享同一路由值的请求可能会被路由到不同的副本。如果你依赖临时表或会话级设置,请准备在重新映射后重新创建它们。SELECT hostName() 始终可以告诉你当前所在的副本。
副本感知路由不是工作负载隔离
粘性路由只决定请求由哪个副本来处理,但该副本仍可能同时承载其他流量。若需专用计算资源,请使用计算资源分离。私有网络连接
基于 HTTP 的路由和基于原生协议的路由在常规服务主机名上均可与私有网络连接配合使用,无需额外添加 DNS 记录。原生协议路由需要 TLS
原生协议路由需要 TLS,因此请传入--secure。未加密的原生连接仍使用常规负载均衡。
故障排查
使用相同路由值的查询仍被路由到不同副本- 确认在服务设置页面上已为所使用的接口启用相应开关。HTTP 与原生方法需分别启用。
- 对于 HTTP,确认每个请求均包含
X-ClickHouse-Replica-Tag请求头,且每个请求使用的值完全一致。 - 对于原生协议,确认已设置
--secure,且--tls-sni-override的形式为<routing-value>.sticky.<host>。 - 启用后请稍候片刻,通常不到一分钟即可生效。
- 检查副本数量近期是否发生变化;扩缩容后发生重新映射属于预期行为。使用
SELECT hostName()查找新的映射关系。
- 确认
--host为常规的服务主机名,并且路由值是通过--tls-sni-override而非--host传递的。