2024-12-20 11:31:33
在微服务架构中,API 网关通常需要对请求和响应进行高级别的处理,如身份验证、数据转换和安全检查。Envoy 提供的 ext_proc
外部处理过滤器,是一个强大的工具,通过与 gRPC 服务交互,实现灵活的请求与响应处理。本文将深入解析该过滤器的功能、配置与性能优化策略,帮助开发人员和 DevOps 工程师高效应用该特性。
ext_proc
和 Envoy 中的其他 gRPC 接口过滤器(如 ext_authz
)在功能上有相似之处,但 ext_proc
提供了更强大的功能,支持完整的请求和响应处理。这使其特别适用于需要深度内容检查和修改的应用场景。
你可以通过下面的 Envoy 外部处理过滤器思维导图快速了解 ext_proc
。
这张思维导图展示了 Envoy ext_proc
外部处理过滤器的核心结构和功能模块。ext_proc
通过 gRPC 双向流协议与外部服务交互,可灵活处理 HTTP 请求和响应的各个阶段,并支持同步与异步处理。
ext_proc
是 Envoy 提供的 HTTP 过滤器,支持将请求和响应外包给 gRPC 服务进行处理,允许在外部服务中实现复杂的逻辑,灵活应对业务需求。例如,在安全场景中,ext_proc
可用于执行身份验证和授权检查;在数据转换场景中,可以实现数据格式转换与内容过滤。此外,还可用于记录审计日志、动态请求重写以及内容增强等功能,适用于各种企业应用环境中的深度流量管理。
ext_proc
使用双向 gRPC 流与外部服务通信,实现请求和响应处理的实时交互。这使得 Envoy 可以将复杂任务(如身份验证、数据转换和自定义 Header 操作)卸载到外部服务,从而提高灵活性和可扩展性。
Envoy 发送 ProcessingRequest
消息,外部服务返回 ProcessingResponse
消息。需要注意的是,每个 HTTP 请求流都会创建一个独立的 gRPC 流,而不会在多个请求之间共享。每个由 Envoy 处理的 HTTP 请求都会创建其专属的 gRPC 流,从而确保请求与响应的隔离和精确管理。
这种设计允许外部服务在请求与响应生命周期的不同阶段进行干预,甚至能够生成全新的响应内容。``
下图概述 Envoy 外部处理过滤器的处理过程:
以下是一个基本的 Envoy 配置示例:
static_resources:
listeners:
- name: listener_0
address:
socket_address:
protocol: TCP
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
log_format:
text_format: "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% \"%RESP(X-EXTPROC-HELLO)%\" \"%RESP(CONTENT-TYPE)%\" \"%RESP(CONTENT-LENGTH)%\" %DURATION% ms\n"
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: [ "*" ]
routes:
- match:
prefix: "/"
route:
host_rewrite_literal: www.envoyproxy.io
cluster: service_envoyproxy_io
http_filters:
- name: envoy.filters.http.ext_proc
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_proc.v3.ExternalProcessor
grpc_service:
envoy_grpc:
cluster_name: ext_proc_cluster
failure_mode_allow: true
processing_mode:
request_header_mode: SKIP
response_header_mode: SEND
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: ext_proc_cluster
connect_timeout: 0.25s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: ext_proc_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 9000
- name: service_envoyproxy_io
type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
load_assignment:
cluster_name: service_envoyproxy_io
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.envoyproxy.io
port_value: 443
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
sni: www.envoyproxy.io
为了理解 Envoy 配置与 gRPC 服务之间的关联,我们需要了解以下配置项如何影响流量处理:
ext_proc_cluster
。ext_proc
和 router
。详细的配置说明请参考 Envoy 文档。
Envoy 使用这些配置选项将请求和响应外包给 gRPC 服务,处理结果通过双向流协议返回,影响请求的转发行为。
以下是一个简单的 gRPC 外部处理服务器实现,演示如何通过 ext_proc
添加自定义响应头。该实现展示了核心方法的选择和设计决策,例如使用 Process
方法持续接收请求和发送响应,确保处理过程的连续性。此外,采用 HeaderMutation
配置修改 HTTP 响应头,展现了 gRPC 消息结构与 Envoy 配置的紧密集成,便于动态扩展和灵活管理。
package main
import (
"log"
"net"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
configPb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
extProcPb "github.com/envoyproxy/go-control-plane/envoy/service/ext_proc/v3"
)
type extProcServer struct {
extProcPb.UnimplementedExternalProcessorServer
}
// Process handles external processing requests from Envoy.
// It listens for incoming requests, modifies response headers,
// and sends the updated response back to Envoy.
//
// When a request with response headers is received, it adds a custom header
// "x-extproc-hello" with the value "Hello from ext_proc" and returns the modified headers.
//
// Note: The `RawValue` field is used instead of `Value` because it supports
// setting the header value as a byte slice, allowing precise handling of binary data.
//
// This function is called once per HTTP request to process gRPC messages from Envoy.
// It exits when an error occurs while receiving or sending messages.
func (s *extProcServer) Process(
srv extProcPb.ExternalProcessor_ProcessServer,
) error {
for {
req, err := srv.Recv()
if err != nil {
return status.Errorf(codes.Unknown, "error receiving request: %v", err)
}
log.Printf("Received request: %+v\n", req)
// Prepare the response to be returned to Envoy.
resp := &extProcPb.ProcessingResponse{}
// Only process response headers, not request headers.
if respHeaders := req.GetResponseHeaders(); respHeaders != nil {
log.Println("Processing Response Headers...")
resp = &extProcPb.ProcessingResponse{
Response: &extProcPb.ProcessingResponse_ResponseHeaders{
ResponseHeaders: &extProcPb.HeadersResponse{
Response: &extProcPb.CommonResponse{
HeaderMutation: &extProcPb.HeaderMutation{
SetHeaders: []*configPb.HeaderValueOption{
{
Header: &configPb.HeaderValue{
Key: "x-extproc-hello",
RawValue: []byte("Hello from ext_proc"),
},
},
},
},
},
},
},
}
log.Printf("Sending response: %+v\n", resp)
// Send the response back to Envoy.
if err := srv.Send(resp); err != nil {
return status.Errorf(codes.Unknown, "error sending response: %v", err)
}
} else {
// If it is not a callback in the response header stage, do not make any modifications and continue processing the next event.
// For request_headers or other events, do not modify & ensure that Envoy will not be stuck.
// An empty processing can be returned for request_headers, or it can be skipped in envoy.yaml.
// Here, simply continue to wait for the next event.
continue
}
}
}
func main() {
lis, err := net.Listen("tcp", ":9000")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
// Register the ExternalProcessorServer with the gRPC server.
extProcPb.RegisterExternalProcessorServer(grpcServer, &extProcServer{})
log.Println("Starting gRPC server on :9000...")
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("Failed to serve: %v", err)
}
}
预期结果:请求返回状态码 200,响应头中包含自定义头 x-extproc-hello: Hello from ext_proc
。如果缺少该头,检查以下内容:
:9000
。ext_proc
过滤器已启用,并且 ext_proc_cluster
配置无误。在本地运行 Envoy 和 gRPC 服务后,使用 curl
进行测试:
envoy -c envoy.yaml
go run main.go
curl -v http://localhost:8080
你将看到包含自定义头 x-extproc-hello: Hello from ext_proc
的响应。
你将看到如下图所示的结果。
在 curl 请求的响应中包含了我们自定义的 header x-extproc-hello: Hello from ext_proc
。
ext_proc
输出的统计信息位于 http.<stat_prefix>.ext_proc.
命名空间,其中 stat_prefix
是 HTTP 连接管理器的前缀。常用统计信息包括:
指标名称 | 类型 | 描述 |
---|---|---|
streams_started | Counter | 启动的 gRPC 流数量 |
streams_msgs_sent | Counter | 发送的消息数量 |
streams_msgs_received | Counter | 接收的消息数量 |
spurious_msgs_received | Counter | 接收的违反协议的意外消息数量 |
streams_closed | Counter | 成功关闭的流数量 |
streams_failed | Counter | 产生 gRPC 错误的流数量 |
failure_mode_allowed | Counter | 错误被忽略的次数(根据配置) |
message_timeouts | Counter | 配置超时内未收到响应的消息数量 |
rejected_header_mutations | Counter | 被拒绝的头部更改数量 |
clear_route_cache_ignored | Counter | 忽略的清理路由缓存请求数量 |
clear_route_cache_disabled | Counter | 被禁用的清理路由缓存请求数量 |
详见 Envoy 文档。
故障恢复与负载均衡:部署多实例 gRPC 服务,使用负载均衡自动转移请求。
消息超时与重试配置:
http_filters:
- name: envoy.filters.http.ext_proc
config:
grpc_service:
envoy_grpc:
cluster_name: ext_proc_server
processing_mode:
request_header_mode: SEND
response_header_mode: SEND
message_timeout: 500ms
max_message_timeout: 1000ms
failure_mode_allow: false
元数据选项与安全策略:
metadata_options:
forwarding_namespaces:
untyped: ["custom_namespace"]
Envoy 的 ext_proc
过滤器通过灵活的请求和响应处理能力,为微服务架构中的服务治理、数据转换和请求检查提供了强大的支持。正确配置和优化 ext_proc
可以显著提高系统的灵活性和可扩展性,满足多样化的业务需求。
2024-12-12 18:44:52
在 Istio Ambient 模式下,ztunnel 是节点级安全代理,在 L4 层拦截并加密服务间流量。但不负责 L7(如 HTTP)层处理。Ambient 模式中,L7 处理由 Waypoint 代理负责。当 ztunnel 发现目标服务需 L7 处理时,通过 HBONE 协议将流量转发给 Waypoint 代理进行 HTTP 层策略应用和可观察性处理,再由 Waypoint 代理经 ztunnel 转发给目标 Pod,本文将详细阐述这条 L7 流量转发链路。
在 Istio Ambient 模式中:
ztunnel 负责透明捕获 Pod 间的 L4 流量,提供 mTLS 加密和身份认证。
Waypoint 代理 是一个基于 Envoy 的 L7 代理,处理 HTTP 层的高级路由、策略和可观察性。
当一个请求需要 L7 层策略时(如 productpage
调用 reviews-v1
服务),ztunnel 将流量通过 HBONE 隧道转发到 Waypoint Proxy,由 Waypoint 执行 HTTP 路由和策略。
下图展示了 L7 流量在 Ambient 模式中的处理路径。
下面两张图片分别展示了源 Pod 和目标 Pod 在同节点和跨节点情况下的 L7 流量处理路径。
下面是详细的流量路径。
假设 productpage 应用需要访问 reviews 服务。productpage Pod 内的应用向 reviews.default.svc.cluster.local:9080
发起 HTTP 请求。
productpage Pod 的出站请求首先被所在节点上的 ztunnel 拦截。ztunnel 查看从 Istio 控制面下发的配置,根据目标服务(reviews)的身份和策略,得知该服务需要经过 Waypoint 代理进行 L7 层处理。
ztunnel 并非使用传统的 Envoy-to-Envoy XDS 或原生 TCP+mTLS 隧道,而是通过 HBONE 协议 与 Waypoint 代理通信。HBONE 是 Istio Ambient 模式中专门设计的无 Sidecar L7 路由协议,基于 HTTP/2,可在透明模式下对流量进行叠加转发,从而实现灵活的服务拓扑和策略控制。
在这一阶段,ztunnel 会将 L4 流量封装到 HBONE 隧道中,发送给相应的 Waypoint 代理。
Waypoint 代理(目前仍基于 Envoy 实现)收到通过 HBONE 隧道传来的流量后,通过 TLS 配置和客户端证书校验,确保下游(ztunnel)是已被认证的受信主体。它将下游客户端的身份信息(SPIFFE ID)和其他上下文元数据提取出来,以便在 L7 层策略决策中使用。
执行的操作包括:
完成 L7 处理后,Waypoint 代理再通过 HBONE 将流量传回到目标节点的 ztunnel。
目标节点上的 ztunnel 会从 Waypoint 代理接收处理过的流量(同样通过 HBONE 隧道传递),然后解封装并将流量传递给对应的 reviews Pod 中的应用容器端口。
15008
。iptables
规则将流量透明重定向到 ztunnel。在 Ambient 模式下,调试方式也有了一些变化:
ztunnel 调试:
istioctl ztunnel
子命令来协助查看和调试 ztunnel 的配置与状态。waypoint 调试:
istioctl pc
和 istioctl ps
来查看其路由、集群和监听器配置。istioctl waypoint
提供了更直观的配置查看和状态检查功能。Istio Ambient 模式通过 ztunnel 来处理 L4 流量并实现零信任加密与传输,再通过 Waypoint 代理为需要 L7 策略的请求提供集中处理。两者之间通过 HBONE 协议进行高效、透明的通信,实现比传统 Sidecar 模式更轻量且易于运维的架构。
2024-12-11 21:50:21
随着大语言模型(LLM)的快速发展,将企业内部知识库与 AI 工具结合成为热门解决方案。作为一名技术探索者,我对构建私有知识库充满兴趣,也希望测试 LLM 的能力,尤其是像 Ollama 和千问这类模型。此外,AnythingLLM 是一个开源项目,具有较高的社区关注度,因此我决定对其进行深入调研。
基于 RAG(检索增强生成)技术,AnythingLLM 提供了从数据处理到用户界面的全栈解决方案,支持构建企业内部的智能知识库。其模块化架构和灵活部署方式,使其成为企业和个人开发者进行知识管理和 AI 项目实践的重要工具。
RAG(Retrieval-Augmented Generation) 是一种结合了信息检索和语言模型的技术。它通过从大规模的知识库中检索相关信息,并利用这些信息来指导语言模型生成更准确和深入的答案。这种方法由 Meta AI 研究人员在 2020 年提出,旨在解决大型语言模型在信息滞后、模型幻觉、私有数据匮乏和内容不可追溯等问题。
RAG 就是可以开卷回复的 LLM。其发展历程:Naive RAG 包含索引、检索、生成三步,存在 召回率低、Prompt 拼接问题。Advanced RAG 优化索引与检索,引入 预检索、后检索策略与数据清洗 提升效率。Modular RAG 实现 模块化流水线与端到端训练,具备更高的 灵活性与适应性。
尽管 LLM 在处理复杂任务方面表现出色,但在以下三个方面存在局限:
RAG 技术通过向量检索与生成模型结合,显著提高了数据处理的深度和准确性。
RAG 的工作流程包括两个主要阶段:
数据准备阶段
用户应用阶段
通过这种方式,RAG 可以搭建团队内部的本地知识库,弥补大模型的知识局限性,解决幻觉和数据隐私问题。然而,RAG 也存在一些主要限制:
数据依赖性强:RAG 系统的效果严重依赖于内置知识库的数据质量和覆盖范围。
检索准确性受限:检索算法可能因索引构建不完善或查询表达模糊导致相关性降低。
模型推理成本高:大型语言模型的推理消耗大量资源,尤其在频繁查询和大规模应用场景中。
技术复杂度高:构建和维护 RAG 系统需要强大的数据管理与模型集成能力,涉及嵌入、索引构建和检索优化等多个复杂组件。
响应延迟与性能瓶颈:在高负载下,检索与推理过程可能导致响应速度变慢,尤其在硬件性能受限的环境中。
AnythingLLM 是 Mintplex Labs Inc. 开发的一款开源 ChatGPT 等效工具,用于在安全的环境中与文档进行交互。它融合了从数据处理到用户界面的所有技术,适用于构建个人或企业私有化的知识库。
要在 AnythingLLM 中构建一个私有知识库,可以按照以下步骤操作:
上传文档:将 PDF、TXT、DOCX、JSON 等支持的文档格式上传到系统中。
嵌入向量生成(Embedding):
存储到向量数据库:
查询与回答:
通过该流程,可以有效构建支持高效查询和生成回答的智能知识库。
参考:Docker 安装指南
export STORAGE_LOCATION=$HOME/anythingllm && \
mkdir -p $STORAGE_LOCATION && \
touch "$STORAGE_LOCATION/.env" && \
docker run -d \
--cap-add SYS_ADMIN \
--network host \
--add-host=host.docker.internal:host-gateway \
-v ${STORAGE_LOCATION}:/app/server/storage \
-v ${STORAGE_LOCATION}/.env:/app/server/.env \
-e STORAGE_DIR="/app/server/storage" \
mintplexlabs/anythingllm
注意:使用 host network,否则容器中无法与 Ollama 通信。
若要在本机运行 Ollama,可以使用下面的命令:
ollama run qwen2.5:14b --keepalive 0
这将会运行 qwen2.5:14b,你也可以选择其他大模型。
打开浏览器:http://localhost:3001
注意:必须选择要接入的 LLM,可以使用
local
或cloud
AnythingLLM 内置的 LLM 引擎支持下载流行的模型如 LLama-3、Phi-3 等,支持 CPU 和 GPU。本地运行适用于试用其基本功能。
参考:Desktop 安装概览
局限性:缺少多用户支持、浏览器插件、用户和 Workspace 管理等功能。
如果你的电脑性能堪忧的话,强烈不建议你在本地运行大模型。你会遇到各种性能问题,例如下面看到的,在上传文件嵌入到 Workspace 时卡住了。
Failed to execute query stream: Invalid input, No vector column found to match with the query vector dimension: 4096
。
使用商用大模型 API:
优化硬件环境:
调整 AnythingLLM 配置:
分布式部署与扩展:
升级数据库存储方案:
代码优化与插件扩展:
AnythingLLM 是一个功能全面的 RAG 解决方案,适用于企业内部知识库构建。通过结合向量检索与大语言模型,该平台提供了强大的文档问答能力。然而,部署和定制化需要一定的技术投入。未来的改进方向包括增强多数据库支持、更灵活的嵌入模型选择以及提升文档解析能力。
2024-12-11 15:04:01
Istio 的 Telemetry API 是替代传统 MeshConfig 遥测配置的现代化方式,提供了更灵活的工具来定义服务网格中的 Tracing、Metrics 和 Access Logging。相比传统的 EnvoyFilter
和 MeshConfig
,Telemetry API 更具模块化、动态更新和跨层次配置能力。
在本篇中,我们将详解如何使用 Telemetry API 配置 Istio 遥测功能,涵盖 Tracing、Metrics 和 Logging 的具体实现,同时展示如何迁移过时的 MeshConfig 配置。
Istio 的遥测能力在早期版本中依赖于较为传统的配置方法,如 Mixer 和 MeshConfig 的 configOverride
,这些方法虽然能够满足基本需求,但在复杂场景下显得力不从心。为了解决这些问题,Istio 引入了基于 CRD 的 Telemetry API。
为了帮助读者了解 Telemetry API 的进化过程,以下是一些重要版本的更新信息:
EnvoyFilter
,完全依赖 Telemetry API 定义遥测行为。尽管传统的 MeshConfig 和 EnvoyFilter 提供了基础的遥测能力,但它们的配置方式在灵活性、动态性和扩展性方面存在诸多限制。为了更清晰地理解这些局限性,我们将从几个关键维度展开说明。
在介绍具体问题之前,我们先了解一下 MeshConfig 和 EnvoyFilter 的定位:MeshConfig 适用于全局配置,而 EnvoyFilter 用于细粒度的自定义。但正是这种分工,导致了它们在管理上的复杂性。
MeshConfig 用于集中定义全局网格行为,例如访问日志路径、追踪采样率和指标维度。虽然适合简单场景,但无法满足命名空间级或工作负载级的需求。
EnvoyFilter 则可以覆盖或扩展 Envoy 的配置,允许更细粒度的控制。但这种方式直接操作 Envoy 内部结构(xDS 字段),配置语言复杂且容易出错。
示例:通过 MeshConfig 配置访问日志
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogFile: /dev/stdout
问题:
示例:通过 EnvoyFilter 自定义指标
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: custom-metric-filter
namespace: mynamespace
spec:
workloadSelector:
labels:
app: myapp # 选择特定的工作负载
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND # 匹配入站流量
patch:
operation: ADD
filterClass: STATS # 指定为统计过滤器
value:
name: istio.request_operation # 自定义指标名称
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
value:
config:
configuration: |
"attributes": [
{
"output_attribute": "istio_operationId",
"match": [
{
"value": "GetReviews",
"condition": "request.url_path == '/reviews' && request.method == 'GET'"
}
]
}
]
vm_config:
runtime: envoy.wasm.runtime.null
code:
local: { inline_string: "envoy.wasm.attributegen" }
问题:
虽然现代微服务环境强调动态调整配置,但 MeshConfig 和 EnvoyFilter 的动态性支持有限:
在多租户环境中,针对不同命名空间或工作负载自定义遥测配置非常重要。然而:
鉴于上述局限性,Istio 社区已经将传统的 MeshConfig 遥测配置标记为弃用。以下示例展示了这些配置的使用方式及其不足之处:
Access Logging 配置:
meshConfig:
accessLogFile: /dev/stdout
Trace Sampling 配置:
meshConfig:
enableTracing: true
extensionProviders:
- name: zipkin
zipkin:
service: zipkin.istio-system.svc.cluster.local
port: 9411
自定义 Metrics 标签:
meshConfig:
telemetry:
v2:
prometheus:
configOverride:
inboundSidecar:
metrics:
- name: requests_total
dimensions:
user-agent: request.headers['User-Agent']
通过上述例子可以看出,这些配置的灵活性和扩展性明显不足,难以应对复杂的生产环境需求。
在传统配置方式的基础上,Telemetry API 带来了多项改进,使其更适合现代化的服务网格管理需求:
为帮助理解 Telemetry API 的具体使用,我们以全局配置示例作为开始:
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: mesh-default
namespace: istio-system
spec:
accessLogging:
- providers:
- name: envoy # better to use a built-in one
tracing:
- providers:
- name: "skywalking"
randomSamplingPercentage: 100.00
metrics:
- overrides:
- match:
metric: REQUEST_COUNT
mode: CLIENT
tagOverrides:
x_user_email:
value: |
'x-user-email' in request.headers ? request.headers['x-user-email'] : 'empty'
providers:
- name: prometheus
我们再以配置 SkyWalking 的采样率和 span tag 为例,演示如何使用 Telemetry API。
telemetry.istio.io/v1
。telemetry.istio.io/v1alpha1
。通过以下命令检查 Telemetry API 的 CRD 是否已安装:
kubectl get crds | grep telemetry
在集群中部署 SkyWalking OAP 服务:
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/addons/extras/skywalking.yaml
检查服务状态:
kubectl get pods -n istio-system -l app=skywalking-oap
在 Istio 的 MeshConfig
中定义 SkyWalking 提供商。
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |-
enableTracing: true
extensionProviders:
- name: "skywalking"
skywalking:
service: "tracing.istio-system.svc.cluster.local"
port: 11800
通过 Telemetry API,将 SkyWalking 设置为默认的 Tracing 提供商,并定义采样率。
你可以从使用 Telemetry API 从多个层级配置采样率,为了节约篇幅,我们仅演示在命名空间范围配置采样率,其他层级的配置请参考 Telemetry API。
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: namespace-override
namespace: default
spec:
tracing:
- providers:
- name: skywalking
randomSamplingPercentage: 50
customTags:
env:
literal:
value: production
说明:
providers.name
:指定 SkyWalking 为默认的 Tracing 提供商。randomSamplingPercentage
:覆盖命名空间级别配置,设置 50% 的采样率。customTags
:为所有追踪数据添加 env=production
标签。访问网格中的服务(如 Bookinfo 示例应用)生成流量:
curl http://$GATEWAY_URL/productpage
查看追踪数据:
istioctl dashboard skywalking
打开浏览器访问 http://localhost:8080
,在追踪界面中查看生成的追踪信息。
点击一个span后,你可以看到其中的追加的 env: production
tag。
Telemetry API 通过其模块化设计、动态更新和多层级支持,大幅降低了服务网格中遥测配置的复杂性。相比 MeshConfig 和 EnvoyFilter,Telemetry API 是一套更灵活、高效的现代化解决方案。我们强烈推荐迁移到 Telemetry API,以充分利用其功能。
2024-12-04 09:46:07
韩国,是我去了一次,可能不会去第二次的国家。难怪韩国人喜欢往外跑,原来是因为他们国家真的没啥好玩的。虽然文化上有不少相似之处,但实际体验却让我感到复杂而矛盾。借着最近韩国发生的政治风波,写下这篇关于我去年韩国之行的记录,既是对旅行的回顾,也是对这个国家的一些思考。
2023 年 10 月,我从中国距离韩国最近的城市威海出发,仅需 1 小时的飞行便抵达仁川机场。韩国与中国一衣带水,但这却是我第一次踏上这片土地。之前,我曾去过两次日本,这两个与中国邻近的国家,旅行体验却有着天壤之别。
这次行程从仁川入境,先前往首尔,再坐火车南下釜山。在釜山停留较久后,返回首尔,从仁川飞回中国。
到达仁川机场后,我直接坐火车前往首尔。其间发生了一个小插曲。由于携带的行李较多,在仁川机场买火车票时弄丢了一件。眼看我要买票的那趟火车即将到来,我才发现行李少了一件。当时我火急火燎地出了站台,赶往机场到达大厅。但因为对环境不熟悉,找不到路。正在这时,火车进站检票处的工作人员问我是不是丢了行李。我跟他确认了行李内的物品和身份信息后,取回了丢失的行李,并使用之前购买的火车票重新进站。工作人员很热情,用流利的英语跟我对话。东西失而复得,而且是在火车即将开车之前找回,实在是庆幸。
在首尔的第一晚,我选择住在明洞。这里是一个繁华的商业区,同时也是许多抗议和文化活动的集中地。漫步在明洞街头,我还看到了大量的法轮功宣传。另外韩国还有大量的教会,我在釜山住的地方就靠近一个教会。这种对比让我对韩国的社会氛围有了更深的思考。
我的行程恰逢中秋节,韩国也放假。去南山塔的公交车站挤满了人,等了许久才上车。南山塔俯瞰整个首尔,但繁华和拥挤是我对这座城市最深的感受。
比起首尔,我更喜欢釜山的节奏。釜山依山傍海,有美丽的沙滩和繁忙的港口。这里让我想起家乡威海,但更加繁华,也更加国际化。釜山也是韩国与日本贸易的重要港口,这里的一切都洋溢着开放的气息。
在釜山旅行的一个亮点是购买了 Busan Pass,这种专为外国游客设计的旅行通票可以带你游览许多官方景点。釜山的乐天乐园是其中之一,既适合家庭游玩,又充满现代化气息。
另一个难忘的经历是在釜山国际电影节上近距离见到了周润发,并在电影节的特别放映中重温了经典电影《卧虎藏龙》。
行程的最后一天,我在仁川停留了一天,夜晚去了仁川登陆纪念公园。这是一个值得参观的地方,纪念了朝鲜战争期间联合国军队的仁川登陆战役。
历史建筑,景福宫像袖珍版的故宫,尤其是宫殿内的陈设,很像影视剧中拙劣的道具。但是韩国人还是不遗余力的推广自己的文化,很多白人、黑人穿着他们的传统服装在景福宫内拍照。
韩国的便利店里有很多种泡面,吃起来味道感觉一般,我个人更喜欢吃杯面。甚至在汉阳公园的 711 里还有专门泡面的机器。
韩国人喝咖啡真多,咖啡店到处都是,可以说咖啡流淌在韩国人的血液里了。最让我念念不忘的就是 blu shaak 咖啡,既便宜又好喝,这种咖啡有一种咸味。
韩国景福宫内随处可见的“中国文化”。
博物馆中很多介绍都只有韩文和英文,没有中文介绍。
韩餐部分吃起来还不错,不过大部分都是泡菜、酱汤、米饭、炸鸡、烤肉之类的,花样太少,远不如中国的饮食丰富,还没有早餐可以吃。
而且,在韩国便利店里买到的各种小零食,大多也不好吃,这点远不如日本,我觉得在日本的便利店里买到的东西口感都还不错。在韩国我就像一个文盲,一个韩文也不认识,而翻译软件经常翻译的莫名其妙,很多招牌和菜单上都没有英文或汉字,甚至连图片都没有,让人很无语。
总结这次韩国之行,虽然有些亮点,但总体体验不尽如人意。语言障碍、文化隔阂,以及相比之下单调的饮食和高昂的住宿费用,让我感到再来一次的动力不足。不过,釜山的电影节和咖啡,以及仁川的历史氛围,还是让我留下了些许回味的瞬间。
如果你没去过韩国,可以去体验一次;但对于我来说,这一次可能就是最后一次了。
2024-12-02 12:17:21
在服务网格架构不断演进的过程中,了解不同部署模式下的网络成本对于优化性能和资源效率至关重要。本文将对比 Istio 的 sidecar 模式和 ambient 模式的网络成本,分享我在这篇文章中的一些观点。
Istio 的 sidecar 模式通过在每个 pod 旁部署 sidecar 代理来拦截服务间的流量。这种架构引入了额外的网络跳转,可能会增加延迟和计算资源使用量。然而,该模式内置了重要的性能优化特性:本地性感知。
图 1 展示了 Application 1 在 Istio sidecar 模式下访问位于不同可用区(AZ)的 Application 2 的流量路径。
在 Sidecar 模式下,可以使用以下命令查看端点表中的本地性信息,从而更好地理解本地性管理:
istioctl proxy-config endpoint <pod-name[.namespace]> -o yaml
以下是一个示例输出片段,显示了集群 outbound|9080||reviews.default.svc.cluster.local
的端点信息:
- addedViaApi: true
circuitBreakers:
thresholds:
- maxConnections: 4294967295
maxPendingRequests: 4294967295
maxRequests: 4294967295
maxRetries: 4294967295
- maxConnections: 1024
maxPendingRequests: 1024
maxRequests: 1024
maxRetries: 3
priority: HIGH
edsServiceName: outbound|9080||reviews.default.svc.cluster.local
hostStatuses:
- address:
socketAddress:
address: 10.244.0.98
portValue: 9080
healthStatus:
edsHealthStatus: HEALTHY
locality:
region: us-central1
zone: us-central1-c
stats:
- name: cx_connect_fail
- name: cx_total
- name: rq_error
- name: rq_success
- name: rq_timeout
- name: rq_total
- name: cx_active
type: GAUGE
- name: rq_active
type: GAUGE
weight: 1
- address:
# 省略
- address:
# 省略
name: outbound|9080||reviews.default.svc.cluster.local
observabilityName: outbound|9080||reviews.default.svc.cluster.local;
从中可以看到 sidecar 模式下对 Envoy 代理对 pod 基于负载均衡的细粒度控制,例如 maxConnections
, maxRequests
, maxRetries
等 circuit breaker 配置,同时包含流量指标和健康状态。这些细节帮助在 Pod 级别管理流量的健康度、稳定性和延迟。
流量负载均衡考虑到 Locality,如 zone 和 region。Envoy 使用这些信息对流量执行更加精准的区域感知流量分配策略(如优先使用同一 zone 内的服务)。
每个 sidecar 代理都会优先将流量路由至同一可用区(AZ)或区域内的服务。这一设计减少了不必要的跨 AZ 流量,从而降低了由数据传输产生的高延迟和高成本。通过将流量限制在本地区域,sidecar 模式能够优化网络路径,避免跨区域的瓶颈。
尽管 sidecar 架构计算密集,但其本地性感知功能在维护高效流量路由方面起到了关键作用,尤其是在多区域云部署中,该功能有助于降低跨区域流量成本。
下图展示的 Istio ambient 模式的架构。
Istio ambient 模式包含两层:
Ztunnel 安全层(L3/L4 流量处理):在此模式下,ambient 模式仅依赖 zTunnel 进行流量管理,主要处理三层和四层的流量,即网络和传输层。这一方式可减少开销,确保基本的连接和安全要求得到满足。
Waypoint 代理层(L7 流量处理):此模式下引入了 waypoint 代理,以扩展至应用层流量,处理高级路由、观测性和策略执行。然而,waypoint 代理的部署位置对性能至关重要。为避免跨 AZ 流量,建议将 waypoint 代理分布于各个 AZ 内,以确保最佳性能。
相比之下,ambient 模式通过 ztunnel 和 waypoint 代理实现不同的架构。zTunnel 确保本地感知的流量路由,类似于 sidecar 模式,优先在同一 AZ 内路由流量,从而限制跨 AZ 流量并减少相应的网络成本。
图 3 展示了 Application 1 在 Istio ambient 模式下访问位于不同 AZ 的 Application 2 的流量路径。
注意:图中 Waypoint Proxy 为演示目的单独显示;在实际中,它并不绑定到特定节点,可以与 Ztunnel 同节点部署。
可以通过以下命令查看 Ambient 模式中 Ztunnel 的详细配置和流量分布:
istioctl ztunnel-config workload -o yaml
以下是一个示例输出:
- applicationTunnel:
protocol: ""
canonicalName: productpage
canonicalRevision: v1
clusterId: Kubernetes
hostname: ""
locality:
region: us-central1
zone: us-central1-c
name: productpage-v1-d5789fdfb-gmw5r
namespace: default
node: gke-cilium-default-pool-63a77182-f699
protocol: HBONE
serviceAccount: bookinfo-productpage
status: Healthy
trustDomain: cluster.local
uid: Kubernetes//Pod/default/productpage-v1-d5789fdfb-gmw5r
workloadIps:
- 10.28.2.14
workloadName: productpage-v1
workloadType: deployment
从中可以看到 ztunnel 隧道的本地化信息,ztunnel 可以对进出该节点所有 pod 的流量进行集中式管理,比如统一执行负载均衡、健康检查和区域感知等操作。
然而,waypoint 代理并非自动具有 AZ 感知功能。关键问题在于它们的部署位置。为优化成本与性能,waypoint 代理需要跨所有 AZ 进行扩展,以便本地处理流量。否则,可能导致跨 AZ 流量和额外成本。此外,当流量进入 waypoint 代理时,原始本地性信息可能被隐藏,进一步增加了路由优化的难度。
为优化性能和成本,建议 waypoint 代理在各个 AZ 内分布,以便能够本地处理流量。此外,ztunnel 与 waypoint 代理的通信设计为接近感知,从而确保流量被路由至最近的 waypoint 代理。这一特性进一步减少了跨 AZ 费用和延迟。
在对比 sidecar 和 ambient 模式时,为了更直观地理解本地性和路由行为,建议使用 Kiali dashboard。Kiali 能够直观展示不同模式下的流量路径,有助于理解 ambient 模式在复杂性上的表现。
在对比 Istio 的 sidecar 和 ambient 模式的网络成本时,两种架构都提供了本地性感知的路由以减少跨 AZ 流量。然而,sidecar 模式在每个代理的本地性管理上更加完善,而 ambient 模式需要谨慎管理 waypoint 代理以避免额外成本。此外,需要考虑 ambient 模式的两种子模式(有或无 waypoint 代理)来理解它们对网络成本和性能的不同影响。
如果希望深入了解四种主要的服务网格数据平面部署模式,建议阅读[深入解析服务网格的四种数据平面部署模式:性能、安全性与成本分析]/blog/service-mesh-data-plane-deployment-modes/)。