About session affinity

Session affinity, also referred to as sticky session, allows you to route requests for a particular session to the same upstream service instance that served the initial request. This setup is particularly useful if you have an upstream service that performs expensive operations and caches the output or data for subsequent requests. With session affinity, you make sure that the expensive operation is performed once and that subsequent requests can be served from the upstream’s cache, which can significantly improve operational cost and response times for your clients.

About the stateful session filter

You can implement strong stickiness for you upstream services by using the Envoy Stateful Session filter. This filter instructs the gateway proxy to pick an upstream service instance that serves the request, encode its address, and to return this value as a header or cookie to the requesting client. If the header or cookie is used in subsequent requests, the gateway proxy forwards all traffic to the instance that served the inital request.

Before you begin

  1. Follow the Get started guide to install Gloo Gateway, set up a gateway resource, and deploy the httpbin sample app.

  2. Get the external address of the gateway and save it in an environment variable.

Choose between the following options to set up the stateful session filter:

Set up header-based session affinity on your gateway proxy. When a request comes in, the proxy chooses an upstream service instance that serves the request, decodes the instance’s address to base64, and stores the base64-encoded value in a header. If the header is provided in subsequent requests, the gateway proxy forwards traffic to the same instance, thereby establishing session affinity.

  1. Scale the httpbin app up to 2 instances.

      kubectl scale deployment httpbin -n httpbin --replicas=2
      
  2. Verify that another instance of the httpbin app is created and note the IP addresses of both httpbin instances. In the following example, you have an httpbin instance available at the 10.0.43.175 and 10.0.38.52 IP addresses.

      kubectl get pods -n httpbin -o wide
      

    Example output

      NAME                      READY   STATUS        RESTARTS   AGE    IP            NODE                          NOMINATED NODE   READINESS GATES
    httpbin-8d557795f-86hzg   3/3     Running       0          54m    10.0.43.175   ip-10-0-34-108.ec2.internal   <none>           <none>
    httpbin-8d557795f-h8ks9   3/3     Running       0          126m   10.0.38.52    ip-10-0-39-74.ec2.internal    <none>           <none>
      
  3. Create an HttpListenerOption resource that enables header-based session affinity on your gateway proxy. In the following example, when a request reaches the proxy, the proxy chooses an upstream service instance to fulfill the request. The proxy encodes the IP address of the instance to base64 and returns it in the x-session-id header.

      kubectl apply -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: HttpListenerOption
    metadata:
      name: session
      namespace: gloo-system
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: http
        namespace: gloo-system
      options:
        statefulSession:
          headerBased:
            headerName: x-session-id
    EOF
      
  4. Send a request to the httpbin app. Verify that you get back a 200 HTTP response code and that you see the base64-encoded value of the httpbin instance that served the inital request in the x-session-id header.

    Example output:

       * Request completely sent off
       < HTTP/1.1 200 OK
       HTTP/1.1 200 OK
       ...
       < x-envoy-upstream-service-time: 0
       x-envoy-upstream-service-time: 0
       < x-session-id: MTAuMC4zOC41Mjo4MDgw
       x-session-id: MTAuMC4zOC41Mjo4MDgw
       < server: envoy
       server: envoy
       ...
       

  5. Optional: Decode the base64-encoded value of the x-session-id header and ensure that this session ID points to one of IP addresses of the httpbin instances that you retrieved earlier.

      echo "MTAuMC4zOC41Mjo4MDgw" | base64 -D
      

    Example output:

      10.0.38.52:8080%
      
  6. Send a few more requests to the httpbin app. This time, you include the session ID that was returned in your first request to direct all requests to the httpbin instance that served the inital request.

  7. Get the logs of the httpbin instance that served the request and verify that all requests were served by the same instance.

      kubectl logs <httpbin-pod> -n httpbin
      

    Example log entry:

      time="2025-03-05T18:57:18.446" status=200 method="GET" uri="/headers" size_bytes=367 duration_ms=0.05 user_agent="curl/8.7.1" client_ip=10.0.XX.XX:45776
      

