面试题答案
一键面试更适合的负载均衡策略及原因
在高并发的微服务场景下,加权轮询负载均衡策略相对更适合。原因如下:
- 均匀分配请求:轮询策略可以将请求均匀地分配到各个实例上,避免某个实例过度负载,在一定程度上保证各实例资源利用的均衡性。但它没有考虑实例的性能差异。
- 考虑实例性能:加权轮询策略在轮询的基础上,根据实例的性能为每个实例分配不同的权重。性能好的实例权重高,会被分配到更多的请求;性能差的实例权重低,接收的请求相对较少。这样既能充分利用高性能实例的资源,又不会让低性能实例过载,更适合高并发场景下不同性能的实例共同处理请求的情况。
在Spring Cloud Gateway中配置加权轮询负载均衡策略
- 引入依赖:如果使用Spring Cloud Alibaba Nacos作为服务注册中心(Nacos自带负载均衡功能支持加权轮询等策略),在
pom.xml
中添加Nacos客户端和负载均衡相关依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
- 配置Nacos服务发现:在
application.yml
中配置Nacos服务发现相关参数:
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # Nacos服务器地址
- 配置负载均衡策略:在
application.yml
中配置使用加权轮询负载均衡策略,以访问名为user-service
的服务为例:
spring:
cloud:
loadbalancer:
loadbalancers:
user-service:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
这里NacosRule
就是Nacos提供的支持加权轮询的负载均衡规则。如果不使用Nacos,也可以通过自定义负载均衡规则来实现加权轮询策略,具体步骤如下:
- 创建自定义负载均衡规则类:实现
IRule
接口,在choose
方法中实现加权轮询逻辑。例如:
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class WeightedRoundRobinRule implements IRule {
private ILoadBalancer lb;
private AtomicInteger nextServerCyclicCounter;
public WeightedRoundRobinRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}
@Override
public Server choose(Object key) {
if (lb == null) {
return null;
}
List<Server> upList = lb.getReachableServers();
List<Server> allList = lb.getAllServers();
int serverCount = upList.size();
if (serverCount == 0) {
return null;
}
int totalWeight = 0;
for (Server server : upList) {
// 假设服务器实例有getWeight方法获取权重
int weight = server.getWeight();
totalWeight += weight;
}
int currentIndex = incrementAndGetModulo(serverCount);
int weightIndex = currentIndex;
int currentWeight = 0;
do {
Server server = upList.get(weightIndex);
// 假设服务器实例有getWeight方法获取权重
currentWeight += server.getWeight();
if (currentWeight * serverCount >= totalWeight * (currentIndex + 1)) {
return server;
}
weightIndex = (weightIndex + 1) % serverCount;
} while (weightIndex != currentIndex);
return upList.get(currentIndex);
}
private int incrementAndGetModulo(int modulo) {
for (; ; ) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
@Override
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
@Override
public ILoadBalancer getLoadBalancer() {
return lb;
}
}
- 配置自定义负载均衡规则:在配置类中注入自定义的负载均衡规则:
import com.netflix.loadbalancer.IRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class LoadBalancerConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public IRule ribbonRule() {
return new WeightedRoundRobinRule();
}
}
这样就可以在Spring Cloud Gateway中使用自定义的加权轮询负载均衡策略。