Istio流量管理实现机制深度解析

4.4 Envoy代理深度解析:理解Istio数据平面的实现机制 本文深入解析了Istio数据平面核心组件Envoy的架构与工作机制。主要内容包括:Envoy作为Sidecar代理的核心功能(流量管理、负载均衡等);关键组件如Listener、Filter、Cluster和Route的配置与作用;Sidecar注入的自动/手动实现方式;流量拦截的iptables规则;Envoy配置查看与管理接口使用方法;以及连接池、超时等性能优化策略。通过本文,读者可以全面掌握Envoy在Istio中的实现机制和操作方法,为后续的Envoy配置实战奠定基础。 阅读详情

前言

Istio作为一个service mesh开源项目,其中最重要的功能就是对网格中微服务之间的流量进行管理,包括服务发现,请求路由和服务间的可靠通信。Istio实现了service mesh的控制面,并整合Envoy开源项目作为数据面的sidecar,一起对流量进行控制。

Istio体系中流量管理配置下发以及流量规则如何在数据面生效的机制相对比较复杂,通过官方文档容易管中窥豹,难以了解其实现原理。本文尝试结合系统架构、配置文件和代码对Istio流量管理的架构和实现机制进行分析,以达到从整体上理解Pilot和Envoy的流量管理机制的目的。

Pilot高层架构

Istio控制面中负责流量管理的组件为Pilot,Pilot的高层架构如下图所示:

Pilot Architecture(来自Isio官网文档[1])

 

根据上图,Pilot主要实现了下述功能:

统一的服务模型

Pilot定义了网格中服务的标准模型,这个标准模型独立于各种底层平台。由于有了该标准模型,各个不同的平台可以通过适配器和Pilot对接,将自己特有的服务数据格式转换为标准格式,填充到Pilot的标准模型中。

例如Pilot中的Kubernetes适配器通过Kubernetes API服务器得到kubernetes中service和pod的相关信息,然后翻译为标准模型提供给Pilot使用。通过适配器模式,Pilot还可以从Mesos, Cloud Foundry, Consul等平台中获取服务信息,还可以开发适配器将其他提供服务发现的组件集成到Pilot中。

标准数据面 API

Pilo使用了一套起源于Envoy项目的标准数据面API[2]来将服务信息和流量规则下发到数据面的sidecar中。

通过采用该标准API,Istio将控制面和数据面进行了解耦,为多种数据面sidecar实现提供了可能性。事实上基于该标准API已经实现了多种Sidecar代理和Istio的集成,除Istio目前集成的Envoy外,还可以和Linkerd, Nginmesh等第三方通信代理进行集成,也可以基于该API自己编写Sidecar实现。

控制面和数据面解耦是Istio后来居上,风头超过Service mesh鼻祖Linkerd的一招妙棋。Istio站在了控制面的高度上,而Linkerd则成为了可选的一种sidecar实现,可谓降维打击的一个典型成功案例!

数据面标准API也有利于生态圈的建立,开源,商业的各种sidecar以后可能百花齐放,用户也可以根据自己的业务场景选择不同的sidecar和控制面集成,如高吞吐量的,低延迟的,高安全性的等等。有实力的大厂商可以根据该API定制自己的sidecar,例如蚂蚁金服开源的Golang版本的Sidecar MOSN(Modular Observable Smart Netstub)(SOFAMesh中Golang版本的Sidecar);小厂商则可以考虑采用成熟的开源项目或者提供服务的商业sidecar实现。

备注:Istio和Envoy项目联合制定了Envoy V2 API,并采用该API作为Istio控制面和数据面流量管理的标准接口。

业务DSL语言

Pilot还定义了一套DSL(Domain Specific Language)语言,DSL语言提供了面向业务的高层抽象,可以被运维人员理解和使用。运维人员使用该DSL定义流量规则并下发到Pilot,这些规则被Pilot翻译成数据面的配置,再通过标准API分发到Envoy实例,可以在运行期对微服务的流量进行控制和调整。

Pilot的规则DSL是采用K8S API Server中的Custom Resource (CRD)[3]实现的,因此和其他资源类型如Service Pod Deployment的创建和使用方法类似,都可以用Kubectl进行创建。

通过运用不同的流量规则,可以对网格中微服务进行精细化的流量控制,如按版本分流,断路器,故障注入,灰度发布等。

Istio流量管理相关组件

我们可以通过下图了解Istio流量管理涉及到的相关组件。虽然该图来自Istio Github old pilot repo, 但图中描述的组件及流程和目前Pilot的最新代码的架构基本是一致的。

Pilot Design Overview (来自Istio old_pilot_repo[4])

 

图例说明:图中红色的线表示控制流,黑色的线表示数据流。蓝色部分为和Pilot相关的组件。

从上图可以看到,Istio中和流量管理相关的有以下组件:

控制面组件

Discovery Services

对应的docker为gcr.io/istio-release/pilot,进程为pilot-discovery,该组件的功能包括:

  • 从Service provider(如kubernetes或者consul)中获取服务信息
  • 从K8S API Server中获取流量规则(K8S CRD Resource)
  • 将服务信息和流量规则转化为数据面可以理解的格式,通过标准的数据面API下发到网格中的各个sidecar中。

K8S API Server

提供Pilot相关的CRD Resource的增、删、改、查。和Pilot相关的CRD有以下几种:

  • Virtualservice:用于定义路由规则,如根据来源或 Header 制定规则,或在不同服务版本之间分拆流量。
  • DestinationRule:定义目的服务的配置策略以及可路由子集。策略包括断路器、负载均衡以及 TLS 等。
  • ServiceEntry:用 ServiceEntry 可以向Istio中加入附加的服务条目,以使网格内可以向istio 服务网格之外的服务发出请求。
  • Gateway:为网格配置网关,以允许一个服务可以被网格外部访问。
  • EnvoyFilter:可以为Envoy配置过滤器。由于Envoy已经支持Lua过滤器,因此可以通过EnvoyFilter启用Lua过滤器,动态改变Envoy的过滤链行为。我之前一直在考虑如何才能动态扩展Envoy的能力,EnvoyFilter提供了很灵活的扩展性。

数据面组件

在数据面有两个进程Pilot-agent和envoy,这两个进程被放在一个docker容器gcr.io/istio-release/proxyv2中。

Pilot-agent

该进程根据K8S API Server中的配置信息生成Envoy的配置文件,并负责启动Envoy进程。注意Envoy的大部分配置信息都是通过xDS接口从Pilot中动态获取的,因此Agent生成的只是用于初始化Envoy的少量静态配置。在后面的章节中,本文将对Agent生成的Envoy配置文件进行进一步分析。

Envoy

Envoy由Pilot-agent进程启动,启动后,Envoy读取Pilot-agent为它生成的配置文件,然后根据该文件的配置获取到Pilot的地址,通过数据面标准API的xDS接口从pilot拉取动态配置信息,包括路由(route),监听器(listener),服务集群(cluster)和服务端点(endpoint)。Envoy初始化完成后,就根据这些配置信息对微服务间的通信进行寻址和路由。

命令行工具

kubectl和Istioctl,由于Istio的配置是基于K8S的CRD,因此可以直接采用kubectl对这些资源进行操作。Istioctl则针对Istio对CRD的操作进行了一些封装。Istioctl支持的功能参见该表格。

数据面标准API

前面讲到,Pilot采用了一套标准的API来向数据面Sidecar提供服务发现,负载均衡池和路由表等流量管理的配置信息。该标准API的文档参见Envoy v2 API[5]。Data Plane API Protocol Buffer Definition[6])给出了v2 grpc接口相关的数据结构和接口定义。

(备注:Istio早期采用了Envoy v1 API,目前的版本中则使用V2 API,V1已被废弃)。

