可以用几行代码实现一个负载均衡器吗?
- 标签:后端、场景题
🏛 业务架构师
可以,一个最简负载均衡器几行就够——但我会答出层次和边界,这也是这道低难度题的加分方式。
最简版:随机
java
List<String> nodes = List.of("10.0.0.1", "10.0.0.2", "10.0.0.3");
String node = nodes.get(ThreadLocalRandom.current().nextInt(nodes.size()));升级一步:加权轮询(贴近生产)
java
// 权重 5:3:2, 平滑加权轮询
int total = nodes.stream().mapToInt(n -> n.weight).sum();
if (++seq >= total) seq = 0;
// 按累计权重区间选节点我会主动补全的"真负载均衡器"要素(说明理解边界):
- 健康检查:节点摘除与恢复(挂了还往它发流量就是故障放大器)
- 策略选型:
- 轮询/加权:无状态服务
- 一致性哈希:有会话粘性需求(缓存命中、长连接路由)
- 最少连接:请求耗时差异大的场景
- 失败重试与快速切换:转发失败换节点重试一次,对上游透明
业务架构视角收尾:这段代码适合回答"理解原理",但生产负载均衡的投入产出账是另一回事——用 Nginx/Dubbo 内置 LB 或 Spring Cloud LoadBalancer 就好,自研均衡器要处理的服务器探活、慢启动、权重热调等工程细节,价值全部在细节里。几行代码的版本帮我理解"均衡策略只是均衡器 10% 的部分",另外 90% 是可用性工程——这个认知比代码本身重要。
🏗 系统架构师
可以,负载均衡器的最小内核就是一个并发安全的服务列表 + 选择策略,几十行就能写一个可用的客户端 LB。
java
public class SimpleLoadBalancer {
private final List<String> servers = new CopyOnWriteArrayList<>();
private final AtomicInteger idx = new AtomicInteger(0);
public void add(String s) { servers.add(s); }
public void remove(String s) { servers.remove(s); }
public String choose() { // 轮询
List<String> list = servers;
if (list.isEmpty()) return null;
int i = Math.abs(idx.getAndIncrement());
return list.get(i % list.size());
}
}这段代码里每个选型都有讲究:
CopyOnWriteArrayList:读多写少(节点变更低频),保证读不加锁且迭代安全AtomicInteger取模做轮询:CAS 无锁,避免 synchronized 争用;随机策略则直接ThreadLocalRandom.nextInt(n),更简单- 真实调用处包一层 try-catch + 失败重选下一个节点,就有了故障转移雏形
但要说明它与生产级 LB 的差距,这体现架构视野:
- 健康检查:节点列表要由心跳/注册中心驱动(这就是 Ribbon/Spring Cloud LoadBalancer 与服务发现的结合点)
- 策略丰富度:加权轮询(权重=机器配置)、最少并发(
ActiveCount最小者,对慢节点自愈最好)、一致性哈希(会话粘性)、响应时间加权 - 软负载 vs 硬负载:客户端 LB(无单点、少一跳)与服务端 LB(Nginx/LVS,统一管控)的取舍;云原生下还有 service mesh sidecar 模式
- 平滑性:普通轮询在节点增删瞬间会抖动,加权要实现平滑轮询(Nginx 的 smooth weighted 算法)
答题节奏:先爽快写出代码,再用差距分析展示纵深。
💻 全栈开发专家
可以,负载均衡器核心就一句话:从实例列表里按策略挑一个。最小实现几行:
轮询版
java
public class RoundRobin {
private final List<String> servers = List.of("10.0.0.1", "10.0.0.2", "10.0.0.3");
private final AtomicInteger idx = new AtomicInteger();
public String next() {
int i = Math.abs(idx.getAndIncrement() % servers.size());
return servers.get(i);
}
}随机版(更简单,大数下均衡)
java
private final Random r = new Random();
public String next() { return servers.get(r.nextInt(servers.size())); }加权轮询(贴合真实场景)
java
// 权重 5,1,1 -> 平滑加权:每次选 currentWeight 最大者,再各减总权重
public String next() {
int total = servers.stream().mapToInt(s -> s.weight).sum();
Server best = null;
for (Server s : servers) {
s.current += s.weight;
if (best == null || s.current > best.current) best = s;
}
best.current -= total;
return best.host;
}面试加分点:真实负载均衡器(如 Ribbon/LoadBalancer)还要考虑——实例动态上下线(对接注册中心)、健康检查摘除故障节点、一致性哈希(有状态路由)、重试时换节点。上面代码是骨架,生产不重复造轮子。