一句话总结
负载均衡是将请求均匀分发到多个服务实例上,避免单点过载。分两种:服务端负载均衡(Nginx,客户端 → LB → 服务)和客户端负载均衡(Ribbon/LoadBalancer,客户端自己选实例)。Ribbon 已进入维护模式,Spring Cloud 官方推荐 Spring Cloud LoadBalancer。常见算法:轮询(Round Robin)、随机(Random)、加权(Weighted)、最少连接(Least Connections)、一致性哈希(Consistent Hash)。
初级理解
客户端 vs 服务端负载均衡
| 对比维度 | 客户端负载均衡 | 服务端负载均衡 |
|---|---|---|
| 实现 | Ribbon、LoadBalancer | Nginx、F5、HAProxy |
| 位置 | 服务消费者内部 | 独立中间件 |
| 服务列表 | 从注册中心获取 | 手动配置 |
| 优点 | 无单点、灵活 | 集中管理、功能强 |
| 缺点 | 与语言绑定 | 有单点风险 |
中级深入
常见负载均衡算法
# 1. 轮询(Round Robin)
# 依次分配:实例1 → 实例2 → 实例3 → 实例1...
# 优点:简单、绝对均匀
# 缺点:不考虑服务器性能差异
# 2. 随机(Random)
# 随机选择一个实例
# 优点:简单
# 缺点:可能不均匀
# 3. 加权轮询(Weighted Round Robin)
# 根据权重分配:权重高的实例分配更多请求
# 适用:服务器性能不一致的场景
# 4. 最少连接(Least Connections)
# 选择当前连接数最少的实例
# 适用:长连接场景
# 5. 一致性哈希(Consistent Hash)
# 根据请求参数(如用户 ID)哈希到固定实例
# 优点:同一用户请求始终到同一实例
# 适用:有状态服务、缓存亲和性
LoadBalancer 使用
# Spring Cloud LoadBalancer 配置
spring:
cloud:
loadbalancer:
ribbon:
enabled: false # 禁用 Ribbon
cache:
enabled: true
ttl: 35s # 服务列表缓存时间
# 自定义负载均衡策略
@Configuration
public class LoadBalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(
Environment env, LoadBalancerClientFactory factory) {
String name = env.getProperty("loadbalancer.client.name");
return new RoundRobinLoadBalancer(
factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
高级拓展
一致性哈希原理
# 一致性哈希
# 1. 将哈希空间组织成环(0 ~ 2^32-1)
# 2. 每个节点(服务实例)映射到环上的一个点
# 3. 请求根据 key 哈希,顺时针找到第一个节点
# 优点:节点增减时只影响相邻节点
# 传统哈希:节点数变化 → 几乎所有 key 重新映射
# 一致性哈希:节点数变化 → 只影响约 1/n 的 key
# 虚拟节点:解决数据倾斜
# 每个物理节点映射多个虚拟节点到环上
# 使数据分布更均匀
Ribbon 原理
# Ribbon 核心组件
# 1. ServerList:服务列表(从注册中心获取)
# 2. ServerListFilter:过滤不健康的实例
# 3. IRule:负载均衡策略
# 4. IPing:健康检查
# Ribbon 执行流程
# 1. 从注册中心获取服务列表 → ServerList
# 2. 过滤掉不健康的实例 → ServerListFilter
# 3. 根据策略选择一个实例 → IRule
# 4. 发起 HTTP 调用
# Ribbon 内置策略
# RoundRobinRule:轮询
# RandomRule:随机
# WeightedResponseTimeRule:根据响应时间加权
# BestAvailableRule:选择并发最小的
# ZoneAvoidanceRule:默认,区域感知
实战场景
场景:自定义一致性哈希策略
# 场景:同一用户请求始终路由到同一实例
# 用于缓存亲和性、会话保持
# 自定义 LoadBalancer 配置
@Configuration
public class ConsistentHashConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> consistentHashLoadBalancer(
Environment env, LoadBalancerClientFactory factory) {
String name = env.getProperty("loadbalancer.client.name");
return new ConsistentHashLoadBalancer(
factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
# 使用
@FeignClient(name = "user-service", configuration = ConsistentHashConfig.class)
public interface UserFeignClient { }
面试模拟
面试官:客户端和服务端负载均衡有什么区别?
你:客户端负载均衡在服务消费者内部(Ribbon/LoadBalancer),从注册中心获取服务列表自己选择;服务端负载均衡是独立中间件(Nginx),客户端请求先到 LB 再转发。客户端无单点但和语言绑定,服务端集中管理但有单点风险。
面试官:一致性哈希的原理和优点?
你:将哈希空间组织成环,节点和请求都映射到环上,请求顺时针找第一个节点。优点是节点增减时只影响相邻节点,不会导致大量缓存失效。通过虚拟节点解决数据倾斜问题。