基于Service Mesh管理Knative流量最佳实践

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
函数计算FC,每月15万CU 3个月
简介: Istio扩展了Kubernetes,以建立可编程、应用程序感知的服务网格(Service Mesh)。Istio与Knative结合使用,可以为Serverless应用工作负载带来标准、通用的流量管理、可观测和安全性能力。

【阅读原文】戳:基于Service Mesh管理Knative流量最佳实践

前言

 

 

Knative是一款基于Kubernetes集群的Serverless 应用框架,提供了云原生、跨平台的Serverless编排标准。Knative通过整合函数、工作负载管理以及事件驱动来实现这一Serverless标准,具有标准化、门槛低、管理自动化、事件驱动等优势。

 

Istio扩展了Kubernetes,以建立可编程、应用程序感知的服务网格(Service Mesh)。Istio与Knative 结合使用,可以为Serverless应用工作负载带来标准、通用的流量管理、可观测和安全性能力。

 

 

 

工作原理

 

 

 

Knative通过KIngress资源将服务层与网络层进行解耦。当一个Knative Service被创建时,Knative Serving Controller会生成对应的KIngress资源,通过net-istio控制器将KIngress转换成 VirtualService。KIngress资源是Knative针对网络层创建的CRD,其中包含了服务对外暴露所需的所有信息。KIngress资源示例如下:

 

apiVersion: networking.internal.knative.dev/v1alpha1
kind: Ingress
metadata:
  annotations:
    networking.internal.knative.dev/rollout: '{"configurations":[{"configurationName":"httpbin","percent":100,"revisions":[{"revisionName":"httpbin-00001","percent":100}],"stepParams":{}}]}'
    networking.knative.dev/ingress.class: istio.ingress.networking.knative.dev
    serving.knative.dev/creator: 1281429699509011-1724722123
    serving.knative.dev/lastModifier: 1281429699509011-1724722123
  labels:
    serving.knative.dev/route: httpbin
    serving.knative.dev/routeNamespace: default
    serving.knative.dev/service: httpbin
  name: httpbin
  namespace: default
spec:
  httpOption: Enabled
  rules:
  - hosts:
    - httpbin.default
    - httpbin.default.svc
    - httpbin.default.svc.cluster.local
    http:
      paths:
      - appendHeaders:
          Knative-Serving-Default-Route: "true"
        splits:
        - appendHeaders:
            Knative-Serving-Namespace: default
            Knative-Serving-Revision: httpbin-00001
          percent: 100
          serviceName: httpbin-00001
          serviceNamespace: default
          servicePort: 80
    visibility: ClusterLocal
  - hosts:
    - httpbin.default.example.com
    http:
      paths:
      - appendHeaders:
          Knative-Serving-Default-Route: "true"
        splits:
        - appendHeaders:
            Knative-Serving-Namespace: default
            Knative-Serving-Revision: httpbin-00001
          percent: 100
          serviceName: httpbin-00001
          serviceNamespace: default
          servicePort: 80
    visibility: ExternalIP

 

 

 

阿里云Knative与服务网格ASM

 

 

阿里云容器服务Knative在完全兼容社区Knative 并提供标准Kubernetes API接口的基础上,进一步增强产品化能力并提供了更丰富的产品方案。

 

 

产品化的能力:提供产品化一键部署能力,您无需购买资源搭建系统。同时提供产品控制台,支持白屏化操作,降低Kubernetes集群和Knative的使用门槛。

 

简化运维:

 

核心组件托管:在ACK集群中,Knative的核心组件Knative Serving和Knative Eventing均由ACK创建和托管,无需您承担资源费用,且提供高可用保障。

 

网关托管:ACK Knative提供ALB、MSE、ASM和Kourier四种网关。除社区兼容的Kourier外,其余三种云产品网关的Controller均由ACK创建,提供全托管、免运维的网关服务。

 

生态集成:无缝集成了阿里云的计算(ECI、ECS)、可观测(日志服务SLS、Prometheus)、CI/CD(云效)、应用集成(EventBridge)、消息(MNS)产品。您无需自行采购服务器,也无需自建服务,便能在Knative服务中实现日志与监控告警、持续交付、事件驱动等能力。

 

更丰富的功能特性:在社区Knative的基础上,ACK Knative结合实际业务场景提供了开箱即用的、更为丰富的产品方案。例如以下方案。

 

保留实例:在应用没有流量时,社区Knative默认将应用实例数缩容至零以降低成本,从而导致应用重新启动时会经历较长的冷启动时间。如果您的应用对冷启动延时较为敏感,推荐使用此功能,保留一个低规格的突发性能实例,平衡好使用成本和启动时长。

 

