• 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
  • 相关阅读:
    WinForm DotNetBar 动态添加DataGridView
    调用Excel宏批量处理文件
    jquery datatables+MVC+WCF
    DataTables warning : Requested unknown parameter '0' from the data source for row 0错误
    数据库中判断内容中是否包含中文
    TerraGate SFS Manager配置时权限设置问题
    AutoCAD开发5--批量修改dwg文件
    关闭浏览器时提示的javascript事件
    ArcGIS for JS 离线部署
    [转]ArcGIS for Silverlight:关于尝试连接到REST端点时发生安全异常的解决方案
  • 原文地址:https://www.cnblogs.com/wgslucky/p/10537561.html
Copyright © 2020-2023  润新知