万无一失:网站的高可用架构
1. 高可用的网站架构
- 核心思想:通过分层(应用层、服务层、数据层)和冗余设计,消除单点故障。
- 各层策略:
- 应用层:负载均衡、心跳检测。
- 服务层:集群、分布式服务调用框架、负载均衡、注册中心、心跳检测。
- 数据层:数据同步复制,冗余备份
2. 高可用的应用
2.1 通过负载均衡实现无状态服务的失效转移
核心原理:
在无状态服务集群中,负载均衡器(如 Nginx、HAProxy、LVS)动态管理后端应用服务器节点,通过健康检查机制实时监测节点状态,自动屏蔽故障节点,将请求路由至健康节点,实现服务无缝切换。
1. 无状态服务的前提
- 服务无状态化:
应用服务器不存储本地会话(Session)或上下文数据,用户请求的上下文信息通过外部存储(如 Redis)或请求参数传递。 - 请求可路由性:
任意请求均可由集群中任意节点处理,无需依赖特定节点。
2. 负载均衡器的失效转移流程
-
健康检查(Health Check):
- 主动探测:负载均衡器定期向应用服务器发送心跳请求(如 HTTP GET
/health
)。 - 被动检测:监控请求响应状态(如超时、5xx错误)。
- 判定阈值:连续多次检测失败后标记节点为不可用。
- 主动探测:负载均衡器定期向应用服务器发送心跳请求(如 HTTP GET
-
节点摘除:
- 负载均衡器将故障节点从可用节点池中移除,停止向其分发流量。
-
请求重定向:
- 新请求仅路由至健康节点,用户无感知切换。
-
节点恢复:
- 故障节点恢复后,健康检查通过,重新加入节点池接收流量。
3. 关键技术实现
- 会话一致性保障(可选):
若需会话保持(如临时粘性路由),可通过一致性哈希算法将同一用户请求路由到固定节点,但需权衡容错性。 - 负载均衡器冗余:
避免负载均衡器自身成为单点故障,可采用主备(Keepalived)或集群(Nginx Plus)部署。
4. 总结
通过负载均衡器实现失效转移的核心价值在于:
- 自动化容错:无需人工干预,实时屏蔽故障节点。
- 高可用保障:结合无状态设计,确保服务持续可用。
- 灵活扩展:动态增删节点,适配业务负载变化。
2.2 应用服务器集群的 Session 管理策略
在应用服务器集群中,Session 管理是保障用户状态一致性的核心问题。以下是四种常见的 Session 管理策略,结合书中内容进行详细阐述:
1. Session 复制(Session Replication)
- 实现原理:
每个应用服务器将 Session 数据实时同步到集群中的其他节点,确保所有节点持有相同的 Session 副本。 - 工作流程:
用户请求首次访问某节点生成 Session → 该节点通过组播或同步工具(如 Tomcat 的 DeltaManager)将 Session 广播至其他节点。 - 优点:
- 容错性强:任意节点故障,其他节点可继续服务用户请求。
- 透明切换:用户请求可路由至任意节点,无需重新登录。
- 缺点:
- 网络开销大:同步大量 Session 数据占用带宽,集群规模越大性能越差。
- 数据一致性挑战:同步延迟可能导致短暂状态不一致。
- 适用场景:
小型集群(如 3-5 节点),对容错性要求高且 Session 数据量较小。
2. Session 绑定(Session Sticky)
- 实现原理:
通过负载均衡器(如 Nginx、F5)将同一用户的请求始终路由到固定应用服务器节点。 - 工作流程:
负载均衡器基于用户 IP 或 Cookie 计算哈希值 → 请求定向到特定节点,该节点维护用户 Session。 - 优点:
- 实现简单:无需同步数据,无网络开销。
- 性能高:Session 数据仅存于单节点,读写效率高。
- 缺点:
- 无容错性:绑定节点故障时,用户 Session 丢失,需重新登录。
- 负载不均:用户请求分布依赖哈希算法,可能倾斜。
- 适用场景:
对一致性要求低、可容忍短暂状态丢失的场景(如静态资源服务)。
3. 利用 Cookie 记录 Session
- 实现原理:
将 Session 数据加密后直接存储在客户端的 Cookie 中,每次请求由客户端携带。 - 工作流程:
用户登录 → 服务器生成 Session 数据并加密写入 Cookie → 客户端后续请求自动附带 Cookie → 服务器解密验证。 - 优点:
- 无状态化:服务端无需存储 Session,天然支持水平扩展。
- 容错性强:节点故障不影响用户状态。
- 缺点:
- 安全性风险:Cookie 可能被窃取或篡改(需加密和签名)。
- 存储限制:Cookie 大小受限(通常 ≤4KB),无法存储复杂数据。
- 适用场景:
安全性要求可控、Session 数据量小的场景(如用户基础身份信息)。
4. Session 服务器(集中式 Session 存储)
- 实现原理:
将会话数据统一存储在独立的分布式缓存或数据库中(如 Redis、Memcached),所有应用服务器共享访问。 - 工作流程:
用户登录 → 生成 SessionID 并存储至 Redis → 应用服务器通过 SessionID 读写 Redis 中的会话数据。 - 优点:
- 高可用:Redis 集群保障数据冗余和故障转移。
- 扩展性强:无状态应用服务器可随意扩缩容。
- 缺点:
- 依赖外部存储:Redis 故障可能导致全站会话失效(需保障 Redis 高可用)。
- 网络延迟:每次请求需访问外部存储,增加耗时。
- 适用场景:
中大型分布式系统(如电商平台、社交应用),需高可用和弹性扩展。
5. 对比与选型建议
策略 | 容错性 | 扩展性 | 性能 | 适用规模 |
---|---|---|---|---|
Session 复制 | 高 | 低 | 低 | 小型集群(≤5节点) |
Session 绑定 | 低 | 中 | 高 | 临时性场景 |
Cookie 存储 | 高 | 高 | 中 | 简单会话场景 |
Session 服务器 | 高 | 高 | 中(依赖网络) | 中大型分布式系统 |
书中建议:
- 优先选择 Session 服务器(集中式存储),结合 Redis 集群实现高可用和高性能。
- 对于遗留系统或特定场景,可考虑 Session 绑定 或 Cookie 存储,但需权衡容错性。
- Session 复制 因扩展性差,仅作为过渡方案或小型系统使用。
3. 高可用的服务
3.1 分级管理
- 定义:根据业务重要性将服务划分为不同等级(如核心服务、非核心服务),优先保障核心服务资源。
- 作用:
- 资源隔离:核心服务独占高优先级资源(CPU、带宽)。
- 故障隔离:非核心服务故障不影响核心链路(如支付服务优先于推荐服务)。
- 实践:通过微服务框架(如Spring Cloud)配置服务权重,结合流量调度策略(如Sentinel)动态分配资源。
3.2 超时设置
- 定义:为服务调用(如RPC、HTTP)设置合理超时时间,避免因下游阻塞导致线程池耗尽。
- 作用:
- 快速失败:超时后立即释放资源,防止级联阻塞。
- 用户体验:前端可及时提示或重试。
- 实践:
- 动态超时:根据历史响应时间动态调整(如P99 + 缓冲值)。
- 分层超时:网关层超时 > 服务层超时 > 数据库超时。
3.3 异步调用
- 定义:将非实时、非关键操作(如日志记录、消息推送)异步化,通过消息队列(MQ)解耦。
- 作用:
- 削峰填谷:缓解突发流量压力(如秒杀订单异步处理)。
- 提升吞吐:释放主线程资源,加速核心流程。
- 实践:
- 使用Kafka/RocketMQ实现生产-消费模型。
- 结合线程池或协程(如Go goroutine)处理异步任务。
3.4 服务降级
- 定义:在系统过载或故障时,临时关闭非核心功能,保障核心服务可用。
- 分类:
- 主动降级:提前预案(如大促期间关闭积分兑换)。
- 被动降级:故障触发(如依赖服务超时后返回默认值)。
- 实践:
- 配置开关(如Apollo)动态启停降级逻辑。
- 降级策略:返回缓存数据、静态页面或友好提示。
3.5 幂等性设计
- 定义:同一操作多次执行结果一致,避免重复操作导致数据错误。
- 场景:网络重试、消息重复消费(如订单重复支付)。
- 实现:
- 唯一标识:请求ID、流水号防重(如支付订单号)。
- 数据库约束:唯一索引或乐观锁(version字段)。
- Token机制:客户端提交一次性Token,服务端校验后失效。