Knative自动伸缩:除提供开箱即用的HPA、KPA(Knative Pod Autoscaler)外,您还可以为Knative服务配置AHPA(Advanced Horizontal Pod Autoscaler)弹性能力。如果您的应用所需资源具备周期性变化,推荐您使用AHPA进行弹性预测,提前预热所需的资源,缓解使用Knative时遇到的冷启动问题。

 

阿里云服务网格ASM是一个完全兼容社区Istio开源服务网格标准的企业级托管式服务网格平台。在网络层的产品化能力上,ASM具有以下优势:

 

提供丰富的路由能力,以及限流熔断、流量泳道等高级流量管理能力,可通过控制台进行配置。

 

支持双向TLS安全能力,支持配置JWT认证、OPA策略、OIDC单点登录等鉴权能力,支持对接WAF实现安全防护能力。

 

提供开箱即用的丰富可观测能力,包括日志、监控指标大盘、服务调用拓扑图、以及链路追踪能力。

 

提供插件市场以及自定义编写任意插件的能力。

 

完全支持Knative net-istio controller,基于开源社区生态构建。

 

支持服务网格的丰富能力,相比单纯的网关实现,服务网格作为云原生应用网络基础设施,能够无侵入式地为Knative服务增加各种网络层能力,包括丰富的高可用性能力构建等。

 

 

 

最佳实践:基于服务网格ASM构建Knative 服务能力

 

前提准备

 

部署Knative时选择ASM为服务网关

 

 

1.登录容器服务管理控制台,在左侧导航栏选择集群

 

2.在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择应用 > Knative

 

3.在Knative页面的组件管理页签下,单击一键部署Knative,然后在服务网关处选择ASM,然后单击一键部署

 

部署成功后,即可在Knative中使用服务网格ASM。

 

 

 

为Knative工作负载注入网格代理

 

默认情况下,Knative在集成服务网格ASM时仍然只启用了网关的能力、而没有给数据面组件注入网格代理,在这种情况下、服务网格ASM可以实现与其它网关类产品对齐的能力,如限流、安全防护、可观测等等。通过为数据面流量组件注入网格代理,可以进一步使用服务网格的能力,包括熔断、同可用区优先路由、请求优先级调度等等。

 

activator和Knative Service的pod是Knative中重要的承载流量的组件,通过为他们注入网格代理,服务网格可以无侵入式地接管Knative服务的流量。

 

为knative-serving命名空间和default命名空间开启Sidecar自动注入,具体操作可参考管理全局命名空间[1]

 

 

在ACK集群中,重新部署knative-serving命名空间下的activator Deployment,新启动的activator pod将注入网格代理。

 

在服务网格ASM中启用reverse dns插件(即“支持Spring Cloud服务”插件),reverse dns主要帮助服务网格针对activator发出的请求进行二次解析、以实现丰富的流量管理能力。有关使用服务网格ASM插件市场的具体操作,可以参考使用插件市场扩展网格能力[2]

 

 

 

 

服务部署

 

 

这里以helloworld-go为示例演示如何通过部署 Knative服务。

 

1.登录容器服务管理控制台,在左侧导航栏选择集群

 

2.在集群列表页面,单击目标集群名称,然后在左侧导航栏,选择应用 > Knative

 

Knative页面的服务管理页签下,选择命名空间default,然后单击使用模板创建,将以下YAML示例粘贴至模板,最后单击创建。创建一个名为helloworld-go的服务。

 

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: helloworld-go
spec:
  template:
    spec:
      containers:
      - image: registry.{REGION-ID}.aliyuncs.com/knative-sample/helloworld-go:73fbdd56 # 请将{REGION-ID}替换为您集群所在地域。
        env:
        - name: TARGET
          value: "Knative"

 

3.在服务管理页面的访问网关列,获取helloworld-go服务的网关地址。

 

4.执行以下命令,访问helloworld-go服务。

  •  
curl -H "host: helloworld-go.default.example.com" http://39.XX.XX.XX # 网关的IP和域名请以您的实际数据为准。

 

预期输出:

  •  
Hello Knative!

 

输出结果表明服务访问成功。

 

 

 

服务限流

 

针对服务的限流是一项常用的构建服务高可用能力的手段。在面临高流量冲击、服务过载、资源耗尽或恶意攻击的情况下,通过配置限流防护,可以实现对流量的精准控制,从而保护后端服务的稳定性,降低成本并提升用户体验。限流能力不需要网格代理参与,只需要通过在网关上的配置,即可限制外界进入系统整体的流量速率,保证系统整体稳定。

 

