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