什么是负载均衡(Load Balance)
分配访问具体哪个服务节点,就是负载均衡
原理是将数据流量分摊到多个服务器执行,减轻每台服务器的压力,从而提高了数据的吞吐量
软硬件角度负载均衡的种类
通过硬件来进行解决,常见的硬件有NetScaler、F5、Radware和Array等商用的负载均衡器,但比较昂贵的
通过软件来进行解决,常见的软件有LVS、Nginx等,它们是基于Linux系统并且开源的负载均衡策略
从端的角度负载均衡有两种
- 1.服务端负载均衡
请求发起后 由负载均衡再决定分发到哪个服务节点
- 2.客户端负载均衡
谁请求谁决定访问哪个服务节点
常见的负载均衡策略(看组件的支持情况)
- 节点轮询
简介:每个请求按顺序分配到不同的后端服务器
- weight 权重配置
简介:weight和访问比率成正比,数字越大,分配得到的流量越高
- 固定分发
简介:根据请求按访问ip的hash结果分配,这样每个用户就可以固定访问一个后端服务器
- 随机选择、最短响应时间等等
AlibabaCloud集成Ribbon实现负载均衡
什么是Ribbon
Ribbon是一个客户端负载均衡工具,通过Spring Cloud封装,可以轻松和AlibabaCloud整合
用法: 加了@LoadBalanced
注解,就有负载均衡的功能。
修改online-edu-order-service/src/main/java/org/online_edu/OrderApplication.java
@SpringBootApplication()
@MapperScan("org.online_edu.dao")
@EnableDiscoveryClient
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
测试验证(客户端负载均衡)
2个实体类增加一个测试字段:
Video.java和VideoOrder.java
//测试
private String serveInfo;
public String getServeInfo() {
return serveInfo;
}
public void setServeInfo(String serveInfo) {
this.serveInfo = serveInfo;
}
修改VideoController.java
@RestController
@RequestMapping("api/v1/video")
public class VideoController {
@Autowired
private VideoService videoService;
@RequestMapping("/find_by_id")
public Video findById(@RequestParam(name = "videoId") int videoId, HttpServletRequest request) {
Video video = videoService.findById(videoId);
// 拿到服务端的id+端口
video.setServeInfo(request.getServerName() + ":" + request.getServerPort());
return video;
}
}
修改VideoOrderController.java
@RestController
@RequestMapping("/api/v1/video_order")
public class VideoOrderController {
/**
* 服务对象
*/
@Autowired
private VideoOrderService videoOrderService;
@Autowired
private RestTemplate restTemplate;
/**
* 可以拉到注册服务的列表
*/
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("save")
public Object save(@RequestParam(name = "videoId") int videoId) {
// Video video = restTemplate.getForObject(
// "http://localhost:9000/api/v1/video/find_by_id?videoId=" + videoId, Video.class);
// 传入在nacos注册的服务名
// List<ServiceInstance> list = discoveryClient.getInstances("online-edu-video-service");
// ServiceInstance serviceInstance = list.get(0);
//
//
// Video video = restTemplate.getForObject(
// "http://" + serviceInstance.getHost() +":"+serviceInstance.getPort()+ "/api/v1/video/find_by_id?videoId=" + videoId, Video.class);
Video video = restTemplate.getForObject(
"http://online-edu-video-service/api/v1/video/find_by_id?videoId=" + videoId, Video.class);
VideoOrder videoOrder = new VideoOrder();
if (video != null) {
videoOrder.setServeInfo(video.getServeInfo());
videoOrder.setVideoId(video.getId());
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setCreateTime(new Date());
}
return videoOrder;
}
}
运行2个online-edu-video-service服务(idea右上角 ,进入编辑详情可以copy)
然后重新调用接口
http://localhost:8000/api/v1/video_order/save?videoId=40
+
ribbon服务间调用负载均衡源码分析
idea搜索类的快捷键是 ctrl+N
@LoadBalanced
1)首先从注册中心获取provider的列表
2)通过一定的策略选择其中一个节点
3)再返回给restTemplate调用
Ribbon支持的负载均衡策略介绍
策略类 | 命名 | 描述 |
---|---|---|
RoundRobinRule | 线性轮询策略 | 按照顺序选择server,简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 可用过滤策略 | 过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server(active connections超过配置的阈值)。 对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上限,可以由客户端的..ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule | 响应时间加权重策略 | 根据server的响应时间分配权重,以响应时间作为权重,响应时间越短的服务器被选中的概率越大,综合了各种因素,比如:网络,磁盘,io等,都直接影响响应时间 |
ZoneAvoidanceRule | 区域权重策略 | 综合判断server所在区域的性能,和server的可用性,轮询选择server |
BestAvailableRule | 最空闲策略 | 忽略那些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机策略 | 随机选择server |
RetryRule | 重试策略 | 当选择server不成功,短期内尝试选择一个可用的server |
怎么配置
通过定义IRule实现可以修改负载均衡规则,有两种方式:
(这种方式是作用于全局的,在order服务访问任何一个微服务,都是随机的)
1.代码方式:在order-service中的OrderApplication类中,定义一个新的IRule:
@Bean
public IRule randomRule() {
return new RandomRule();
}
2.配置文件方式:在online-edu-order-service的application.yml文件中,添加新的配置也可以修改规则:
这种方式会先指定服务名称,再去指定负载均衡的规则,所以这种配置是针对某个微服务而言的。
online-edu-order-service:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule # 负
载均衡规则
服务器性能有差异时用WeightedResponseTimeRule,没有则默认即可。
demo(客户端负载均衡)
因为我的服务总是报java.net.UnknownHostException: online-edu-video-service
c错误。
最后百度的原因是
因为Spring Cloud 2020版本以后,默认移除了对Netflix的依赖,其中就包括Ribbon,官方默认推荐使用Spring Cloud Loadbalancer 正式替换Ribbon,并成为了Spring Cloud负载均衡器的唯一实现,因此要在原有依赖的基础上添加 下面的Loadbalancer依赖。
按照且感谢 春.生——https://blog.csdn.net/Funny54?type=blog 的博客指导,增加依赖(父项目引入依赖和版本,子项目引入依赖)
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>4.1.4</version>
</dependency>
online-edu-order-service/src/main/resources/application.yml
增加依赖:
online-edu-order-service/src/main/java/org/online_edu/controller/VideoOrderController.java
@RestController
@RequestMapping("/api/v1/video_order")
public class VideoOrderController {
/**
* 服务对象
*/
@Autowired
private VideoOrderService videoOrderService;
@Autowired
private RestTemplate restTemplate;
// /**
// * 可以拉到注册服务的列表
// */
// @Autowired
// private DiscoveryClient discoveryClient;
@RequestMapping("save")
public Object save(@RequestParam(name = "videoId") int videoId) {
// Video video = restTemplate.getForObject(
// "http://localhost:9000/api/v1/video/find_by_id?videoId=" + videoId, Video.class);
// 传入在nacos注册的服务名
// List<ServiceInstance> list = discoveryClient.getInstances("online-edu-video-service");
// ServiceInstance serviceInstance = list.get(0);
////
////
// Video video = restTemplate.getForObject(
// "http://" + serviceInstance.getHost() +":"+serviceInstance.getPort()+ "/api/v1/video/find_by_id?videoId=" + videoId, Video.class);
Video video = restTemplate.getForObject(
"http://online-edu-video-service/api/v1/video/find_by_id?videoId=" + videoId, Video.class);
VideoOrder videoOrder = new VideoOrder();
if (video != null) {
videoOrder.setServeInfo(video.getServeInfo());
videoOrder.setVideoId(video.getId());
videoOrder.setVideoTitle(video.getTitle());
videoOrder.setCreateTime(new Date());
}
return videoOrder;
}
}
这里
online-edu-video-service
起3个服务。我这里用的Apipost软件。
发起多次请求,可以看到再访问到video服务分布式节点。