为什么在K8s上Web应用的会话会被破坏?~原因和解决方法~
要点是
-
- KubernetesにセッションをもつWebアプリをデプロイした場合を考える.
-
- セッションの保管先は,マシンの内部と外部に分類される.
-
- セッションをマシンの内部にもつと,スケーラビリティが損なわれる.
-
- セッションをマシン内部に保持するアプリをスケーラビリティをもたせる方法は次の2つがある.
Session Affinity
セッション切り出し
スケーラビリティで重要なのはソフトウェアアーキテクチャである.
コンテナでもVMでもマシン内部に状態を保持するとスケーラビリティに課題が生じる.
首先
KubernetesでスケーラビリティをもたせたWebアプリケーションのデプロイをするときに苦労したセッション管理について紹介します.アプリケーションをKubernetesにデプロイする場合の注意点と対策を紹介します.
2. 会议是什么?
HTTPはステートレス(状態をもたない)プロトコルです.そのため,Cookieに代表される識別子を付与することでセッションを実現しています.この記事ではWebアプリケーションにおいてCookieにより実現されるセッションの管理について説明します.
3. 会话存储位置
在Web应用程序中,会话常用于维持登录状态。以下是一些保持会话的方法示例。
-
- マシン内のメモリやファイル
- マシン外のデータベースやKVS
下面是用于识别会话的示例标识符。
-
- Cookie
- HTTPヘッダ
在本章中,我们将比较和讨论会话存储的选项。
3.1. 机器内的内存和文件
通过内存或文件的方式,每台设备会在内部保留会话。通过扩展规模增加设备数量后,每台设备会独立地保留会话。因此,会出现存在会话的设备和不存在会话的设备。

3.2. 机器外的数据库或键值存储(KVS)。
データベースやKVSによる方法では,マシンの外部でセッションを保持しています.マシンが増えてもセッションはマシンの外部で保持するため,マシン間でセッションが共有されます.これにより,どのマシンにアクセスしても同一のセッションを利用することができます.

4. 考虑可伸缩性的问题
マシン内のメモリやファイルを利用する場合,スケールアウトするとマシンごとにセッションが独立するためセッションの不整合が発生します.マシン外のデータベースやKVSを利用する場合は,セッションがマシン間で共有されるためスケールアウトした場合もセッションが壊れません.

以下では,マシン内のメモリやファイルをセッション管理に使うアプリケーションをスケールアウトさせる方法を検討します.
4.1. (方案1) 会话固定
マシン内でセッションを保持するアプリケーションをスケールさせるための方法としてIngress(Serviceのtype:ingress)によるセッション固定があります.これはSession Sticky(Session Affinity)とよばれます.Session StickyをKubernetes上で実現する方法には,Nginx IngressやAmbassadorの利用があります.
以下は,Nginx IngressによるCookieベースのSession Stickyです.
Sticky Sessions – NGINX Ingress Controllerより引用
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-test
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
spec:
rules:
- host: stickyingress.example.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
以下是大使边缘堆栈中使用基于Cookie的会话粘性实现的“Sticky Sessions / Session Affinity”功能。这段引文摘自Ambassador。
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
name: quote-backend
spec:
prefix: /backend/
service: quote
resolver: my-resolver
load_balancer:
policy: ring_hash
cookie:
name: sticky-cookie
ttl: 60s
4.2. (方法2) 分割会话.
要将将会话存储在机器内部的Web应用程序进行扩展,需要对将会话存储在外部的实现进行更改。
如果使用Node.js Web框架Express,在使用connect-redis将会需要对外部Redis存储会话的实现进行修改。
在使用PHP时,通过使用php-redis-extension,可以将会话存储到Redis中,而无需更改实现方法。
通过使用内存中的数据网格(In-Memory Data Grid)来共享机器之间的内存,也许可以实现内存空间的共享。
参考: “限界”を突破する技術、「インメモリデータグリッド」 (1/2) – ITmedia エンタープライズ
4.3. 对比
会话亲和性
-
- メリット: ソフトウェア実装を変更せずにスケーラビリティを高められる.
- デメリット: Session Affinityを実装しているロードバランサ(Ingress)でしか実現できない.
将会话切割
-
- メリット: Session Affinityに比べてアプリケーションとミドルウェアの依存度を下げられる.
- デメリット: ソフトウェア実装の変更が必要になる.
5. おわりに
KubernetesでスケーラビリティをもたせたWebアプリケーションのデプロイをするときに苦労したセッション管理について紹介しました.マシン内部に状態を保持するアーキテクチャのWebアプリケーションはVMやコンテナに関わらず,スケーラビリティに課題が発生することが分かります.ソフトウェア設計においてスケーラビリティを意識して設計できるかは,重要な観点だといえます.
既存のDockerイメージがスケーラビリティを持つかは,Dockerfileやソースコードを読まない限り把握できないのが課題だと考えています.わたし自身もDocker Hubで公開されているDockerイメージがスケーラビリティをもつかの判断に苦労しています.Helmを使った場合も同様にチャートの作者以外がスケーラビリティをもつかは判断しにくいです.
在软件架构设计中考虑到可伸缩性,我认为在使用Kubernetes时能够感到幸福。
请提供相关参考资料。
ACID特性
「トランザクションのACID特性」を理解する:「データベーススペシャリスト試験」戦略的学習のススメ(21) – @IT
Session Affinity
AWS Kubernetes on AWS で sticky session を実現する – ゆびてく
Nginx Ingress KubernetesでのIngress経由のSession Sticky – Qiita
Azure Session affinityを構成したい – Logico Inside
セッション切り出し
PHPセッションをPhpRedisに保存する – Qiita