Spring Cloud Gateway Ribbon 自定义负载均衡


 依赖的spring cloud版本信息:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.15.RELEASE</version>
    </parent>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

 

在微服务开发中,使用Spring Cloud Gateway做为服务的网关,网关后面启动N个业务服务。但是有这样一个需求,同一个用户的操作,有时候需要保证顺序性,如果使用默认负载均衡策略,同一个用户的请求可能会转发到不同的服务实例上面。所以需要实现一个负载均衡规则。

1,重写LoadBalancerClientFilter

 import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; import java.net.URI; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.gateway.config.LoadBalancerProperties; import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; import org.springframework.web.server.ServerWebExchange; public class UserLoadBalancerClientFilter extends LoadBalancerClientFilter { public UserLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties) { super(loadBalancer, properties); } @Override protected ServiceInstance choose(ServerWebExchange exchange) { //这里可以拿到web请求的上下文,可以从header中取出来自己定义的数据。 String userId = exchange.getRequest().getHeaders().getFirst("userId"); if (userId == null) { return super.choose(exchange); } if (this.loadBalancer instanceof RibbonLoadBalancerClient) { RibbonLoadBalancerClient client = (RibbonLoadBalancerClient) this.loadBalancer; String serviceId = ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(); //这里使用userId做为选择服务实例的key return client.choose(serviceId, userId); } return super.choose(exchange); } }

 

2,添加自定义的负载规则

 import java.util.List; import org.apache.commons.lang.math.RandomUtils; import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.AbstractLoadBalancerRule; import com.netflix.loadbalancer.Server; /** * * @ClassName: GameCenterBalanceRule * @Description: 根据userId对服务进行负载均衡。同一个用户id的请求,都转发到同一个服务实例上面。 * @author: wgs * @date: 2019年3月15日 下午2:17:06 */ public class GameCenterBalanceRule extends AbstractLoadBalancerRule { @Override public Server choose(Object key) {//这里的key就是过滤器中传过来的userId List<Server> servers = this.getLoadBalancer().getReachableServers(); if (servers.isEmpty()) { return null; } if (servers.size() == 1) { return servers.get(0); } if (key == null) { return randomChoose(servers); } return hashKeyChoose(servers, key); } /** * * <p>Description:随机返回一个服务实例 </p> * @param servers * @return * @author wgs * @date 2019年3月15日 下午2:25:23 * */ private Server randomChoose(List<Server> servers) { int randomIndex = RandomUtils.nextInt(servers.size()); return servers.get(randomIndex); } /** * * <p>Description:使用key的hash值,和服务实例数量求余,选择一个服务实例 </p> * @param servers * @param key * @return * @author wgs * @date 2019年3月15日 下午2:25:36 * */ private Server hashKeyChoose(List<Server> servers, Object key) { int hashCode = Math.abs(key.hashCode()); if (hashCode < servers.size()) { return servers.get(hashCode); } int index = hashCode % servers.size(); return servers.get(index); } @Override public void initWithNiwsConfig(IClientConfig config) { } } 

 

3.  添加Bean

import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.gateway.config.LoadBalancerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class LoadBalancedBean { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } @Bean public UserLoadBalancerClientFilter userLoadBalanceClientFilter(LoadBalancerClient client, LoadBalancerProperties properties) { return new UserLoadBalancerClientFilter(client, properties); } }

 


欢迎添加QQ交流群:398808948,677464431


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM