重庆知名做网站的公司,5万左右的新能源汽车推荐,dw建设网站视频,网站网上推广文章目录 多机部署,负载均衡-LoadBalance1. 开启多个服务2. 什么是负载均衡负载均衡的实现客户端负载均衡 3. Spring Cloud LoadBalance快速上手使用Spring Cloud LoadBalance实现负载均衡修改IP,端口号为服务名称启动多个服务 负载均衡策略自定义负载均衡策略 LoadBalance原理… 文章目录 多机部署,负载均衡-LoadBalance1. 开启多个服务2. 什么是负载均衡负载均衡的实现客户端负载均衡 3. Spring Cloud LoadBalance快速上手使用Spring Cloud LoadBalance实现负载均衡修改IP,端口号为服务名称启动多个服务 负载均衡策略自定义负载均衡策略 LoadBalance原理 多机部署,负载均衡-LoadBalance
1. 开启多个服务 多复制两个服务,将服务全部启动起来 此时多次访问原来的接口,发现 调用的还是同一个
我们对代码进行修改:
Service
public class OrderService {private static final Logger log LoggerFactory.getLogger(OrderService.class);Autowiredprivate OrderMapper orderMapper;Resourceprivate DiscoveryClient discoveryClient;Autowiredprivate RestTemplate restTemplate;private static AtomicInteger atomicInteger new AtomicInteger(1);private static ListServiceInstance instances;PostConstructpublic void init() {instances discoveryClient.getInstances(product-service);}public OrderInfo getOrderList(int orderId){OrderInfo orderInfo orderMapper.getOrderList(orderId);int index atomicInteger.getAndIncrement() % instances.size();EurekaServiceInstance instance (EurekaServiceInstance) instances.get(index);String url instance.getUri() /product/getProduct?productId orderInfo.getProductId();log.info(url);ProductInfo productInfo restTemplate.getForObject(url,ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}
}通过轮询的方式去将请求均衡的分配到不同的实例上,这就是负载均衡 2. 什么是负载均衡
负载均衡是高并发,高可用系统必不可少的关键组件
当服务流量增大的时候,通常会采用增加机器的方式进行扩容,负载均衡就是用来在多个机器或者其他资源中,按照一定的规则合理分配负载,也就是负载均衡策略
负载均衡的实现
负载均衡分为服务端负载均衡和客户端负载均衡
服务端负载均衡 指的是在服务端进行负载均衡的算法分配
例如Nginx就是比较出名的服务端负载均衡器,请求会先到达Nginx负载均衡器,然后通过负载均衡算法,在多个服务器之间选择一个进行访问 客户端负载均衡
在客户端进行负载均衡的算法分配
就是将负载均衡的功能以库的方式集成到客户端,而不是由一台指定的负载均衡设备集中提供
比如Spring Cloud的Ribbon,请求发送到客户端,客户端从注册中心(比如Eureka)获取服务列表,在发送请求的时候通过负载均衡算法一个服务器,然后进行访问
但是Ribbon是Spring Cloud早期的默认实现,由于不维护了,现在最新版本的Spring Cloud 负载均衡集成的是Spring Cloud LoadBalance(Spring Cloud官方维护) 客户端负载均衡器和服务端负载均衡器的最大区别在于服务清单存储的位置
3. Spring Cloud LoadBalance
快速上手
使用Spring Cloud LoadBalance实现负载均衡
给RestTemplate这个Bean 添加 LoadBalance注解
Configuration
public class BeanConfig {LoadBalancedBeanpublic RestTemplate restTemplate() {return new RestTemplate();}
}修改IP,端口号为服务名称
Service
public class OrderService {private static final Logger log LoggerFactory.getLogger(OrderService.class);Autowiredprivate OrderMapper orderMapper;Autowiredprivate RestTemplate restTemplate;public OrderInfo getOrderList(int orderId){OrderInfo orderInfo orderMapper.getOrderList(orderId);String url http://product-service/product/getProduct?productId orderInfo.getProductId();log.info(url);ProductInfo productInfo restTemplate.getForObject(url,ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;}
}启动多个服务 进行6次访问
为了方便观察,我们在product-service里面加上日志 此时进行访问 可以看到请求被均匀的分布在3个实例上
负载均衡策略
负载均衡策略是一种思想,无论是哪种负载均衡,他们的负载均衡策略都是相似的.Spring Cloud LoadBalance仅支持两种负载均衡策略:轮询策略以及随机策略
轮询:轮询策略指的是服务器轮流处理用户的请求.这是一种实现最简单,也最常用的策略随机选择:随机选择策略是指随机选择一个后端服务器来处理新的请求
自定义负载均衡策略
Spring Cloud LoadBalance默认的负载均衡策略是轮询策略.实现是RoundRobinLoadBalance
如果想使用随机的负载均衡策略:
定义随机算法对象,通过Bean将其加载到Spring容器里面
这里我们使用Spring Cloud LoadBalancer提供的RandomLoadBalance
public class LoadBalanceConfig {BeanReactorLoadBalancerServiceInstance randomLoadBalance(Environment env, LoadBalancerClientFactory clientFactory) {String name env.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);return new RandomLoadBalancer(clientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),name);}
}注意:不用Configuration注释,要求这个类在组件扫描范围内
使用LoadBalancerClieent或者LoadBalancerClients注解在RestTemplate配置类上方,就可以实现对不同的服务提供方配置不同的客户端负载均衡算法策略
LoadBalancerClient(name product-service,configuration LoadBalanceConfig.class)
Configuration
public class BeanConfig {LoadBalancedBeanpublic RestTemplate restTemplate() {return new RestTemplate();}
}其中,name表示该负载均衡策略对哪个服务生效(服务提供方),Configuration表示负载均衡策略
LoadBalance原理
LoadBalance的实现,主要是LoadBalanceInterceptor,这个类会对RestTemplate的请求进行拦截,然后从Eureka根据服务id获取服务列表,然后利用负载均衡算法得到真实的服务地址信息,替换服务Id public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {private LoadBalancerClient loadBalancer;private LoadBalancerRequestFactory requestFactory;public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {this.loadBalancer loadBalancer;this.requestFactory requestFactory;}public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));}public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {URI originalUri request.getURI();String serviceName originalUri.getHost();Assert.state(serviceName ! null, Request URI does not contain a valid hostname: originalUri);return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));}
}主要就是看intercept方法,拦截了用户的请求后,做了以下几件事:
request.getURI()从请求中获取urioriginalUri.getHost()从uri中获取路径的主机名,也就是服务IdloadBalancer.execute根据服务Id,进行负载均衡,并处理请求
我们继续看execute方法
public T T execute(String serviceId, LoadBalancerRequestT request) throws IOException {
String hint this.getHint(serviceId);
LoadBalancerRequestAdapterT, TimedRequestContext lbRequest new LoadBalancerRequestAdapter(request, this.buildRequestContext(request, hint));
SetLoadBalancerLifecycle supportedLifecycleProcessors this.getSupportedLifecycleProcessors(serviceId);
supportedLifecycleProcessors.forEach((lifecycle) - {lifecycle.onStart(lbRequest);
});
// 根据serviceId,和负载均衡策略,选择处理的服务
ServiceInstance serviceInstance this.choose(serviceId, lbRequest);
if (serviceInstance null) {supportedLifecycleProcessors.forEach((lifecycle) - {lifecycle.onComplete(new CompletionContext(Status.DISCARD, lbRequest, new EmptyResponse()));});throw new IllegalStateException(No instances available for serviceId);
} else {return this.execute(serviceId, serviceInstance, lbRequest);
}
}public T ServiceInstance choose(String serviceId, RequestT request) {// 获取负载均衡器ReactiveLoadBalancerServiceInstance loadBalancer this.loadBalancerClientFactory.getInstance(serviceId);if (loadBalancer null) {return null;} else {// 根据负载均衡算法,在列表中选择一个服务实例ResponseServiceInstance loadBalancerResponse (Response)Mono.from(loadBalancer.choose(request)).block();return loadBalancerResponse null ? null : (ServiceInstance)loadBalancerResponse.getServer();}
}