粘性会话的坑与解:不用Sticky Session怎么保登录?

去年一个客户,大促期间扩容,从10台扩到30台。扩完之后,大量用户反馈“购物车空了”“登录状态掉了”。排查发现,他们用了负载均衡的粘性会话(Sticky Session),用户请求一直落在同一台机器上。扩容后,新用户落到了新机器,但老用户的会话还留在老机器。老机器没被摘,但会话没同步到新机器。
这不是扩容,是换了一批机器,用户不认了。
这是粘性会话最经典的翻车现场:它帮你保持了会话,却让你没法弹性伸缩。
今天聊聊粘性会话的坑,以及不用它怎么保登录。
01 粘性会话是什么?
粘性会话,也叫会话保持。负载均衡把同一个用户的请求,始终转发到同一台后端服务器。
常见实现方式:
基于源IP:负载均衡根据客户端IP做哈希。同一IP的请求始终到同一台机器。缺点是办公网出口IP相同,所有用户落到同一台,负载不均。
基于Cookie:负载均衡插入Cookie,标记后端服务器。用户请求带Cookie,就转发到指定机器。
基于应用层Session ID:负载均衡读取请求里的Session ID,做哈希。
那家客户用的是基于Cookie的粘性会话。简单,好用。但扩容时翻车了。
02 粘性会话的四大坑
坑一:负载不均
某些用户请求量大,落到的机器负载高;其他用户请求少,机器空闲。无法充分发挥集群性能。基于源IP时尤其明显。
坑二:扩容/缩容导致会话失效
扩容加新机器,老用户还是只到老机器,新机器接不到老用户,扩容等于白扩。缩容时老机器被摘,老用户的会话直接丢失。那家客户扩到30台,老用户还在10台上,新机器只服务新用户。老机器压力没降,扩容没效果。
坑三:节点故障,会话全丢
一台服务器挂了,这台机器上的所有用户会话丢失,必须重新登录。
坑四:发布、重启影响用户
发布新版本时,重启服务器,上面正在用的用户会话丢失。
03 不用粘性会话:集中会话存储
不把会话存在服务器本地,而是存在一个集中位置。所有服务器共享。
方案一:Redis集中存储
用户登录后,Session存Redis。每次请求,服务器从Redis读Session。
优点:扩容缩容无影响,节点故障会话不丢,所有服务器无状态,任意节点可处理任意请求。
缺点:Redis成为依赖,需要高可用;每次请求多一次Redis访问(毫秒级)。
方案二:JWT客户端存储
Session数据加密后存到Cookie里,服务器不存状态。
优点:无状态,无依赖,扩容无感知。
缺点:数据量有限制(Cookie 4KB),无法主动注销(除非加黑名单),数据泄露风险。
方案三:数据库存储
Session存数据库,最简单。
优点:已有数据库,不用加组件。
缺点:性能差,数据库压力大。
那家客户选了Redis集中存储。用户登录后,Session写Redis,服务器只存Session ID。扩容、重启都不影响用户登录。
04 实在要用粘性会话,怎么减少副作用
有些遗留系统改造成本太高,暂时无法去掉粘性会话。怎么尽量减少问题?
配置会话超时:负载均衡的粘性超时不要设太久。比如15分钟。超过15分钟用户没请求,会话绑定解除,下次请求可能落到其他机器。
配合优雅停机:节点下线前,主动通知负载均衡不再发新请求,等现有会话处理完再关。避免用户直接掉线。
会话备份:关键系统,会话在多个节点间备份。一台挂了,另一台能接管。
那家客户改造期间,先加了优雅停机。发布时不再直接重启,而是先摘流量,等现有会话结束后再重启。用户不再掉线。
05 什么时候可以接受粘性会话?
粘性会话不是罪大恶极。有些场景可以接受。
内部系统:用户少,负载不高,集群规模稳定。扩容缩容不频繁,节点故障影响面小。
低流量系统:个人博客、小工具。挂了对业务影响小。
缓存场景:本地缓存,不希望请求跨节点。
核心交易系统、高并发、弹性伸缩频繁的系统,尽量不用粘性会话。
06 一个真实案例:改造后扩容无感
那家客户,改造前:粘性会话 + 10台机器。大促扩容到30台,老用户登录状态丢失,投诉炸锅。
改造后:
会话存Redis(集群+主从,高可用)
服务器无状态,任意节点可处理任意请求
负载均衡轮询转发(不用粘性会话)
下一次大促,从容扩容到50台。用户登录状态全程在线。运维负责人说:“以前扩容像换血,用户掉一批;现在扩容像加菜,用户没感觉。”
写在最后
粘性会话是一把双刃剑。简单省事,但后患无穷。
那家客户的运维负责人后来总结:“能不用就不用,实在要用也要配超时、配优雅停机、配会话备份。最好是把会话集中存,让服务器无状态。”
你的系统,用户登录状态存哪了?今天就要去看。