基本概念和术语

首先我们需要了解数据面API中涉及到的一些基本概念:

  • Host:能够进行网络通信的实体(如移动设备、服务器上的应用程序)。在此文档中,主机是逻辑网络应用程序。一块物理硬件上可能运行有多个主机,只要它们是可以独立寻址的。在EDS接口中,也使用“Endpoint”来表示一个应用实例,对应一个IP+Port的组合。
  • Downstream:下游主机连接到 Envoy,发送请求并接收响应。
  • Upstream:上游主机接收来自 Envoy 的连接和请求,并返回响应。
  • Listener:监听器是命名网地址(例如,端口、unix domain socket等),可以被下游客户端连接。Envoy 暴露一个或者多个监听器给下游主机连接。在Envoy中,Listener可以绑定到端口上直接对外服务,也可以不绑定到端口上,而是接收其他listener转发的请求。
  • Cluster:集群是指 Envoy 连接到的逻辑上相同的一组上游主机。Envoy 通过服务发现来发现集群的成员。可以选择通过主动健康检查来确定集群成员的健康状态。Envoy 通过负载均衡策略决定将请求路由到哪个集群成员。

XDS服务接口

Istio数据面API定义了xDS服务接口,Pilot通过该接口向数据面sidecar下发动态配置信息,以对Mesh中的数据流量进行控制。xDS中的DS表示discovery service,即发现服务,表示xDS接口使用动态发现的方式提供数据面所需的配置数据。而x则是一个代词,表示有多种discover service。这些发现服务及对应的数据结构如下:

XDS服务接口的最终一致性考虑

xDS的几个接口是相互独立的,接口下发的配置数据是最终一致的。但在配置更新过程中,可能暂时出现各个接口的数据不匹配的情况,从而导致部分流量在更新过程中丢失。

设想这种场景:在CDS/EDS只知道cluster X的情况下,RDS的一条路由配置将指向Cluster X的流量调整到了Cluster Y。在CDS/EDS向Mesh中Envoy提供Cluster Y的更新前,这部分导向Cluster Y的流量将会因为Envoy不知道Cluster Y的信息而被丢弃。

对于某些应用来说,短暂的部分流量丢失是可以接受的,例如客户端重试可以解决该问题,并不影响业务逻辑。对于另一些场景来说,这种情况可能无法容忍。可以通过调整xDS接口的更新逻辑来避免该问题,对上面的情况,可以先通过CDS/EDS更新Y Cluster,然后再通过RDS将X的流量路由到Y。

一般来说,为了避免Envoy配置数据更新过程中出现流量丢失的情况,xDS接口应采用下面的顺序:

  1. CDS 首先更新Cluster数据(如果有变化)
  2. EDS 更新相应Cluster的Endpoint信息(如果有变化)
  3. LDS 更新CDS/EDS相应的Listener。
  4. RDS 最后更新新增Listener相关的Route配置。
  5. 删除不再使用的CDS cluster和 EDS endpoints。

ADS聚合发现服务

保证控制面下发数据一致性,避免流量在配置更新过程中丢失的另一个方式是使用ADS(Aggregated Discovery Services),即聚合的发现服务。ADS通过一个gRPC流来发布所有的配置更新,以保证各个xDS接口的调用顺序,避免由于xDS接口更新顺序导致的配置数据不一致问题。

关于XDS接口的详细介绍可参考xDS REST and gRPC protocol[7]

Bookinfo 示例程序分析

下面我们以Bookinfo为例对Istio中的流量管理实现机制,以及控制面和数据面的交互进行进一步分析。

Bookinfo程序结构

下图显示了Bookinfo示例程序中各个组件的IP地址,端口和调用关系,以用于后续的分析。

xDS接口调试方法

首先我们看看如何对xDS接口的相关数据进行查看和分析。Envoy v2接口采用了gRPC,由于gRPC是基于二进制的RPC协议,无法像V1的REST接口一样通过curl和浏览器进行进行分析。但我们还是可以通过Pilot和Envoy的调试接口查看xDS接口的相关数据。

Pilot调试方法

Pilot在9093端口提供了下述调试接口[8]下述方法查看xDS接口相关数据。

PILOT=istio-pilot.istio-system:9093

# What is sent to envoy
# Listeners and routes
curl $PILOT/debug/adsz

# Endpoints
curl $PILOT/debug/edsz

# Clusters
curl $PILOT/debug/cdsz

Envoy调试方法

Envoy提供了管理接口,缺省为localhost的15000端口,可以获取listener,cluster以及完整的配置数据导出功能。

kubectl exec productpage-v1-54b8b9f55-bx2dq -c istio-proxy curl http://127.0.0.1:15000/help
  /: Admin home page
  /certs: print certs on machine
  /clusters: upstream cluster status
  /config_dump: dump current Envoy configs (experimental)
  /cpuprofiler: enable/disable the CPU profiler
  /healthcheck/fail: cause the server to fail health checks
  /healthcheck/ok: cause the server to pass health checks
  /help: print out list of admin commands
  /hot_restart_version: print the hot restart compatibility version
  /listeners: print listener addresses
  /logging: query/change logging levels
  /quitquitquit: exit the server
  /reset_counters: reset all counters to zero
  /runtime: print runtime values
  /runtime_modify: modify runtime values
  /server_info: print server version/status information
  /stats: print server stats
  /stats/prometheus: print server stats in prometheus format

进入productpage pod 中的istio-proxy(Envoy) container,可以看到有下面的监听端口

  • 9080: productpage进程对外提供的服务端口
  • 15001: Envoy的入口监听器,iptable会将pod的流量导入该端口中由Envoy进行处理
  • 15000: Envoy管理端口,该端口绑定在本地环回地址上,只能在Pod内访问。
kubectl exec t productpage-v1-54b8b9f55-bx2dq -c istio-proxy --  netstat -ln
 
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:9080            0.0.0.0:*               LISTEN      -               
tcp        0      0 127.0.0.1:15000         0.0.0.0:*               LISTEN      13/envoy        
tcp        0      0 0.0.0.0:15001           0.0.0.0:*               LISTEN      13/envoy  

Envoy启动过程分析

Istio通过K8s的Admission webhook[9]机制实现了sidecar的自动注入,Mesh中的每个微服务会被加入Envoy相关的容器。下面是Productpage微服务的Pod内容,可见除productpage之外,Istio还在该Pod中注入了两个容器gcr.io/istio-release/proxy_init和gcr.io/istio-release/proxyv2。

备注:下面Pod description中只保留了需要关注的内容,删除了其它不重要的部分。为方便查看,本文中后续的其它配置文件以及命令行输出也会进行类似处理。

ubuntu@envoy-test:~$ kubectl describe pod productpage-v1-54b8b9f55-bx2dq

Name:               productpage-v1-54b8b9f55-bx2dq
Namespace:          default
Init Containers:
  istio-init:
    Image:         gcr.io/istio-release/proxy_init:1.0.0
      Args:
      -p
      15001
      -u
      1337
      -m
      REDIRECT
      -i
      *
      -x

      -b
      9080,
      -d

Containers:
  productpage:
    Image:          istio/examples-bookinfo-productpage-v1:1.8.0
    Port:           9080/TCP
    
  istio-proxy:
    Image:         gcr.io/istio-release/proxyv2:1.0.0
    Args:
      proxy
      sidecar
      --configPath
      /etc/istio/proxy
      --binaryPath
      /usr/local/bin/envoy
      --serviceCluster
      productpage
      --drainDuration
      45s
      --parentShutdownDuration
      1m0s
      --discoveryAddress
      istio-pilot.istio-system:15007
      --discoveryRefreshDelay
      1s
      --zipkinAddress
      zipkin.istio-system:9411
      --connectTimeout
      10s
      --statsdUdpAddress
      istio-statsd-prom-bridge.istio-system:9125
      --proxyAdminPort
      15000
      --controlPlaneAuthPolicy
      NONE

