在上一个微服务模拟场景的基础上我们来搭建负载均衡
完整的初级微服务模拟场景点这里!!!
一.Ribbon是什么
1、Sping Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完整的配置项如连接超时,重试等。简单地说,就是在配置文件中列出Load Balancer(简称LB) 后面所有的机器, Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。
负载均衡
2、LB,
即负载均衡(Load Balancer),在微服务或分布式集群中经常用的一种应用。
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)。
常见的负载均衡软件有Nginx,LVS,硬件F5等。
相应的中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
3、集中式LB
即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件F5(好用但是贵),也可以说软件,如nginx),由该设施负责把访问请求通过某种策略转发至服务的提供方。
4、进程内LB
将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。Ribbon就属于进程内LB,它只是一个类库,集成消费方进程,消费方通过它来获取到服务提供方的地址。
二.使用负载均衡带来的好处很明显:
1、当集群里的1台或者多台服务器down的时候,剩余的没有down的服务器可以保证服务的继续使用
2、使用了更多的机器保证了机器的良性使用,不会由于某一高峰时刻导致系统cpu急剧上升
三.搭建微服务的负载均衡
1、修改ribbon初步设置
(1)配置pom文件
<!-- 负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.1.2.RELEASE</version><!--服务器有可不写-->
</dependency>
</dependencies>
(2)因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖。直接修改代码:
在RestTemplate的配置方法上添加 @LoadBalanced 注解:
#在主启动类的中找到RestTemplate加上@LoadBanced
我的主启动类是D:\idea2\cloud-project\user-consumer-project\src\main\java\livia\ConsumerApplication.java
package livia;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @program: cloud-demo-project
* @description
* @author: livia
* @create: 2019-12-26 14:38
**/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDiscoveryClient
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
@Bean
@LoadBalanced//负载均衡需要注解
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
(3)注:新版本不用传入new RestTemplate(new OkHttp3ClientHttpRequestFactory())可不传
修改调用方式,不再手动获取ip和端口,而是直接通过服务名称调用:
原始的获取方式:
@RequestMapping("findall2")
public String findAll2(){
ServiceInstance instans = loadBalancerClient.choose("user-service");
String host = instans.getHost();
int port = instans.getPort();
String urlByEureka = "http://" + host + ":" + port + "/findall";
return restTemplate.getForObject(urlByEureka,String.class);
}
负载均衡后获取方式:
@GetMapping("findall3")
// user-service负载均衡加上之后才可以用
public String findAll3(){
return restTemplate.getForObject("http://user-service/findall",String.class);
}
修改后的整体代码:
package livia.controller;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @program: cloud-project
* @description
* @author: livia
* @create: 2019-12-26 15:47
**/
@RestController
@RequestMapping("/")
public class ConsumerController {
private String SERVICEURL = "http://localhost:1225/findall";
@Autowired
RestTemplate restTemplate;
@Autowired
DiscoveryClient discoveryClient;
@Autowired
LoadBalancerClient loadBalancerClient;
@RequestMapping("findall")
public String findAll(){
// return restTemplate.getForObject(SERVICEURL,String.class);
List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
ServiceInstance instance = instances.get(0);
String host = instance.getHost();
int port = instance.getPort();
String urlByEureka = "http://" + host + ":" + port +"/findall";
return restTemplate.getForObject(urlByEureka,String.class);
}
@RequestMapping("findall2")
public String findAll2(){
//原始的获取方式:"http://" + host + ":" + port + "/findall"
ServiceInstance instans = loadBalancerClient.choose("user-service");
String host = instans.getHost();
int port = instans.getPort();
String urlByEureka = "http://" + host + ":" + port + "/findall";
return restTemplate.getForObject(urlByEureka,String.class);
}
@GetMapping("findall3")
// user-service负载均衡加上之后才可以用
public String findAll3(){
return restTemplate.getForObject("http://user-service/findall",String.class);
}
}
(4)application.yml中添加配置:(D:\idea2\cloud-project\user-consumer-project\src\main\resources\application.yml)
cloud:
loadbalancer:
retry:
enabled: true # 开启Spring Cloud的重试功能
user-service:
ribbon:
ConnectTimeout: 250 # Ribbon的连接超时时间
ReadTimeout: 1000 # Ribbon的数据读取超时时间
OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
MaxAutoRetries: 1 # 对当前实例的重试次数
整体:
server:
port: 1111
spring:
application:
name: user-consumer-project
cloud:
loadbalancer:
retry:
enabled: true # 开启Spring Cloud的重试功能
user-service:
ribbon:
ConnectTimeout: 250 # Ribbon的连接超时时间
ReadTimeout: 1000 # Ribbon的数据读取超时时间
OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
MaxAutoRetries: 1 # 对当前实例的重试次数
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka,http://localhost:10087/eureka
相关配置完成后,我们来启动两个user-service服务实例(一个是原始的8082,在配置一个新的8083):
配置端口(这里我修改name为application2,端口号为8083)点击apply之前要选中name红的Allow parellel run
再点击运行就可以了!
查看服务是否真的启动了:
(1)http://localhost:8083/findall(使用新端口查看)
(2)http://localhost:10086/ 查看user-service进程有几个:
这样即使我们的8082服务器坏掉了,也会有8083服务器继续工作!