在微服务开发中,使用Spring Cloud Gateway作为服务的网关,网关后面启动N个业务服务。可是有这样一个需求,同一个用户的操做,有时候须要保证顺序性,若是使用默认负载均衡策略,同一个用户的请求可能会转发到不一样的服务实例上面。因此须要实现一个负载均衡规则。java
1,重写LoadBalancerClientFilterweb
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,添加自定义的负载规则spring
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. 添加Beanapache
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