负载均衡
在现在的互联网应用中,一台机器通常并不能承担所有的流量,所以我们通常需要部署多台机器。对于某些访问量比较小的服务,即使一台机器可以承载所有的流量,为了避免单点故障,我们也通常至少部署两台。
而对于流量比较大的情况下,负载均衡则是一个必修课,是必须要过关的一个内容。它的重要性体现在很多方面:
(1).降低性能损失。在流量大的时候,根据不同的场景选择合适的地区、城市或机房来做流量的分发是很重要的,比如我们的机房可能分别部署在华南和华东,分别在青岛和深圳有机房,这个时候我们就需要同城优先来进行访问,要想合理的使用同城优先的策略,合理的负载均衡策略是必不可少的。
(2).机器保护。有时候我们的某台机器可能CPU飙升或者网络,这个时候可能是因为程序写的不好,有可能是某些请求太高,我们通常可以制定合理的负载均衡策略来降低这台机器的权重,来让更少的流量打到它上面。避免这台服务器被压垮或者太多请求超时,或者直接禁用它。
(3).负载均衡也和很多其他技术一起发挥作用,它也是很多技术的基础。比如动态的缩容和扩容,比如限流。
使用Ribbon做负载均衡
作为一个开源的通用组件,支持的策略还是蛮多的。Ribbon的负载均衡策略主要支持如下几种:
我们来分别介绍一下吧:
(1).RoundRobinRule即轮询策略,这也是默认的负载均衡策略。
(2).RadmonRule即随机策略,它会从服务器列表中选择一个进行访问。
(3).BestAvailableRule即最大可用策略,它会先过滤出故障服务器,然后选择一个当前请求数最小的。
(4).WeightedResponseTimeRule即带有加权的轮询策略,它会对各个服务器响应时间进行加权,然后在采用轮询的方式获取相应的服务器。
(5).AvailabilityFilteringRule即可用过滤策略,它先过滤出故障的或者并发请求大于某个阈值的一部分服务实例,然后再用轮询的方式从过滤后的实例中选择一个。
(6).ZoneAvoidanceRule即区域感知策略,它会先使用主过滤条件,比如区域负载器,选择最优的区域,然后对所有的实例进行过滤并且返回过滤后的实例列表,依次使用过滤列表条件中的过滤条件对主过滤条件的结果进行过滤,判断最小过滤数和最小过滤百分比,最后对所有满足条件的服务器使用RoundRobinRule选择一个服务器实例。
我们也可以选择直接使用注入LoadBalancerClient的方式来得到我们选择的对象列表。我们还是在我们的course-service这个微服务中进行编辑,我们新建一个bean子目录,我们写入如下代码:
package com.mengzhidu.java.demo.scdemo.course.service.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.web.client.RestTemplate;
/**
* Created by xinxing on 2019/1/23
*/
@Configuration
public class BeanConfig {
@Primary
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
然后我们新建一个controller吧,我们编辑内容如下所示:
package com.mengzhidu.java.demo.scdemo.course.service.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URI;
/**
* Created by xinxing on 2019/1/23
*/
@RestController
@RequestMapping("/course/index/v2")
public class CourseIndexV2Controller {
private static final Logger LOGGER = LoggerFactory.getLogger(CourseIndexV2Controller.class);
@Resource
private RestTemplate restTemplate;
@Resource
private LoadBalancerClient loadBalancerClient;
@RequestMapping("/my")
public String my(Integer id) {
if (id == null) {
id = 0;
}
ServiceInstance instance = loadBalancerClient.choose("user-service");
String addr = String.format("http://%s:%s/user/profile/name?id=%s", instance.getHost(), instance.getPort(), id);
LOGGER.info("本次请求的地址:{}", addr);
String userName = restTemplate.getForObject(URI.create(addr), String.class);
return "用户姓名: " + userName + " 教程名称: Course" + id;
}
}
然后我们这里是调用的用户中心的服务,我们在9003和9004端口上分别启动user-service服务,然后我们请求 http://localhost:9002/course/index/v2/my?id=3 来看一下具体的日志信息吧,我们会看到如下的日志记录:
可以看到,这里分别访问9004端口和9003端口,实现了负载均衡。
小结
基本的使用Ribbon来进行负载均衡的例子就介绍到这里啦。