服务网格ASM可以通过ASMLocalRateLimiter来声明式地配置针对任意Knative服务的限流防护措施。以前提准备中部署的helloworld-go服务为例,可以建立如下的限流规则:

 

apiVersion: istio.alibabacloud.com/v1
kind: ASMLocalRateLimiter
metadata:
  name: helloworld
  namespace: istio-system
spec:
  configs:
    - limit:
        fill_interval:
          seconds: 2
        quota: 60
      match:
        vhost:
          name: helloworld-go.default.svc.cluster.local
          port: 80
  isGateway: true
  workloadSelector:
    labels:
      istio: ingressgateway

 

上述配置代表为helloworld-go服务配置限流,每60秒允许两个请求经过。除了示例中的基础限流配置之外,ASMLocalRateLimiter还支持请求精细化匹配限流、自定义响应体等高级功能,可参考ASMLocalRateLimiter CRD说明[3]

 

可通过kubeconfig连接到ACK集群或ASM实例来部署上述限流规则:

  •  
kubectl apply -f ratelimit.yaml

 

通过连续的三次请求来验证限流规则:

 

curl -H "host: helloworld-go.default.example.com" http://{ASM网关IP}
Hello Knative-v2!
curl -H "host: helloworld-go.default.example.com" http://{ASM网关IP}
Hello Knative-v2!
curl -H "host: helloworld-go.default.example.com" http://{ASM网关IP}
local_rate_limited

 

可以看到一分钟内的连续请求,第三次时请求会触发429限流响应,达到保护内部服务的目的。

 

 

 

服务级熔断

 

 

服务级熔断可以针对Knative服务的一个revision配置自适应的请求错误以及慢请求检测,当服务连续返回5xx错误或者连续发生请求响应慢的情况时,服务级熔断会主动切断对服务的访问并提前返回熔断错误码,以防进一步的请求造成整个系统的级联错误。

 

在示例中,我们部署一个相对helloworld-go来说更加适合测试的httpbin服务,这个服务可以根据请求内容来动态调整响应码以及响应时间。

 

在Knative中部署以下的KService:

 

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: httpbin
  namespace: default
spec:
  template:
    spec:
      containers:
        - image: 'registry.cn-hangzhou.aliyuncs.com/acs/httpbin:latest'
          imagePullPolicy: IfNotPresent
          name: httpbin
          ports:
            - containerPort: 80
              protocol: TCP

 

服务级熔断同样可以在服务网格中通过声明式方法来配置。基于部署的httpbin服务,可以配置如下的熔断规则:

 

apiVersion: istio.alibabacloud.com/v1
kind: ASMCircuitBreaker
metadata:
  name: httpbin-delay
  namespace: knative-serving
spec:
  configs:
    - breaker_config:
        break_duration: 60s
        custom_response:
          body: delay break!
          header_to_add:
            x-envoy-overload: 'true'
          status_code: 498
        max_slow_requests: 5
        min_request_amount: 2
        slow_request_rt: 0.5s
        window_size: 10s
      match:
        vhost:
          name: httpbin-00001-private.default.svc.cluster.local
          port: 8012
  workloadSelector:
    labels:
      app: activator

 

这个规则为activator组件增加了服务熔断能力,上述规则表示了一个针对httpbin-00001 revision的慢请求熔断策略。其中慢请求被定义为响应时间超过0.5s的请求,当在10s的时间窗口内检测到5个及以上的慢请求,后续请求就将被熔断60s,期间所有发往该revision的请求都将直接返回498响应码、响应为delay break!

 

可通过kubeconfig连接到ACK集群或ASM实例来部署上述限流规则:

  •  
kubectl apply -f asmcircuitbreak.yaml

 

同样通过连续请求几次服务的/delay/1路径验证熔断生效:

 

