简介
说明
本文用示例介绍Spring Cloud LoadBalancer如何自定义负载均衡策略。
Spring Cloud LoadBalancer的默认负载均衡策略为轮询策略。我们可以自定义负载均衡策略。自定义负载均衡策略可以用于:灰度发布、蓝绿发布等。
相关网址
Spring Cloud LoadBalancer--默认的负载均衡策略_IT利刃出鞘的博客-CSDN博客
Spring Cloud LoadBalancer--指定负载均衡策略--方法/实例_IT利刃出鞘的博客-CSDN博客
本文目标
本处的场景是:order(订单微服务)调用storage(库存微服务)扣减库存。
启动两个storage(库存微服务),将order的feign请求全部路由到IP为192.168.5.1,端口号为9211的实例上。
基础代码
注意(本处为了简单,直接用@RequestParam传参)
order的controller
package com.knife.order.controller;
import com.knife.common.entity.Result;
import com.knife.order.entity.Order;
import com.knife.storage.api.StorageFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* http://localhost:9011/order/create/?userId=1&productId=1&count=10&money=100
* http://localhost:9011/order/createFault/?userId=1&productId=1&count=10&money=100
*/
@Slf4j
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private StorageFeignClient storageFeignClient;
// 正常流程
@PostMapping("create")
public Result create(Order order) {
log.info("订单服务:创建订单:{}", order);
storageFeignClient.decreaseStorage(order.getProductId(), order.getCount());
return new Result().message("创建订单成功");
}
}
storage的feign定义
package com.knife.storage.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient("storage")
public interface StorageFeignClient {
@PostMapping("/feign/storage/decreaseStorage")
void decreaseStorage(@RequestParam("productId") Long productId, @RequestParam("count") Integer count);
}
storage的controller
package com.knife.storage.feign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
public class FeignController {
@PostMapping("/feign/storage/decreaseStorage")
public void decreaseStorage(@RequestParam("productId")Long productId,
@RequestParam("count")Integer count) {
log.info("库存服务:减少库存。productId: {}, count: {}", productId, count);
}
}
自定义负载均衡策略
自定义策略类
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.knife.order.config;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 强制路由到某个实例
*/
public class ForceLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private static final Log log = LogFactory.getLog(ForceLoadBalancer.class);
private final String serviceId;
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
/**
* @param serviceInstanceListSupplierProvider a provider of
* {@link ServiceInstanceListSupplier} that will be used to get available instances
* @param serviceId id of the service for which to choose an instance
*/
public ForceLoadBalancer(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
String serviceId) {
this.serviceId = serviceId;
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next().map(this::getInstanceResponse);
}
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
if (log.isWarnEnabled()) {
log.warn("No servers available for service: " + serviceId);
}
return new EmptyResponse();
}
// 将特定应用的请求路由到指定实例
String serviceId = "storage";
String host = "192.168.5.1";
int port = 9021;
ServiceInstance instanceResult = null;
for (ServiceInstance instance : instances) {
if (serviceId.equals(instance.getInstanceId())
&& host.equals(instance.getHost())
&& port == instance.getPort()) {
instanceResult = instance;
break;
}
}
// 如果指定的实例不可用,则随机取一个可用的服务
if (instanceResult == null) {
instanceResult = instances.get(0);
}
return new DefaultResponse(instanceResult);
}
}
配置类(不要加@Configuration)
package com.knife.order.config;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
@Configuration
public class LoadBalancerConfiguration {
@Bean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new ForceLoadBalancer(
loadBalancerClientFactory
.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
注册策略配置
package com.knife.order;
import com.knife.common.annotation.CommonApplication;
import com.knife.order.config.LoadBalancerClientConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients("com.knife.**.api")
@LoadBalancerClients(defaultConfiguration = {LoadBalancerConfiguration.class})
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
测试
启动两个storage实例,端口号分别为90211和9022。Idea可以一个应用启动多个实例,方法见这里。
Post方式访问:http://localhost:9011/order/create/?userId=1&productId=1&count=10&money=100
1.默认的负载均衡策略
默认情况下,是轮询策略,调用10次接口的结果如下(每个实例都是5次请求):
2.自定义的负载均衡策略
可以发现,所有请求全部路由到了我们指定的9021实例。
标签:自定义,--,Spring,springframework,annotation,import,org,order,cloud From: https://blog.51cto.com/knifeedge/5825952