Set up cookie-based session affinity on your gateway proxy. When a request comes in, the proxy chooses an upstream service instance that serves the request, decodes the instance’s address to base64, and stores the base64-encoded value in a cookie. If the cookie is provided in subsequent requests, the gateway proxy forwards traffic to the same instance, thereby establishing session affinity.

  1. Scale the httpbin app up to 2 instances.

      kubectl scale deployment httpbin -n httpbin --replicas=2
      
  2. Verify that another instance of the httpbin app is created and note the IP addresses of both httpbin instances. In the following example, you have an httpbin instance available at the 10.0.43.175 and 10.0.38.52 IP addresses.

      kubectl get pods -n httpbin -o wide
      

    Example output

      NAME                      READY   STATUS        RESTARTS   AGE    IP            NODE                          NOMINATED NODE   READINESS GATES
    httpbin-8d557795f-86hzg   3/3     Running       0          54m    10.0.43.175   ip-10-0-34-108.ec2.internal   <none>           <none>
    httpbin-8d557795f-h8ks9   3/3     Running       0          126m   10.0.38.52    ip-10-0-39-74.ec2.internal    <none>           <none>
      
  3. Create an HttpListenerOption to set up cookie-based session affinity on your gateway proxy. In the following example, when a request reaches the proxy, the proxy chooses an upstream service instance to fulfill the request. The proxy encodes the IP address of the instance to base64 and returns it in a statefulsessioncookie cookie. The cookie expires after 60 seconds (TTL).

      kubectl apply -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: HttpListenerOption
    metadata:
      name: session
      namespace: gloo-system
    spec:
      targetRefs:
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: http
      options:
        statefulSession:
          cookieBased:
            cookie:
              name: statefulsessioncookie
              path: /
              ttl: 60s
    EOF
      
  4. Send a request to the httpbin app and verify that you see the statefulsessioncookie cookie in the set-cookie header of your response. The -c option stores the cookie in a local file on your machine so that you can use it in subsequent requests.

    Example output:

       HTTP/1.1 200 OK
       ...
       set-cookie: statefulsessioncookie="ChAxMC4wLjQzLjE3NTo4MDgwELerCQ=="; Max-Age=60; Path=/; HttpOnly
       server: envoy
    
       {
         "headers": {
           "Accept": [
             "*/*"
           ],
           "Host": [
             "www.example.com:8080"
           ],
           "User-Agent": [
             "curl/8.7.1"
           ],
           "X-Envoy-Expected-Rq-Timeout-Ms": [
             "15000"
           ],
           "X-Forwarded-Proto": [
             "http"
           ],
           "X-Request-Id": [
             "f1341372-b7ab-4ec2-9d7a-48bf05265c0b"
           ]
         }
       }
       

  5. Optional: Decode the base64-encoded value that was returned in the statefulsessioncookie cookie and ensure that this IP address matches one of IP addresses of the httpbin instances that you retrieved earlier.

      echo "ChAxMC4wLjQzLjE3NTo4MDgwELerCQ==" | base64 -D
      

    Example output:

      10.0.43.175:8080??
      
  6. Send a few more requests to the httpbin app. This time, you include the cookie that you stored in the local file by using the -b option. Make sure to send these requests within the 60 second cookie validity period.

  7. Get the logs of the httpbin instance that served the initial request. Verify that all subsequent requests were also served by the same instance.

      kubectl logs <httpbin-pod> -n httpbin
      

    Example log entry:

      time="2025-03-05T18:57:18.446" status=200 method="GET" uri="/headers" size_bytes=367 duration_ms=0.05 user_agent="curl/8.7.1" client_ip=10.0.XX.XX:45776
      

Cleanup

You can optionally remove the resources that you created in this guide.

  kubectl delete httplisteneroption session -n gloo-system
kubectl scale deployment httpbin -n httpbin --replicas=1