curl -H "host: httpbin.default.example.com" http://116.62.100.25/delay/1
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Forwarded": "for=59.82.59.83;proto=http, for=192.168.0.18",
    "Host": "httpbin.default.example.com",
    "K-Proxy-Request": "activator",
    "Knative-Serving-Default-Route": "true",
    "User-Agent": "curl/8.7.1",
    "X-Client-Address": "59.82.59.83:58368",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-External-Address": "59.82.59.83",
    "X-Envoy-Peer-Metadata": "Ch0KDkFQUF9DT05UQUlORVJTEgsaCWFjdGl2YXRvcgoxCgpDTFVTVEVSX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAoeCgxJTlNUQU5DRV9JUFMSDhoMMTkyLjE2OC4wLjEwChcKDUlTVElPX1ZFUlNJT04SBhoEMS4yMgrEAgoGTEFCRUxTErkCKrYCChIKA2FwcBILGglhY3RpdmF0b3IKKgobYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50EgsaCWFjdGl2YXRvcgorChZhcHAua3ViZXJuZXRlcy5pby9uYW1lEhEaD2tuYXRpdmUtc2VydmluZwolChlhcHAua3ViZXJuZXRlcy5pby92ZXJzaW9uEggaBjEuMTIuNAoTCgRyb2xlEgsaCWFjdGl2YXRvcgokChlzZWN1cml0eS5pc3Rpby5pby90bHNNb2RlEgcaBWlzdGlvCjQKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSERoPa25hdGl2ZS1zZXJ2aW5nCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBjEuMTIuNAouCgdNRVNIX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAokCgROQU1FEhwaGmFjdGl2YXRvci01NWRiNmQ4NzdiLXZyeGJtCh4KCU5BTUVTUEFDRRIRGg9rbmF0aXZlLXNlcnZpbmcKVQoFT1dORVISTBpKa3ViZXJuZXRlczovL2FwaXMvYXBwcy92MS9uYW1lc3BhY2VzL2tuYXRpdmUtc2VydmluZy9kZXBsb3ltZW50cy9hY3RpdmF0b3IKHAoNV09SS0xPQURfTkFNRRILGglhY3RpdmF0b3I=",
    "X-Envoy-Peer-Metadata-Id": "sidecar~192.168.0.10~activator-55db6d877b-vrxbm.knative-serving~knative-serving.svc.cluster.local"
  },
  "origin": "59.82.59.83, 192.168.0.18, 192.168.0.10",
  "url": "http://httpbin.default.example.com/delay/1"
}
curl -H "host: httpbin.default.example.com" http://116.62.100.25/delay/1
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Forwarded": "for=59.82.59.83;proto=http, for=192.168.0.18",
    "Host": "httpbin.default.example.com",
    "K-Proxy-Request": "activator",
    "Knative-Serving-Default-Route": "true",
    "User-Agent": "curl/8.7.1",
    "X-Client-Address": "59.82.59.83:58369",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-External-Address": "59.82.59.83",
    "X-Envoy-Peer-Metadata": "Ch0KDkFQUF9DT05UQUlORVJTEgsaCWFjdGl2YXRvcgoxCgpDTFVTVEVSX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAoeCgxJTlNUQU5DRV9JUFMSDhoMMTkyLjE2OC4wLjEwChcKDUlTVElPX1ZFUlNJT04SBhoEMS4yMgrEAgoGTEFCRUxTErkCKrYCChIKA2FwcBILGglhY3RpdmF0b3IKKgobYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50EgsaCWFjdGl2YXRvcgorChZhcHAua3ViZXJuZXRlcy5pby9uYW1lEhEaD2tuYXRpdmUtc2VydmluZwolChlhcHAua3ViZXJuZXRlcy5pby92ZXJzaW9uEggaBjEuMTIuNAoTCgRyb2xlEgsaCWFjdGl2YXRvcgokChlzZWN1cml0eS5pc3Rpby5pby90bHNNb2RlEgcaBWlzdGlvCjQKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSERoPa25hdGl2ZS1zZXJ2aW5nCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBjEuMTIuNAouCgdNRVNIX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAokCgROQU1FEhwaGmFjdGl2YXRvci01NWRiNmQ4NzdiLXZyeGJtCh4KCU5BTUVTUEFDRRIRGg9rbmF0aXZlLXNlcnZpbmcKVQoFT1dORVISTBpKa3ViZXJuZXRlczovL2FwaXMvYXBwcy92MS9uYW1lc3BhY2VzL2tuYXRpdmUtc2VydmluZy9kZXBsb3ltZW50cy9hY3RpdmF0b3IKHAoNV09SS0xPQURfTkFNRRILGglhY3RpdmF0b3I=",
    "X-Envoy-Peer-Metadata-Id": "sidecar~192.168.0.10~activator-55db6d877b-vrxbm.knative-serving~knative-serving.svc.cluster.local"
  },
  "origin": "59.82.59.83, 192.168.0.18, 192.168.0.10",
  "url": "http://httpbin.default.example.com/delay/1"
}
curl -H "host: httpbin.default.example.com" http://116.62.100.25/delay/1
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Forwarded": "for=59.82.59.83;proto=http, for=192.168.0.18",
    "Host": "httpbin.default.example.com",
    "K-Proxy-Request": "activator",
    "Knative-Serving-Default-Route": "true",
    "User-Agent": "curl/8.7.1",
    "X-Client-Address": "59.82.59.83:58370",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-External-Address": "59.82.59.83",
    "X-Envoy-Peer-Metadata": "Ch0KDkFQUF9DT05UQUlORVJTEgsaCWFjdGl2YXRvcgoxCgpDTFVTVEVSX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAoeCgxJTlNUQU5DRV9JUFMSDhoMMTkyLjE2OC4wLjEwChcKDUlTVElPX1ZFUlNJT04SBhoEMS4yMgrEAgoGTEFCRUxTErkCKrYCChIKA2FwcBILGglhY3RpdmF0b3IKKgobYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50EgsaCWFjdGl2YXRvcgorChZhcHAua3ViZXJuZXRlcy5pby9uYW1lEhEaD2tuYXRpdmUtc2VydmluZwolChlhcHAua3ViZXJuZXRlcy5pby92ZXJzaW9uEggaBjEuMTIuNAoTCgRyb2xlEgsaCWFjdGl2YXRvcgokChlzZWN1cml0eS5pc3Rpby5pby90bHNNb2RlEgcaBWlzdGlvCjQKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSERoPa25hdGl2ZS1zZXJ2aW5nCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBjEuMTIuNAouCgdNRVNIX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAokCgROQU1FEhwaGmFjdGl2YXRvci01NWRiNmQ4NzdiLXZyeGJtCh4KCU5BTUVTUEFDRRIRGg9rbmF0aXZlLXNlcnZpbmcKVQoFT1dORVISTBpKa3ViZXJuZXRlczovL2FwaXMvYXBwcy92MS9uYW1lc3BhY2VzL2tuYXRpdmUtc2VydmluZy9kZXBsb3ltZW50cy9hY3RpdmF0b3IKHAoNV09SS0xPQURfTkFNRRILGglhY3RpdmF0b3I=",
    "X-Envoy-Peer-Metadata-Id": "sidecar~192.168.0.10~activator-55db6d877b-vrxbm.knative-serving~knative-serving.svc.cluster.local"
  },
  "origin": "59.82.59.83, 192.168.0.18, 192.168.0.10",
  "url": "http://httpbin.default.example.com/delay/1"
}
curl -H "host: httpbin.default.example.com" http://116.62.100.25/delay/1
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Forwarded": "for=59.82.59.83;proto=http, for=192.168.0.18",
    "Host": "httpbin.default.example.com",
    "K-Proxy-Request": "activator",
    "Knative-Serving-Default-Route": "true",
    "User-Agent": "curl/8.7.1",
    "X-Client-Address": "59.82.59.83:58373",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-External-Address": "59.82.59.83",
    "X-Envoy-Peer-Metadata": "Ch0KDkFQUF9DT05UQUlORVJTEgsaCWFjdGl2YXRvcgoxCgpDTFVTVEVSX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAoeCgxJTlNUQU5DRV9JUFMSDhoMMTkyLjE2OC4wLjEwChcKDUlTVElPX1ZFUlNJT04SBhoEMS4yMgrEAgoGTEFCRUxTErkCKrYCChIKA2FwcBILGglhY3RpdmF0b3IKKgobYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50EgsaCWFjdGl2YXRvcgorChZhcHAua3ViZXJuZXRlcy5pby9uYW1lEhEaD2tuYXRpdmUtc2VydmluZwolChlhcHAua3ViZXJuZXRlcy5pby92ZXJzaW9uEggaBjEuMTIuNAoTCgRyb2xlEgsaCWFjdGl2YXRvcgokChlzZWN1cml0eS5pc3Rpby5pby90bHNNb2RlEgcaBWlzdGlvCjQKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSERoPa25hdGl2ZS1zZXJ2aW5nCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBjEuMTIuNAouCgdNRVNIX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAokCgROQU1FEhwaGmFjdGl2YXRvci01NWRiNmQ4NzdiLXZyeGJtCh4KCU5BTUVTUEFDRRIRGg9rbmF0aXZlLXNlcnZpbmcKVQoFT1dORVISTBpKa3ViZXJuZXRlczovL2FwaXMvYXBwcy92MS9uYW1lc3BhY2VzL2tuYXRpdmUtc2VydmluZy9kZXBsb3ltZW50cy9hY3RpdmF0b3IKHAoNV09SS0xPQURfTkFNRRILGglhY3RpdmF0b3I=",
    "X-Envoy-Peer-Metadata-Id": "sidecar~192.168.0.10~activator-55db6d877b-vrxbm.knative-serving~knative-serving.svc.cluster.local"
  },
  "origin": "59.82.59.83, 192.168.0.18, 192.168.0.10",
  "url": "http://httpbin.default.example.com/delay/1"
}
curl -H "host: httpbin.default.example.com" http://116.62.100.25/delay/1
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Forwarded": "for=59.82.59.83;proto=http, for=192.168.0.18",
    "Host": "httpbin.default.example.com",
    "K-Proxy-Request": "activator",
    "Knative-Serving-Default-Route": "true",
    "User-Agent": "curl/8.7.1",
    "X-Client-Address": "59.82.59.83:58377",
    "X-Envoy-Attempt-Count": "1",
    "X-Envoy-External-Address": "59.82.59.83",
    "X-Envoy-Peer-Metadata": "Ch0KDkFQUF9DT05UQUlORVJTEgsaCWFjdGl2YXRvcgoxCgpDTFVTVEVSX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAoeCgxJTlNUQU5DRV9JUFMSDhoMMTkyLjE2OC4wLjEwChcKDUlTVElPX1ZFUlNJT04SBhoEMS4yMgrEAgoGTEFCRUxTErkCKrYCChIKA2FwcBILGglhY3RpdmF0b3IKKgobYXBwLmt1YmVybmV0ZXMuaW8vY29tcG9uZW50EgsaCWFjdGl2YXRvcgorChZhcHAua3ViZXJuZXRlcy5pby9uYW1lEhEaD2tuYXRpdmUtc2VydmluZwolChlhcHAua3ViZXJuZXRlcy5pby92ZXJzaW9uEggaBjEuMTIuNAoTCgRyb2xlEgsaCWFjdGl2YXRvcgokChlzZWN1cml0eS5pc3Rpby5pby90bHNNb2RlEgcaBWlzdGlvCjQKH3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLW5hbWUSERoPa25hdGl2ZS1zZXJ2aW5nCi8KI3NlcnZpY2UuaXN0aW8uaW8vY2Fub25pY2FsLXJldmlzaW9uEggaBjEuMTIuNAouCgdNRVNIX0lEEiMaIWM1NjdhMTQ0MGU4YTk0NDQwODI2MDlkOWY1ZTVlMmI2NAokCgROQU1FEhwaGmFjdGl2YXRvci01NWRiNmQ4NzdiLXZyeGJtCh4KCU5BTUVTUEFDRRIRGg9rbmF0aXZlLXNlcnZpbmcKVQoFT1dORVISTBpKa3ViZXJuZXRlczovL2FwaXMvYXBwcy92MS9uYW1lc3BhY2VzL2tuYXRpdmUtc2VydmluZy9kZXBsb3ltZW50cy9hY3RpdmF0b3IKHAoNV09SS0xPQURfTkFNRRILGglhY3RpdmF0b3I=",
    "X-Envoy-Peer-Metadata-Id": "sidecar~192.168.0.10~activator-55db6d877b-vrxbm.knative-serving~knative-serving.svc.cluster.local"
  },
  "origin": "59.82.59.83, 192.168.0.18, 192.168.0.10",
  "url": "http://httpbin.default.example.com/delay/1"
}
curl -H "host: httpbin.default.example.com" http://116.62.100.25/delay/1
delay break!%

 