Proxy_init

Productpage的Pod中有一个InitContainer proxy_init,InitContrainer是K8S提供的机制,用于在Pod中执行一些初始化任务.在Initialcontainer执行完毕并退出后,才会启动Pod中的其它container。

我们看一下proxy_init容器中的内容:

ubuntu@envoy-test:~$ sudo docker inspect gcr.io/istio-release/proxy_init:1.0.0
[
    {
        "RepoTags": [
            "gcr.io/istio-release/proxy_init:1.0.0"
        ],

        "ContainerConfig": {
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "ENTRYPOINT [\"/usr/local/bin/istio-iptables.sh\"]"
            ],
            "Entrypoint": [
                "/usr/local/bin/istio-iptables.sh"
            ],
        },
    }
]

从上面的命令行输出可以看到,Proxy_init中执行的命令是istio-iptables.sh,该脚本源码较长,就不列出来了,有兴趣可以在Istio 源码仓库的tools/deb/istio-iptables.sh查看。

该脚本的作用是通过配置iptable来劫持Pod中的流量。结合前面Pod中该容器的命令行参数-p 15001,可以得知Pod中的数据流量被iptable拦截,并发向Envoy的15001端口。 -u 1337参数用于排除用户ID为1337,即Envoy自身的流量,以避免Iptable把Envoy发出的数据又重定向到Envoy,形成死循环。

Proxyv2

前面提到,该容器中有两个进程Pilot-agent和envoy。我们进入容器中看看这两个进程的相关信息。

ubuntu@envoy-test:~$ kubectl exec   productpage-v1-54b8b9f55-bx2dq -c istio-proxy -- ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD
istio-p+     1     0  0 Sep06 ?        00:00:00 /usr/local/bin/pilot-agent proxy sidecar --configPath /etc/istio/proxy --binaryPath /usr/local/bin/envoy --serviceCluster productpage --drainDuration 45s --parentShutdownDuration 1m0s --discoveryAddress istio-pilot.istio-system:15007 --discoveryRefreshDelay 1s --zipkinAddress zipkin.istio-system:9411 --connectTimeout 10s --statsdUdpAddress istio-statsd-prom-bridge.istio-system:9125 --proxyAdminPort 15000 --controlPlaneAuthPolicy NONE
istio-p+    13     1  0 Sep06 ?        00:47:37 /usr/local/bin/envoy -c /etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time-s 60 --service-cluster productpage --service-node sidecar~192.168.206.23~productpage-v1-54b8b9f55-bx2dq.default~default.svc.cluster.local --max-obj-name-len 189 -l warn --v2-config-only

Envoy的大部分配置都是dynamic resource,包括网格中服务相关的service cluster, listener, route规则等。这些dynamic resource是通过xDS接口从Istio控制面中动态获取的。但Envoy如何知道xDS server的地址呢?这是在Envoy初始化配置文件中以static resource的方式配置的。

Envoy初始配置文件

Pilot-agent进程根据启动参数和K8S API Server中的配置信息生成Envoy的初始配置文件,并负责启动Envoy进程。从ps命令输出可以看到Pilot-agent在启动Envoy进程时传入了pilot地址和zipkin地址,并为Envoy生成了一个初始化配置文件envoy-rev0.json

Pilot agent生成初始化配置文件的代码: https://github.com/istio/istio/blob/release-1.0/pkg/bootstrap/bootstrap_config.go 137行

// WriteBootstrap generates an envoy config based on config and epoch, and returns the filename.
// TODO: in v2 some of the LDS ports (port, http_port) should be configured in the bootstrap.
func WriteBootstrap(config *meshconfig.ProxyConfig, node string, epoch int, pilotSAN []string, opts map[string]interface{}) (string, error) {
	if opts == nil {
		opts = map[string]interface{}{}
	}
	if err := os.MkdirAll(config.ConfigPath, 0700); err != nil {
		return "", err
	}
	// attempt to write file
	fname := configFile(config.ConfigPath, epoch)

	cfg := config.CustomConfigFile
	if cfg == "" {
		cfg = config.ProxyBootstrapTemplatePath
	}
	if cfg == "" {
		cfg = DefaultCfgDir
	}
	......

	if config.StatsdUdpAddress != "" {
		h, p, err = GetHostPort("statsd UDP", config.StatsdUdpAddress)
		if err != nil {
			return "", err
		}
		StoreHostPort(h, p, "statsd", opts)
	}

	fout, err := os.Create(fname)
	if err != nil {
		return "", err
	}

	// Execute needs some sort of io.Writer
	err = t.Execute(fout, opts)
	return fname, err
}

可以使用下面的命令将productpage pod中该文件导出来查看其中的内容:

kubectl exec productpage-v1-54b8b9f55-bx2dq -c istio-proxy -- cat /etc/istio/proxy/envoy-rev0.json > envoy-rev0.json

配置文件的结构如图所示:

其中各个配置节点的内容如下:

Node

包含了Envoy所在节点相关信息。

"node": {
    "id": "sidecar~192.168.206.23~productpage-v1-54b8b9f55-bx2dq.default~default.svc.cluster.local",
    //用于标识envoy所代理的node(在k8s中对应为Pod)上的service cluster,来自于Envoy进程启动时的service-cluster参数
    "cluster": "productpage",  
    "metadata": {
          "INTERCEPTION_MODE": "REDIRECT",
          "ISTIO_PROXY_SHA": "istio-proxy:6166ae7ebac7f630206b2fe4e6767516bf198313",
          "ISTIO_PROXY_VERSION": "1.0.0",
          "ISTIO_VERSION": "1.0.0",
          "POD_NAME": "productpage-v1-54b8b9f55-bx2dq",
          "istio": "sidecar"
    }
  }

Admin

配置Envoy的日志路径以及管理端口。

"admin": {
    "access_log_path": "/dev/stdout",
    "address": {
      "socket_address": {
        "address": "127.0.0.1",
        "port_value": 15000
      }
    }
  }

Dynamic_resources

配置动态资源,这里配置了ADS服务器。

