首页 > 其他分享 >Spring Cloud LoadBalancer--自定义负载均衡策略--方法/实例

Spring Cloud LoadBalancer--自定义负载均衡策略--方法/实例

时间:2022-11-05 14:02:31浏览次数:70  
标签:自定义 -- Spring springframework annotation import org order cloud


简介

说明

        本文用示例介绍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次请求):

Spring Cloud LoadBalancer--自定义负载均衡策略--方法/实例_java

Spring Cloud LoadBalancer--自定义负载均衡策略--方法/实例_spring cloud_02

2.自定义的负载均衡策略

可以发现,所有请求全部路由到了我们指定的9021实例。

Spring Cloud LoadBalancer--自定义负载均衡策略--方法/实例_spring_03

Spring Cloud LoadBalancer--自定义负载均衡策略--方法/实例_负载均衡_04

标签:自定义,--,Spring,springframework,annotation,import,org,order,cloud
From: https://blog.51cto.com/knifeedge/5825952

相关文章

  • 数据库事务
    事务是逻辑上的一组操作,要么都执行,要么都不执行。事务的四大特性(ACID)原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用......
  • [Linux]----文件操作(重定向+缓冲区)
    文章目录​​前言​​​​一、重定向​​​​具体操作​​​​dup2​​​​二、关于缓冲区的理解​​​​1.什么是缓冲区​​​​2.为什么要有缓冲区​​​​3.缓冲区在......
  • containerd和shim通信
    containerd-shim-runc-v2启动了一个ttrpcserver(类似grpc)containerd通过ttrpc和containerd-shim-runc-v2 通信来管理容器serviceTask{ rpcState(StateReques......
  • 关于rocketmq 中日志文件路径的配置
    rocketmq中的数据和日志文件默认都是存储在​​user.home​​路径下面的,往往我们都需要修改这些路径到指定文件夹以便管理。服务端日志网上搜索rocketmq日志存储路径的修改......
  • Atomsk孪晶多晶建模方法
    大家好,我是小马老师。本文介绍atomsk孪晶多晶建模方法。atomsk多晶建模的原理是先建立一个晶胞,然后编写一个polycrystal.txt文件,设定最终模型的尺寸和晶粒的个数。atomsk按......
  • 29. 两数相除
    29.两数相除题解:a/b=y等价于b>a-(b*y)>0,只要求出减了多少次b就好了。一个一个地减b,效率太低了,最坏情况下,a=2^31-1,b=1,超时;应该先预......
  • JS中的变量声明
    一、引入1.定义:在JavaScript中创建变量被称为“声明”变量。JavaScript中变量声明又分为显示声明和隐式声明。其中显示声明中,被“声明”变量之前的关键词有var、let、cons......
  • Typora打不开了
    按Windows+R打开运行窗口,输入regedit,点确定,打开注册表,依次展开计算机\HKEY_CURRENT_USER\SOFTWARE\Typora,然后在Typora上右键,点权限,选中Administrtors,把权限全部设置为拒......
  • Jmeter断言之Xpath Assertion
    Xpath:XML路径语言(XMLPathLanguage),它是一种用来确定XML文档中某部分位置的语言。首先添加XpathAssertionXpathAssertion界面......
  • 分数求和
    【题目名称】分数求和【题目内容】计算1/1-1/2+1/3-1/4+1/5……+1/99-1/100的值,打印出结果第一种:运用两个for循环 ,整体思路为:1/1+1/3+1/5+.....+1/99和1/2+1/4+1/6......