/delay/1路径会让httpbin服务延迟1秒响应请求,满足慢请求的定义。可以看到连续5次发生慢请求后,后续请求被熔断,返回delay break!

 

 

 

主机级熔断和同可用区优先路由

 

除了服务级熔断外,服务网格ASM还支持开源Istio社区的原生主机级熔断:这种熔断策略以一个服务的若干个端点主机为单位进行。服务网格可以修改精细化activator作出的路由决策,针对同一个Knative服务revision的多个可用端点,服务网格会持续跟踪每个端点主机对请求的响应情况,当某个端点主机持续地返回5xx状态码时,可以暂时地将该主机从可用端点池中移除,以尽量维持服务整体的可用性。

 

要实现主机级熔断,可以直接通过Istio原生的DestinationRule CR来声明:

 

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: httpbin
  namespace: default
spec:
  host: httpbin-00001-private
  trafficPolicy:
    outlierDetection:
      baseEjectionTime: 20s
      consecutiveErrors: 3
      interval: 5s
      maxEjectionPercent: 100

 

上述规则表示当httpbin-00001 revision的某个端点主机在5s内连续三次发生5xx错误时,将该主机从负载均衡池中移除。

 

当前,阿里云ACK集群大多具备多可用区特性,服务网格也支持基于多可用区特性进行工作负载的容灾以及降低服务响应时间。该特性同样给予主机级熔断,只需对服务配置主机级熔断即可启用:当服务存在多个可用端点主机时,网格代理会优先将请求发送到同可用区的主机、以降低请求延迟;而如果同可用区的所有端点都因为故障而处于不可用状态时,网格代理也可以将请求转发到其它可用区中的端点主机、实现灾备能力。

 

 

 