"dynamic_resources": {
    "lds_config": {
        "ads": {}
    },
    "cds_config": {
        "ads": {}
    },
    "ads_config": {
      "api_type": "GRPC",
      "refresh_delay": {"seconds": 1, "nanos": 0},
      "grpc_services": [
        {
          "envoy_grpc": {
            "cluster_name": "xds-grpc"
          }
        }
      ]
    }
  }```

Static_resources

配置静态资源,包括了xds-grpc和zipkin两个cluster。其中xds-grpc cluster对应前面dynamic_resources中ADS配置,指明了Envoy用于获取动态资源的服务器地址。

"static_resources": {
    "clusters": [
    {
    "name": "xds-grpc",
    "type": "STRICT_DNS",
    "connect_timeout": {"seconds": 10, "nanos": 0},
    "lb_policy": "ROUND_ROBIN",

    "hosts": [
    {
    "socket_address": {"address": "istio-pilot.istio-system", "port_value": 15010}
    }
    ],
    "circuit_breakers": {
        "thresholds": [
      {
        "priority": "default",
        "max_connections": "100000",
        "max_pending_requests": "100000",
        "max_requests": "100000"
      },
      {
        "priority": "high",
        "max_connections": "100000",
        "max_pending_requests": "100000",
        "max_requests": "100000"
      }]
    },
    "upstream_connection_options": {
      "tcp_keepalive": {
        "keepalive_time": 300
      }
    },
    "http2_protocol_options": { }
    } ,
      {
        "name": "zipkin",
        "type": "STRICT_DNS",
        "connect_timeout": {
          "seconds": 1
        },
        "lb_policy": "ROUND_ROBIN",
        "hosts": [
          {
            "socket_address": {"address": "zipkin.istio-system", "port_value": 9411}
          }
        ]
      }
      
    ]
  }

Tracing

配置分布式链路跟踪。

"tracing": {
    "http": {
      "name": "envoy.zipkin",
      "config": {
        "collector_cluster": "zipkin"
      }
    }
  }

Stats_sinks

这里配置的是和Envoy直连的metrics收集sink,和Mixer telemetry没有关系。Envoy自带stats格式的metrics上报。

"stats_sinks": [
    {
      "name": "envoy.statsd",
      "config": {
        "address": {
          "socket_address": {"address": "10.103.219.158", "port_value": 9125}
        }
      }
    }
  ]

在Gist https://gist.github.com/zhaohuabing/14191bdcf72e37bf700129561c3b41ae中可以查看该配置文件的完整内容。

Envoy配置分析

通过管理接口获取完整配置

从Envoy初始化配置文件中,我们可以大致看到Istio通过Envoy来实现服务发现和流量管理的基本原理。即控制面将xDS server信息通过static resource的方式配置到Envoy的初始化配置文件中,Envoy启动后通过xDS server获取到dynamic resource,包括网格中的service信息及路由规则。

Envoy配置初始化流程:

  1. Pilot-agent根据启动参数和K8S API Server中的配置信息生成Envoy的初始配置文件envoy-rev0.json,该文件告诉Envoy从xDS server中获取动态配置信息,并配置了xDS server的地址信息,即控制面的Pilot。
  2. Pilot-agent使用envoy-rev0.json启动Envoy进程。
  3. Envoy根据初始配置获得Pilot地址,采用xDS接口从Pilot获取到Listener,Cluster,Route等d动态配置信息。
  4. Envoy根据获取到的动态配置启动Listener,并根据Listener的配置,结合Route和Cluster对拦截到的流量进行处理。

可以看到,Envoy中实际生效的配置是由初始化配置文件中的静态配置和从Pilot获取的动态配置一起组成的。因此只对envoy-rev0 .json进行分析并不能看到Mesh中流量管理的全貌。那么有没有办法可以看到Envoy中实际生效的完整配置呢?答案是可以的,我们可以通过Envoy的管理接口来获取Envoy的完整配置。

kubectl exec -it productpage-v1-54b8b9f55-bx2dq -c istio-proxy curl http://127.0.0.1:15000/config_dump > config_dump

该文件内容长达近7000行,本文中就不贴出来了,在Gist https://gist.github.com/zhaohuabing/034ef87786d290a4e89cd6f5ad6fcc97 中可以查看到全文。

Envoy配置文件结构

文件中的配置节点包括:

Bootstrap

从名字可以大致猜出这是Envoy的初始化配置,打开该节点,可以看到文件中的内容和前一章节中介绍的envoy-rev0.json是一致的,这里不再赘述。

Clusters

在Envoy中,Cluster是一个服务集群,Cluster中包含一个到多个endpoint,每个endpoint都可以提供服务,Envoy根据负载均衡算法将请求发送到这些endpoint中。

在Productpage的clusters配置中包含static_clusters和dynamic_active_clusters两部分,其中static_clusters是来自于envoy-rev0.json的xDS server和zipkin server信息。dynamic_active_clusters是通过xDS接口从Istio控制面获取的动态服务信息。

Dynamic Cluster中有以下几类Cluster:

Outbound Cluster

这部分的Cluster占了绝大多数,该类Cluster对应于Envoy所在节点的外部服务。以details为例,对于Productpage来说,details是一个外部服务,因此其Cluster名称中包含outbound字样。

从details 服务对应的cluster配置中可以看到,其类型为EDS,即表示该Cluster的endpoint来自于动态发现,动态发现中eds_config则指向了ads,最终指向static Resource中配置的xds-grpc cluster,即Pilot的地址。

{
 "version_info": "2018-09-06T09:34:19Z",
 "cluster": {
  "name": "outbound|9080||details.default.svc.cluster.local",
  "type": "EDS",
  "eds_cluster_config": {
   "eds_config": {
    "ads": {}
   },
   "service_name": "outbound|9080||details.default.svc.cluster.local"
  },
  "connect_timeout": "1s",
  "circuit_breakers": {
   "thresholds": [
    {}
   ]
  }
 },
 "last_updated": "2018-09-06T09:34:20.404Z"
}

可以通过Pilot的调试接口获取该Cluster的endpoint:

curl http://10.96.8.103:9093/debug/edsz > pilot_eds_dump

导出的文件长达1300多行,本文只贴出details服务相关的endpoint配置,完整文件参见:https://gist.github.com/zhaohuabing/a161d2f64746acd18097b74e6a5af551

从下面的文件内容可以看到,details cluster配置了1个endpoint地址,是details的pod ip。

{
  "clusterName": "outbound|9080||details.default.svc.cluster.local",
  "endpoints": [
    {
      "locality": {

      },
      "lbEndpoints": [
        {
          "endpoint": {
            "address": {
              "socketAddress": {
                "address": "192.168.206.21",
                "portValue": 9080
              }
            }
          },
          "metadata": {
            "filterMetadata": {
              "istio": {
                  "uid": "kubernetes://details-v1-6764bbc7f7-qwzdg.default"
                }
            }
          }
        }
      ]
    }
  ]
}

Inbound Cluster

该类Cluster对应于Envoy所在节点上的服务。如果该服务接收到请求,当然就是一个入站请求。对于Productpage Pod上的Envoy,其对应的Inbound Cluster只有一个,即productpage。该cluster对应的host为127.0.0.1,即环回地址上productpage的监听端口。由于iptable规则中排除了127.0.0.1,入站请求通过该Inbound cluster处理后将跳过Envoy,直接发送给Productpage进程处理。

{
   "version_info": "2018-09-14T01:44:05Z",
   "cluster": {
    "name": "inbound|9080||productpage.default.svc.cluster.local",
    "connect_timeout": "1s",
    "hosts": [
     {
      "socket_address": {
       "address": "127.0.0.1",
       "port_value": 9080
      }
     }
    ],
    "circuit_breakers": {
     "thresholds": [
      {}
     ]
    }
   },
   "last_updated": "2018-09-14T01:44:05.291Z"
}

BlackHoleCluster

这是一个特殊的Cluster,并没有配置后端处理请求的Host。如其名字所暗示的一样,请求进入后将被直接丢弃掉。如果一个请求没有找到其对的目的服务,则被发到cluste。

{
   "version_info": "2018-09-06T09:34:19Z",
   "cluster": {
    "name": "BlackHoleCluster",
    "connect_timeout": "5s"
   },
   "last_updated": "2018-09-06T09:34:20.408Z"
}

Listeners

Envoy采用listener来接收并处理downstream发过来的请求,listener的处理逻辑是插件式的,可以通过配置不同的filter来插入不同的处理逻辑。Istio就在Envoy中加入了用于policy check和metric report的Mixer filter。

Listener可以绑定到IP Socket或者Unix Domain Socket上,也可以不绑定到一个具体的端口上,而是接收从其他listener转发来的数据。Istio就是利用了Envoy listener的这一特点实现了将来发向不同服务的请求转交给不同的listener处理。

Virtual Listener

Envoy创建了一个在15001端口监听的入口监听器。Iptable将请求截取后发向15001端口,该监听器接收后并不进行业务处理,而是根据请求目的地分发给其他监听器处理。该监听器取名为”virtual”(虚拟)监听器也是这个原因。

Envoy是如何做到按服务分发的呢? 可以看到该Listener的配置项use_original_dest设置为true,该配置要求监听器将接收到的请求转交给和请求原目的地址关联的listener进行处理。

从其filter配置可以看到,如果找不到和请求目的地配置的listener进行转交,则请求将被发送到BlackHoleCluster,由于BlackHoleCluster并没有配置host,因此找不到对应目的地对应监听器的请求实际上会被丢弃。

    {
     "version_info": "2018-09-06T09:34:19Z",
     "listener": {
      "name": "virtual",
      "address": {
       "socket_address": {
        "address": "0.0.0.0",
        "port_value": 15001
       }
      },
      "filter_chains": [
       {
        "filters": [
         {
          "name": "envoy.tcp_proxy",
          "config": {
           "stat_prefix": "BlackHoleCluster",
           "cluster": "BlackHoleCluster"
          }
         }
        ]
       }
      ],
      "use_original_dst": true
     },
     "last_updated": "2018-09-06T09:34:26.262Z"
    }

Inbound Listener

在Productpage Pod上的Envoy创建了Listener 192.168.206.23_9080,当外部调用Productpage服务的请求到达Pod上15001的”Virtual” Listener时,Virtual Listener根据请求目的地匹配到该Listener,请求将被转发过来。

    {
     "version_info": "2018-09-14T01:44:05Z",
     "listener": {
      "name": "192.168.206.23_9080",
      "address": {
       "socket_address": {
        "address": "192.168.206.23",
        "port_value": 9080
       }
      },
      "filter_chains": [
       {
        "filters": [
         {
          "name": "mixer",
          "config": {
           "transport": {
            "check_cluster": "outbound|9091||istio-policy.istio-system.svc.cluster.local",
            "network_fail_policy": {
             "policy": "FAIL_CLOSE"
            },
            "report_cluster": "outbound|9091||istio-telemetry.istio-system.svc.cluster.local",
            "attributes_for_mixer_proxy": {
             "attributes": {
              "source.uid": {
               "string_value": "kubernetes://productpage-v1-54b8b9f55-bx2dq.default"
              }
             }
            }
           },
           "mixer_attributes": {
            "attributes": {
             "destination.port": {
              "int64_value": "9080"
             },
             "context.reporter.uid": {
              "string_value": "kubernetes://productpage-v1-54b8b9f55-bx2dq.default"
             },
             "destination.namespace": {
              "string_value": "default"
             },
             "destination.ip": {
              "bytes_value": "AAAAAAAAAAAAAP//wKjOFw=="
             },
             "destination.uid": {
              "string_value": "kubernetes://productpage-v1-54b8b9f55-bx2dq.default"
             },
             "context.reporter.kind": {
              "string_value": "inbound"
             }
            }
           }
          }
         },
         {
          "name": "envoy.tcp_proxy",
          "config": {
           "stat_prefix": "inbound|9080||productpage.default.svc.cluster.local",
           "cluster": "inbound|9080||productpage.default.svc.cluster.local"
          }
         }
        ]
       }
      ],
      "deprecated_v1": {
       "bind_to_port": false
      }
     },
     "last_updated": "2018-09-14T01:44:05.754Z"
    }

从上面的配置”bind_to_port”: false可以得知该listener创建后并不会被绑定到tcp端口上直接接收网络上的数据,因此其所有请求都转发自15001端口。

该listener配置的envoy.tcp_proxy filter对应的cluster为“inbound|9080||productpage.default.svc.cluster.local”,该cluster配置的host为127.0.0.1:9080,因此Envoy会将该请求发向127.0.0.1:9080。由于iptable设置中127.0.0.1不会被拦截,该请求将发送到Productpage进程的9080端口进行业务处理。

除此以外,Listenter中还包含Mixer filter的配置信息,配置了策略检查(Mixer check)和Metrics上报(Mixer report)服务器地址,以及Mixer上报的一些attribute取值。

Outbound Listener

Envoy为网格中的外部服务按端口创建多个Listener,以用于处理出向请求。

Productpage Pod中的Envoy创建了多个Outbound Listener

  • 0.0.0.0_9080 :处理对details,reviews和rating服务的出向请求
  • 0.0.0.0_9411 :处理对zipkin的出向请求
  • 0.0.0.0_15031 :处理对ingressgateway的出向请求
  • 0.0.0.0_3000 :处理对grafana的出向请求
  • 0.0.0.0_9093 :处理对citadel、galley、pilot、(Mixer)policy、(Mixer)telemetry的出向请求
  • 0.0.0.0_15004 :处理对(Mixer)policy、(Mixer)telemetry的出向请求
  • ……

除了9080这个Listener用于处理应用的业务之外,其他listener都是Istio用于处理自身组件之间通信使用的,有的控制面组件如Pilot,Mixer对应多个listener,是因为该组件有多个端口提供服务。

我们这里主要分析一下9080这个业务端口的Listenrer。和Outbound Listener一样,该Listener同样配置了”bind_to_port”: false属性,因此该listener也没有被绑定到tcp端口上,其接收到的所有请求都转发自15001端口的Virtual listener。

监听器name为0.0.0.0_9080,推测其含义应为匹配发向任意IP的9080的请求,从bookinfo程序结构可以看到该程序中的productpage,revirews,ratings,details四个service都是9080端口,那么Envoy如何区别处理这四个service呢?

首先需要区分入向(发送给productpage)请求和出向(发送给其他几个服务)请求:

  • 发给productpage的入向请求,virtual listener根据其目的IP和Port首先匹配到192.168.206.23_9080这个listener上,不会进入0.0.0.0_9080 listener处理。
  • 从productpage外发给reviews、details和ratings的出向请求,virtual listener无法找到和其目的IP完全匹配的listener,因此根据通配原则转交给0.0.0.0_9080处理。

备注:
1. 该转发逻辑为根据Envoy配置进行的推测,并未分析Envoy代码进行验证。欢迎了解Envoy代码和实现机制的朋友指正。
2.根据业务逻辑,实际上productpage并不会调用ratings服务,但Istio并不知道各个业务之间会如何调用,因此将所有的服务信息都下发到了Envoy中。这样做对效率和性能理论上有一定影响,存在一定的优化空间。

由于对应到reviews、details和Ratings三个服务,当0.0.0.0_9080接收到出向请求后,并不能直接发送到一个downstream cluster中,而是需要根据请求目的地进行不同的路由。

在该listener的配置中,我们可以看到并没有像inbound listener那样通过envoy.tcp_proxy直接指定一个downstream的cluster,而是通过rds配置了一个路由规则9080,在路由规则中再根据不同的请求目的地对请求进行处理。

{
     "version_info": "2018-09-06T09:34:19Z",
     "listener": {
      "name": "0.0.0.0_9080",
      "address": {
       "socket_address": {
        "address": "0.0.0.0",
        "port_value": 9080
       }
      },
      "filter_chains": [
       {
        "filters": [
         {
          "name": "envoy.http_connection_manager",
          "config": {
           "access_log": [
            {
             "name": "envoy.file_access_log",
             "config": {
              "path": "/dev/stdout"
             }
            }
           ],
           "http_filters": [
            {
             "name": "mixer",
             "config": {
			  
			  ......

             }
            },
            {
             "name": "envoy.cors"
            },
            {
             "name": "envoy.fault"
            },
            {
             "name": "envoy.router"
            }
           ],
           "tracing": {
            "operation_name": "EGRESS",
            "client_sampling": {
             "value": 100
            },
            "overall_sampling": {
             "value": 100
            },
            "random_sampling": {
             "value": 100
            }
           },
           "use_remote_address": false,
           "stat_prefix": "0.0.0.0_9080",
           "rds": {
            "route_config_name": "9080",
            "config_source": {
             "ads": {}
            }
           },
           "stream_idle_timeout": "0.000s",
           "generate_request_id": true,
           "upgrade_configs": [
            {
             "upgrade_type": "websocket"
            }
           ]
          }
         }
        ]
       }
      ],
      "deprecated_v1": {
       "bind_to_port": false
      }
     },
     "last_updated": "2018-09-06T09:34:26.172Z"
    },
    

Routes

配置Envoy的路由规则。Istio下发的缺省路由规则中对每个端口设置了一个路由规则,根据host来对请求进行路由分发。

下面是9080的路由配置,从文件中可以看到对应了3个virtual host,分别是details、ratings和reviews,这三个virtual host分别对应到不同的outbound cluster。

{
     "version_info": "2018-09-14T01:38:20Z",
     "route_config": {
      "name": "9080",
      "virtual_hosts": [
       {
        "name": "details.default.svc.cluster.local:9080",
        "domains": [
         "details.default.svc.cluster.local",
         "details.default.svc.cluster.local:9080",
         "details",
         "details:9080",
         "details.default.svc.cluster",
         "details.default.svc.cluster:9080",
         "details.default.svc",
         "details.default.svc:9080",
         "details.default",
         "details.default:9080",
         "10.101.163.201",
         "10.101.163.201:9080"
        ],
        "routes": [
         {
          "match": {
           "prefix": "/"
          },
          "route": {
           "cluster": "outbound|9080||details.default.svc.cluster.local",
           "timeout": "0s",
           "max_grpc_timeout": "0s"
          },
          "decorator": {
           "operation": "details.default.svc.cluster.local:9080/*"
          },
          "per_filter_config": {
           "mixer": {
            ......

           }
          }
         }
        ]
       },
       {
        "name": "ratings.default.svc.cluster.local:9080",
        "domains": [
         "ratings.default.svc.cluster.local",
         "ratings.default.svc.cluster.local:9080",
         "ratings",
         "ratings:9080",
         "ratings.default.svc.cluster",
         "ratings.default.svc.cluster:9080",
         "ratings.default.svc",
         "ratings.default.svc:9080",
         "ratings.default",
         "ratings.default:9080",
         "10.99.16.205",
         "10.99.16.205:9080"
        ],
        "routes": [
         {
          "match": {
           "prefix": "/"
          },
          "route": {
           "cluster": "outbound|9080||ratings.default.svc.cluster.local",
           "timeout": "0s",
           "max_grpc_timeout": "0s"
          },
          "decorator": {
           "operation": "ratings.default.svc.cluster.local:9080/*"
          },
          "per_filter_config": {
           "mixer": {
           ......

            },
            "disable_check_calls": true
           }
          }
         }
        ]
       },
       {
        "name": "reviews.default.svc.cluster.local:9080",
        "domains": [
         "reviews.default.svc.cluster.local",
         "reviews.default.svc.cluster.local:9080",
         "reviews",
         "reviews:9080",
         "reviews.default.svc.cluster",
         "reviews.default.svc.cluster:9080",
         "reviews.default.svc",
         "reviews.default.svc:9080",
         "reviews.default",
         "reviews.default:9080",
         "10.108.25.157",
         "10.108.25.157:9080"
        ],
        "routes": [
         {
          "match": {
           "prefix": "/"
          },
          "route": {
           "cluster": "outbound|9080||reviews.default.svc.cluster.local",
           "timeout": "0s",
           "max_grpc_timeout": "0s"
          },
          "decorator": {
           "operation": "reviews.default.svc.cluster.local:9080/*"
          },
          "per_filter_config": {
           "mixer": {
            ......

            },
            "disable_check_calls": true
           }
          }
         }
        ]
       }
      ],
      "validate_clusters": false
     },
     "last_updated": "2018-09-27T07:17:50.242Z"
    }

Bookinfo端到端调用分析

通过前面章节对Envoy配置文件的分析,我们了解到Istio控制面如何将服务和路由信息通过xDS接口下发到数据面中;并介绍了Envoy上生成的各种配置数据的结构,包括listener,cluster,route和endpoint。

下面我们来分析一个端到端的调用请求,通过调用请求的流程把这些配置串连起来,以从全局上理解Istio控制面的流量控制是如何在数据面的Envoy上实现的。

下图描述了一个Productpage服务调用Details服务的请求流程:

  1. Productpage发起对Details的调用:http://details:9080/details/0 。
  2. 请求被Pod的iptable规则拦截,转发到15001端口。
  3. Envoy的Virtual Listener在15001端口上监听,收到了该请求。
  4. 请求被Virtual Listener根据原目标IP(通配)和端口(9080)转发到0.0.0.0_9080这个listener。

    {
     "version_info": "2018-09-06T09:34:19Z",
     "listener": {
      "name": "virtual",
      "address": {
       "socket_address": {
        "address": "0.0.0.0",
        "port_value": 15001
       }
      }
      ......
    
      "use_original_dst": true //请求转发给和原始目的IP:Port匹配的listener
     },
    
  5. 根据0.0.0.0_9080 listener的http_connection_manager filter配置,该请求采用“9080” route进行分发。

    {
     "version_info": "2018-09-06T09:34:19Z",
     "listener": {
      "name": "0.0.0.0_9080",
      "address": {
       "socket_address": {
        "address": "0.0.0.0",
        "port_value": 9080
       }
      },
      "filter_chains": [
       {
        "filters": [
         {
          "name": "envoy.http_connection_manager",
          "config": {
          ......
    
           "rds": {
            "route_config_name": "9080",
            "config_source": {
             "ads": {}
            }
           },
    
         }
        ]
       }
      ],
      "deprecated_v1": {
       "bind_to_port": false
      }
     },
     "last_updated": "2018-09-06T09:34:26.172Z"
    },
    
    {
     },
    
  6. “9080”这个route的配置中,host name为details:9080的请求对应的cluster为outbound|9080||details.default.svc.cluster.local

    {
     "version_info": "2018-09-14T01:38:20Z",
     "route_config": {
      "name": "9080",
      "virtual_hosts": [
       {
        "name": "details.default.svc.cluster.local:9080",
        "domains": [
         "details.default.svc.cluster.local",
         "details.default.svc.cluster.local:9080",
         "details",
         "details:9080",
         "details.default.svc.cluster",
         "details.default.svc.cluster:9080",
         "details.default.svc",
         "details.default.svc:9080",
         "details.default",
         "details.default:9080",
         "10.101.163.201",
         "10.101.163.201:9080"
        ],
        "routes": [
         {
          "match": {
           "prefix": "/"
          },
          "route": {
           "cluster": "outbound|9080||details.default.svc.cluster.local",
           "timeout": "0s",
           "max_grpc_timeout": "0s"
          },
            ......
    
           }
          }
         }
        ]
       },
    	   ......
    
    {
     },
    
  7. outbound|9080||details.default.svc.cluster.local cluster为动态资源,通过eds查询得到其endpoint为192.168.206.21:9080。

    {
    "clusterName": "outbound|9080||details.default.svc.cluster.local",
    "endpoints": [
    {
      "locality": {
    
      },
      "lbEndpoints": [
        {
          "endpoint": {
            "address": {
              "socketAddress": {
                "address": "192.168.206.21",
                "portValue": 9080
              }
            }
          },
         ......  
        }
      ]
    }
    ]
    }
    
  8. 请求被转发到192.168.206.21,即Details服务所在的Pod,被iptable规则拦截,转发到15001端口。

  9. Envoy的Virtual Listener在15001端口上监听,收到了该请求。

  10. 请求被Virtual Listener根据请求原目标地址IP(192.168.206.21)和端口(9080)转发到192.168.206.21_9080这个listener。

  11. 根据92.168.206.21_9080 listener的http_connection_manager filter配置,该请求对应的cluster为 inbound|9080||details.default.svc.cluster.local 。

    {
     "version_info": "2018-09-06T09:34:16Z",
     "listener": {
      "name": "192.168.206.21_9080",
      "address": {
       "socket_address": {
        "address": "192.168.206.21",
        "port_value": 9080
       }
      },
      "filter_chains": [
       {
        "filters": [
         {
          "name": "envoy.http_connection_manager",
          ......
              
          "route_config": {
            "name": "inbound|9080||details.default.svc.cluster.local",
            "validate_clusters": false,
            "virtual_hosts": [
             {
              "name": "inbound|http|9080",
              "routes": [
                ......
                    
                "route": {
                 "max_grpc_timeout": "0.000s",
                 "cluster": "inbound|9080||details.default.svc.cluster.local",
                 "timeout": "0.000s"
                },
                ......
                    
                "match": {
                 "prefix": "/"
                }
               }
              ],
              "domains": [
               "*"
              ]
             }
            ]
           },
            ......
                
           ]
          }
         }
        ]
       }
      ],
      "deprecated_v1": {
       "bind_to_port": false
      }
     },
     "last_updated": "2018-09-06T09:34:22.184Z"
    }
    
  12. inbound|9080||details.default.svc.cluster.local cluster配置的host为127.0.0.1:9080。

  13. 请求被转发到127.0.0.1:9080,即Details服务进行处理。

上述调用流程涉及的完整Envoy配置文件参见:

小结

本文介绍了Istio流量管理相关组件,Istio控制面和数据面之间的标准接口,以及Istio下发到Envoy的完整配置数据的结构和内容。然后通过Bookinfo示例程序的一个端到端调用分析了Envoy是如何实现服务网格中服务发现和路由转发的,希望能帮助大家透过概念更进一步深入理解Istio流量管理的实现机制。

参考资料

  1. Istio Traffic Managment Concept
  2. Data Plane API
  3. kubernetes Custom Resource
  4. Istio Pilot Design Overview
  5. Envoy V2 API Overview
  6. Data Plane API Protocol Buffer Definition
  7. xDS REST and gRPC protocolhttps://github.com/istio/istio/tree/master/pilot/pkg/proxy/envoy/v2
  8. Pilot Debug interface
  9. Istio Sidecar自动注入原理

 

深入解析CycloneDDS跨域通信中的XML配置文件优化策略 本文深入解析了CycloneDDS跨域通信中XML配置文件的优化策略,重点介绍了网络接口配置、多播设置、性能调优参数及复杂场景下的配置案例。通过实战技巧和调试方法,帮助开发者在SoC环境中实现高效稳定的跨域通信,提升系统性能。 阅读详情

相关推荐

【硬核指南/MI50 32G/Ubuntu】从零部署大模型:MI50显卡Ubuntu系统驱动安装与避坑全记录

本文详细记录了在Ubuntu系统上为AMD MI50显卡安装驱动并部署大模型的完整流程,包括硬件兼容性检查、BIOS关键设置、系统安装优化、ROCm驱动安装及常见问题解决方案。特别针对MI50显卡在X99平台上的特殊配置需求提供了实用技巧,帮助用户避免常见陷阱,提升大模型训练效率。

weixin_42520909的博客 813

云原生Istio基本介绍

目录 1 什么是Istio 2 Istio特征 2.1 连接 2.2 安全 2.3 策略 2.4 观察 3 Istio与服务治理 3.1服务治理的三种形态 4 Istio与Kubernetes 4.1 Kubernetes介绍 4.2 Istio是Kubernetes的好帮手 4.3 Kubernetes是Istio的好基座 5 Istio与服务网格 5.1 时代选择服务网格 5.2 服务网格选择Istio

赵广陆 1万+

Cadence仿真MOS电容C-V曲线:从电路图到参数扫描的完整流程

本文详细介绍了使用Cadence Virtuoso仿真MOS电容C-V曲线的完整流程,从电路图绘制到参数扫描,再到结果分析与问题排查。通过实际案例和实用技巧,帮助工程师快速掌握MOS电容特性分析的关键步骤,提升集成电路设计效率。

weixin_29271263的博客 431

k8s实战之istio资源详解

云平台令使用它们的公司受益匪浅。但不可否认的是,上云会给 DevOps 团队带来压力。为了可移植性,开发人员必须使用微服务来构建应用,同时运维人员也正在管理着极端庞大的混合云和多云的部署环境。 Istio 允许您连接、保护、控制和观察服务。从较高的层面来说,Istio 有助于降低这些部署的复杂性,并减轻开发团队的压力。它是一个完全开源的服务网格,作为透明的一层接入到现有的分布式应用程序里。它也是一个平台,拥有可以集成任何日志、遥测和策略系统的 API 接口。Istio 多样化的特性使您能够成功且高效地运行分布式微服务架构,并提供保护、连接和监控微服务的统一方法。本课程详细讲解istio的各种crd资源,如何写yaml配置文件,以及他们会起什么作用。

深度学习之基于Pytorch手指静脉识别系统(

一、项目背景与目标手指静脉识别技术是一种新兴的生物特征识别技术,它依据人类手指中流动的血液可吸收特定波长的光线这一科学原理,利用手指内的静脉分布图像来进行身份识别。与传统的生物识别技术(如指纹识别)相比,手指静脉识别技术具有不易伪造、识别精度高、非接触性等特点,因此在安全性要求较高的场景(如金融、医疗、公安等)具有广阔的应用前景。本项目旨在利用PyTorch深度学习框架,构建一套高效、准确的手指静脉识别系统。

Q1744828575的博客 835

基于RAG(Retrieval Augmented Generation)架构的简单问答系统的Python实现示例

以下是一个基于RAG(Retrieval Augmented Generation)架构的简单问答系统的Python实现示例。这个系统使用langchain库进行文档处理、检索,以及与大语言模型交互。

max500600的博客 743

笔记:Istio & 组件 基础概念学习

文章目录1. Istio是什么?1.1 读音1.2 简介1.3 服务网格是什么?1.4 为什么使用Isito?1.5 Istio 是如何诞生的?1.6 为什么我想用 ISTIO?1.7 目前Istio支持哪些部署环境?1.8 架构1.8.1 组件1.8.1.1 Envoy1.8.1.2 Pilot1.8.1.3 Citadel1.8.1.4 Galley1.8.2 设计目标2. 核心特性2.1 流量管理2.1.1 Istio 流量管理介绍2.1.2 虚拟服务2.1.2.1 为什么使用虚拟服务?2.1.2.1

wifiiii的博客 6302

Office系列完全干净卸载工具合集(最全)

使用 Microsoft Fix it 卸载 Microsoft Office 套件 一、Windows 7、Windows Vista或Windows XP下卸载Office 1.MicrosoftEasyFix50416 工具用来卸载office 2003 MicrosoftEasyFix50416_Office2003.msi 2.MicrosoftEasyFix50154 工具用来卸载office 2007 MicrosoftEasyFix50154_Office2007.msi 3.Microso

业精于勤,荒于嬉 3万+

istio简介和基础组件原理(服务网格Service Mesh)

Istio简介 Istio:一个连接,管理和保护微服务的开放平台。 按照isito文档中给出的定义: Istio提供一种简单的方式来建立已部署的服务的网络,具备负载均衡,服务到服务认证,监控等等功能,而不需要改动任何服务代码。简单的说,有了Istio,你的服务就不再需要任何微服务开发框架(典型如Spring Cloud,Dubbo),也不再需要自己手动实现各种复杂的服务...

7万+

ATS Request中的PASID的作用是什么

摘要: PASID(进程地址空间标识符)是PCIe ATS(地址转换服务)中的关键组件,用于标识不同进程或虚拟机的地址空间。其主要作用包括:1)支持多进程共享设备时隔离地址空间;2)实现共享虚拟地址(SVA),允许用户态程序直接访问设备;3)提升虚拟化性能(如SIOV),通过PASID区分虚拟机请求;4)增强安全性,基于PASID限制设备内存访问权限。PASID通过20位标识符在TLP前缀中传递,与IOMMU协作完成地址转换与缓存,适用于高性能计算、AI及虚拟化场景,但依赖硬件支持和软件适配。

元直的博客 1563

华为昇腾(Ascend)开发考试原题目解析 (2024) (题库一)——HCIP-AI-Ascend Developer——第一部分

给出一段代码如下,以下哪个选项描述错误?...A.中的语句由 MindSpore 接管,有语法限制B. 算子在中定义,并用来建立网络C.__init__()中的语句由 Python 解析执行D. 网络定义必须继承基类nn.Cell正确答案: B__init__()用于定义算子和网络层。所有需要用到的层(如卷积层、全连接层等)都应该在这里进行实例化。这部分代码由Python解释器执行。用于构建前向计算图。它调用在__init__()中定义好的算子和层来描述数据的流向。

qq_38334677的博客 1055

istio 简介

文章目录什么是 istio?istio 解决了什么痛点?总结istio 的解决方案流量管理安全性可观察性平台支持 什么是 istio? 讲多了记不住,那就:服务网格 + 微服务治理。 istio 解决了什么痛点? 了解Istio得从微服务架构谈起,微服务是在2012年提出的概念,其根本思想是通过拆分原则,希望一个服务只负责业务中一个独立的功能,这样任何一个需求不会因为发布或者维护而影响到不相关的服务,所有服务都可以做到独立部署运维,当然这也只是微服务架构给我们带来的好处之一。 但是: 首先,原来的单个应用

看,未来的博客 5571

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Istio调用链埋点原理剖析—是否真的“零修改”分享实录

戳蓝字“优快云云计算”关注我们哦!来自:容器魔方作者:idouba本文整理自华为Cloud BU技术专家在K8S技术社上关于Istio调用链的分享。前言大家好,我是i...

优快云云计算 1176

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Istio调用链埋点原理剖析—是否真的“零修改”分享实录(上)

本文整理自华为Cloud BU技术专家在K8S技术社上 关于Istio调用链的分享。 前言 大家好,我是idouba,来自华为Cloud BU,当前在做Istio服务网格在华为云容器服务的产品化工作。今天跟大家分享的主题是Istio调用链相关内容。通过剖析Istio的架构机制与Istio中调用链的工作原理来解答一个大家经常问道的一个问题:Istio是否像其官方文档中宣传的一样,...

weixin_30408675的博客 75

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

为什么90%的Java架构师都在关注Istio 1.22服务网格集成?

掌握Java微服务架构中的服务网格Istio 1.22集成实战,提升系统可观测性与流量治理能力。适用于多云、混合部署场景,通过无侵入方式实现熔断、限流、安全通信等关键功能,助力企业级服务高效协同。架构优化必读,值得收藏。

AlgoChat的博客 1047

Naftis源码深度解析:理解小米微服务治理平台的核心实现

Naftis是小米开源的一款基于Web的Istio Dashboard,它通过任务模板的方式帮助用户更轻松地管理Istio任务。作为一款优秀的微服务治理平台,Naftis让复杂的Istio配置变得简单直观。本文将深入解析Naftis的源码架构,帮助你理解这个强大的微服务治理工具是如何构建的。 ## 🏗️ Naftis整体架构设计 Naftis采用了前后端分离的架构设计,后端使用Go语言开发,

gitblog_00372的博客 359

Istio 服务网格的流量管理功能深度解析

Istio 服务网格的流量管理功能深度解析,结合配置示例和实战场景,助你掌握流量路由、负载均衡、熔断等核心能力!

独坐一隅,凝神遐想,是种幸福! —— 独隅 1123

Istio超强流量管理:实现智能路由与负载均衡的新范式

还在为微服务架构中的流量管理而头疼吗?面对复杂的服务间通信、版本发布、故障恢复等场景,传统的手动配置方式已经无法满足现代云原生应用的需求。Istio作为服务网格(Service Mesh)领域的领军者,提供了革命性的流量管理解决方案,让您轻松实现智能路由、精细负载均衡和弹性流量控制。 通过本文,您将掌握: - Istio流量管理的核心概念与架构原理 - VirtualService与Desti...

gitblog_00613的博客 836

Istio 服务网格深度解析

Istio 是一个开源的服务网格(Service Mesh)解决方案,旨在简化微服务应用的部署和管理。解耦业务逻辑与基础设施:通过将网络功能从应用代码中抽离,开发者可以专注于业务逻辑,而不必处理复杂的通信和安全细节。可观察性和可控性:提供统一的方式来监控和控制服务间的通信,包括流量管理、安全策略和遥测数据收集。灵活性和可扩展性:采用模块化和可插拔的设计,允许根据需求定制和扩展功能。Pilot:服务发现和流量管理Mixer(已在新版本中被移除):策略控制和遥测数据收集Citadel。

hello.reader 1809

Service Mesh 深度解析与 Istio+Envoy 实现方案

建议生产部署时遵循渐进式原则,从非关键业务开始验证,逐步完善监控告警体系,最终实现全业务服务网格化改造。饱和度 Saturation。延迟 Latency。流量 Traffic。

保持热爱。 1454

Kubernetes服务网格实战:Istio架构原理与高级流量管理

✅架构原理:控制平面与数据平面的协同机制✅流量管理:金丝雀发布、熔断、故障注入等高级模式✅安全机制:mTLS、JWT认证、授权策略等安全特性✅可观测性:分布式追踪、指标收集、日志集成✅生产实践:多集群部署、性能优化、故障排查如需获取更多关于Kubernetes性能调优、安全加固、多集群管理、GitOps实践、服务网格深度解析等进阶内容,请持续关注本专栏《云原生技术深度解析》系列文章。在超大规模微服务架构中,如何设计服务网格架构来保证性能和高可用性?欢迎在评论区分享你的见解!

用文字记录技术,用分享回馈社区,用坚持见证成长 1051

Istio 架构全景解析:控制面 vs 数据面、核心组件与流量路径深度拆解

摘要: 本文深度解析 Istio 架构,揭示其“控制面-数据面”分离设计哲学。控制面(Istiod)负责策略管理与配置分发,数据面(Envoy Sidecar)处理实际流量,通过 xDS 协议实现动态治理。核心组件从早期分散架构(Pilot/Citadel/Mixer)演进为统一集成的 Istiod,解决性能与运维痛点。文章详细拆解流量路径(Ingress→服务间通信),展示 VirtualService/DestinationRule 的配置逻辑,并对比传统微服务与 Istio 的优势:治理能力下沉、多语

qq_43414012的博客 1272

深度解析Istio系列之流量控制篇

在我们公众号的上一篇文章中,我们对比了当前较流行的几款服务网格产品,主要关注的是Istio。得益于良好的模块化设计,Istio的各个组件设计清晰,分工明确,几个大的组件之间甚至可以独立工作,所以接下来我们将逐一深入分析Istio的各个组件。本文首先详细分析一下我们最常用的流量管理功能所对应的模块——Pilot和Envoy。 Istio基本架构 Istio基本架构图如下图所示,网格东西向及...

BoCloud博云 1176
上一篇: 虚拟机容器嵌合体—— Kata Containers正式走出实验室
下一篇: Install Percona XtraDB Cluster on Kubernetes
hxpjava1
博客等级 码龄19年 1365粉丝 511原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值