更新时间:2024-01-04 GMT+08:00

通过负载均衡配置实现会话保持

概念

会话保持是负载均衡最常见的问题之一,也是一个相对比较复杂的问题。

会话保持有时候又叫做粘滞会话(Sticky Sessions),开启会话保持后,负载均衡会把来自同一客户端的访问请求持续分发到同一台后端云服务器上进行处理。

在介绍会话保持技术之前,必须先花点时间弄清楚一些概念:什么是连接(Connection)、什么是会话(Session),以及这二者之间的区别。需要特别强调的是,如果仅仅是谈论负载均衡,会话和连接往往具有相同的含义。

从简单的角度来看,如果用户需要登录,那么就可以简单的理解为会话;如果不需要登录,那么就是连接。

实际上,会话保持机制与负载均衡的基本功能是完全矛盾的。负载均衡希望将来自客户端的连接、请求均衡的转发至后端的多台服务器,以避免单台服务器负载过高;而会话保持机制却要求将某些请求转发至同一台服务器进行处理。因此,在实际的部署环境中,需要根据应用环境的特点,选择适当的会话保持机制。

四层负载均衡(Service)

四层的模式下可以开启基于源IP的会话保持(基于客户端的IP进行hash路由),Service上开启基于源IP的会话保持需要满足以下条件:
  1. Service的服务亲和级别选择“节点级别”(即Service的externalTrafficPolicy字段为Local)。

    CCE Turbo集群无需设置该参数。

  2. Service的负载均衡配置启用源IP地址会话保持。
    apiVersion: v1
    kind: Service
    metadata:
      name: svc-example
      namespace: default
      annotations:
        kubernetes.io/elb.class: union
        kubernetes.io/elb.id: 56dcc1b4-8810-480c-940a-a44f7736f0dc
        kubernetes.io/elb.lb-algorithm: ROUND_ROBIN
        kubernetes.io/elb.session-affinity-mode: SOURCE_IP
    spec:
      selector: 
        app: nginx
      externalTrafficPolicy: Local   # CCE Turbo集群无需设置该参数
      ports:
        - name: cce-service-0
          targetPort: 80
          nodePort: 32633
          port: 80
          protocol: TCP
      type: LoadBalancer
  3. Service后端的应用开启反亲和。

七层负载均衡(Ingress)

7层的模式下可以开启基于http cookie和app cookie的会话保持 ,在ingress上开启基于cookie的会话保持需要满足以下条件:

  1. Ingress对应的应用(工作负载)应该开启与自身反亲和。
  2. Ingress对应的service需要开启节点亲和。

操作步骤:

  1. 创建nginx工作负载。

    实例数设置为3,通过工作负载反亲和设置Pod与自身反亲和。
    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: nginx
      namespace: default
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
            - name: container-0
              image: 'nginx:perl'
              resources:
                limits:
                  cpu: 250m
                  memory: 512Mi
                requests:
                  cpu: 250m
                  memory: 512Mi
          imagePullSecrets:
            - name: default-secret
          affinity:
            podAntiAffinity:                   # Pod与自身反亲和
              requiredDuringSchedulingIgnoredDuringExecution:
                - labelSelector:
                    matchExpressions:
                      - key: app
                        operator: In
                        values:
                          - nginx
                  topologyKey: kubernetes.io/hostname

  2. 创建NodePort类型Service。

    会话保持的配置在Service这里设置,Ingress可以对接多个Service,每个Service可以有不同的会话保持配置。
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      namespace: default
      annotations:
        kubernetes.io/elb.lb-algorithm: ROUND_ROBIN
        kubernetes.io/elb.session-affinity-mode: HTTP_COOKIE      # HTTP Cookie类型
        kubernetes.io/elb.session-affinity-option: '{"persistence_timeout":"1440"}'   # 会话保持时间,单位为分钟,取值范围为1-1440
    spec:
      selector:
        app: nginx
      ports:
        - name: cce-service-0
          protocol: TCP
          port: 80
          targetPort: 80
          nodePort: 32633            # 节点端口
      type: NodePort
      externalTrafficPolicy: Local   # 节点级别转发

    还可以选择应用程序Cookie,如下所示。

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      namespace: default
      annotations:
        kubernetes.io/elb.lb-algorithm: ROUND_ROBIN
        kubernetes.io/elb.session-affinity-mode: APP_COOKIE     # 选择应用程序Cookie
        kubernetes.io/elb.session-affinity-option: '{"app_cookie_name":"test"}'  # 应用程序Cookie名称
    ...

  3. 创建Ingress,关联Service。

    apiVersion: networking.k8s.io/v1
    kind: Ingress 
    metadata: 
      name: ingress-test
      namespace: default
      annotations: 
        kubernetes.io/elb.class: union
        kubernetes.io/elb.port: '80'
        kubernetes.io/elb.autocreate: 
          '{
              "type":"public",
              "bandwidth_name":"cce-bandwidth-test",
              "bandwidth_chargemode":"traffic",
              "bandwidth_size":1,
              "bandwidth_sharetype":"PER",
              "eip_type":"5_bgp"
            }'
    spec:
      rules: 
      - host: 'www.example.com'
        http: 
          paths: 
          - path: '/'
            backend: 
              service:
                name: nginx     # Service的名称
                port: 
                  number: 80
            property:
              ingress.beta.kubernetes.io/url-match-mode: STARTS_WITH
            pathType: ImplementationSpecific
      ingressClassName: cce

  4. 登录ELB控制台,进入对应的ELB实例,查看会话保持是否开启。