请求优先级调度

 

基于服务网格的无侵入式特性,服务网格ASM还支持更加高级的流量调度套件,支持多种条件下的请求优先级调度能力、请求坡道能力、流量速率并行度限制能力等等。有关流量调度套件的具体介绍、以及如何在集群中开启流量调度套件,可以参考使用ASM流量调度套件进行分布式系统流量控制[4]。请求优先级调度需要在开启ASM流量调度套件的情况下使用。

 

本示例中主要演示流量调度套件的QuotaSchedulingPolicy,这个策略配置使得针对Knative服务的流量速率保持在一定限度之内,同时对超过限度的请求进行优先级调度,具有更高优先级的请求会被更频繁地调度发送给服务。

 

针对上文中部署的httpbin Knative服务,我们可以在流量调度套件中声明以下策略:

 

apiVersion: istio.alibabacloud.com/v1
kind: QuotaSchedulingPolicy
metadata:
  name: quotascheduling
  namespace: istio-system
spec:
  quota_scheduler:
    bucket_capacity: 10
    fill_amount: 10
    rate_limiter:
      interval: 1s
    scheduler:
      workloads:
        - label_matcher:
            match_labels:
              http.request.header.user_type: guest
          parameters:
            priority: 50.0
          name: guest
        - label_matcher:
            match_labels:
              http.request.header.user_type: subscriber
          parameters:
            priority: 200.0
          name: subscriber
    selectors:
    - service: httpbin-00001-private.default.svc.cluster.local

 

这个策略的含义是,将发往httpbin-00001 revision的请求速率始终控制在每秒钟10个的范围之内。对于接收到的超过请求速率限制的请求进行排队,其中具有user_type: guest header的请求相比具有user_type: subscriber header的请求拥有更小的排队优先级,后者的优先级是前者的四倍。

 

通过kubeconfig连接到ASM实例来部署这个声明式策略:

  •  
kubectl apply -f policy.yaml

 

我们可以通过压力测试来查看该策略的效果,这里压测工具fortio进行测试,安装方式请参见安装fortio[5]

 

同时打开两个终端,并分别运行下面两个压测命令(尽可能同时开始这两个测试):

 

测试一:

  •  
fortio load -c 10 -qps 10000  -H "user_type:guest" -H "host: httpbin.default.example.com" -t 30s -timeout 60s -a http://${ASM网关IP}/status/201

 

测试二:

  •  
fortio load -c 10 -qps 10000  -H "user_type:subscriber" -H "host: httpbin.default.example.com" -t 30s -timeout 60s -a http://${ASM网关IP}/status/202

 

测试1的预期输出:

 

...
# target 50% 4.83333
# target 75% 5.20763
# target 90% 5.38203
# target 99% 5.48668
# target 99.9% 5.49714
Sockets used: 10 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false
Code 201 : 70 (100.0 %)
Response Header Sizes : count 70 avg 249.94286 +/- 0.2871 min 248 max 250 sum 17496
Response Body/Total Sizes : count 70 avg 249.94286 +/- 0.2871 min 248 max 250 sum 17496
All done 70 calls (plus 10 warmup) 4566.839 ms avg, 2.1 qps

 

测试2的预期输出:

  •  
...
# target 50% 0.253333
# target 75% 1.875
# target 90% 4.26635
# target 99% 4.47301
# target 99.9% 4.49367
Sockets used: 10 (for perfect keepalive, would be 10)
Uniform: false, Jitter: false
Code 202 : 250 (100.0 %)
Response Header Sizes : count 250 avg 250.264 +/- 0.4408 min 250 max 251 sum 62566
Response Body/Total Sizes : count 250 avg 250.264 +/- 0.4408 min 250 max 251 sum 62566
All done 250 calls (plus 10 warmup) 1226.657 ms avg, 8.0 qps

 

可以看到测试2的平均请求延迟约为测试1的四分之一,QPS约为测试1的四倍。这是由于先前定义的策略中,subscriber类型的请求优先级是guest类型的请求的四倍。同时,两个测试在30秒内总共完成了320个请求,除去最开始预热使用的20个请求,服务收到的请求速率正好是1秒钟10个请求,证明服务收到的请求始终在给定限额之内。

 

 

 

查看Knative服务流量拓扑

 

在为Knative组件注入网格代理后,基于服务网格的可观测能力,可以直接获取到服务流量经过网关转发到后端服务的流量拓扑,进而能够直观地观测到服务的流量状态。有关如何服务网格ASM的网格拓扑能力,可以参考开启网格拓扑提高服务可观测性[6]

 

 

本文中的示例演示了当服务级熔断刚刚发生时网格拓扑所展示的服务状态,使用的服务级熔断配置即为上文的服务级熔断示例。可以看到对于httpbin-00001 revision,有部分的请求没有发往目的地、而是发生了熔断(红线部分),对于从网关访问的所有请求来说、一部分请求发生了失败,处于需要注意的警告状态(黄线部分)。

 

 

 

小结

 

 

本文主要介绍了阿里云Knative与阿里云服务网格ASM结合实现Serverless服务的优势与特点,同时就如何发挥服务网格能力、为Knative服务构建各种自适应的高可用流量管理能力的最佳实践进行了深入的场景化案例介绍。对于企业级应用服务来说,拥有Knative提供的Serverless免运维、弹性以及快速迭代能力,结合服务网格提供的各种高可用流量管理能力可以在低门槛开发迭代云原生服务的同时、保持业务的健壮与稳定性。

 

也欢迎有兴趣的开发者扫描下方二维码加入Knative钉钉技术交流群:

 

 

相关链接:

 

[1]管理全局命名空间

https://help.aliyun.com/zh/asm/user-guide/manage-global-namespaces

 

[2]使用插件市场扩展网格能力

https://help.aliyun.com/zh/asm/user-guide/enable-plug-ins-to-extend-asm-capabilities

 

[3]ASMLocalRateLimiter CRD说明

https://help.aliyun.com/zh/asm/user-guide/description-of-asmlocalratelimiter-fields

 

[4]使用ASM流量调度套件进行分布式系统流量控制

https://help.aliyun.com/zh/asm/user-guide/distributed-system-traffic-control-using-asm-traffic-scheduling-suite/

 

[5]安装fortio

https://github.com/fortio/fortio?tab=readme-ov-file#installation

 

[6]开启网格拓扑提高服务可观测性

https://help.aliyun.com/zh/asm/user-guide/turn-on-the-mesh-topology-to-improve-observability


我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。

欢迎关注 “阿里云基础设施”同名微信微博知乎

获取关于我们的更多信息~

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
存储 Kubernetes 负载均衡
【Service Mesh】最佳实践在哪里-2:多集群流量管理
服务网格 - 多集群流量管理最佳实践相关思考
|
域名解析 存储 网络协议
【Service Mesh】最佳实践在哪里-2.5:多集群服务发现
主要描述服务网格中DNS代理功能在多集群服务发现之中的妙用
|
Kubernetes 监控 负载均衡
service mesh 实现蓝绿发布
service mesh 实现蓝绿发布
|
JSON Kubernetes Cloud Native
【云原生|K8s系列第5篇】:实战使用Service暴露应用
本期文章是K8s系列第5篇,主要是实战使用Service暴露应用。通过本期文章:我们将学习了解 Kubernetes 中的 Service,学习标签(Label) 和 标签选择器(Label Selector) 对象如何与 Service 关联,最后在 Kubernetes 集群外用 Service 暴露应用。 ———————————————— 版权声明:本文为CSDN博主「程序员洲洲」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_51484460/article/details/1260
【云原生|K8s系列第5篇】:实战使用Service暴露应用
|
运维 Kubernetes Cloud Native
Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布|学习笔记(一)
快速学习Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布
Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布|学习笔记(一)
|
运维 Kubernetes Cloud Native
Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布|学习笔记(二)
快速学习Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布
Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布|学习笔记(二)
|
运维 Kubernetes Cloud Native
Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布|学习笔记(一)
快速学习 Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布
Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布|学习笔记(一)
|
运维 Kubernetes Cloud Native
Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布|学习笔记(二)
快速学习 Kubernetes 应用通过 Service Mesh 进行流量切分与灰度发布
|
Prometheus Kubernetes Cloud Native
腾讯云 K8S 集群实战 Service Mesh—Linkerd2 & Traefik2 部署 emojivoto 应用
腾讯云 K8S 集群实战 Service Mesh—Linkerd2 & Traefik2 部署 emojivoto 应用
366 0
腾讯云 K8S 集群实战 Service Mesh—Linkerd2 & Traefik2 部署 emojivoto 应用
|
Prometheus Kubernetes Cloud Native
快速上手 Linkerd v2 Service Mesh(服务网格)
快速上手 Linkerd v2 Service Mesh(服务网格)
256 0
快速上手 Linkerd v2 Service Mesh(服务网格)