在上一章,我介绍了springcloud的eureka搭建。我们做了服务注册。最后我们还介绍了一些续约,失效剔除等参数配置。已经不需要再通过手动输入ip去访问服务,而是通过中心只需要通过服务名就可以获取服务。这一章我们将要学习一下Ribbon负载均衡
上一章:(二 什么是Eureka服务注册中心,如何搭建?)手摸手带你一起搭建 Spring cloud 微服务 理论+实践+解析
负载均衡顾名思义,平均每台服务器的压力。实际开发过程中,同一种服务可能有多个服务器,即服务集群。这个时候为了保证这个类型的服务每台服务负载平均分配。
Ribbon是Netfix发布的负载均衡器,他有助于控制HTTP和TCP客户端的行为。为Ribbon配置服务提供者地址列表后,Ribbon就可以基于某种负载均衡算法,自动帮助服务消费者去请求。
我们上一章的例程是通过服务名获取完服务集合,serviceInstances.get(0) 可以看到总是获取第一个,因为我们当时只有一个user-service,这样显然是不对的。
List<ServiceInstance> serviceInstances= discoveryClient.getInstances("user-service");
String url = "http://"+serviceInstances.get(0).getHost()+":"+serviceInstances.get(0).getPort()+"/user/"+id;
所以我们需要根据算法,每次去选取合适的服务器,进行访问。
Ribbon默认为我们提供了很多负载均衡算法,我们先了解一下ribbon负载均衡有几种策略,也就是算法。
从名字就能看出,这是个很随性的策略,随性到什么程度呢?它会从当前可用的服务节点中,随机挑选一个节点访问。妈的真随便,比我还随便。
这个rule是RandomRule的亲兄弟,RandomRule是随性而为挑选节点,RobinRule却按部就班从一个节点一步一步地向后选取节点,既不会跳过一个,也不会原地踏步,每一次只向后移动一步。
RetryRule他的BUFF就是给其他负载均衡策略加上重试功能。而在RetryRule里还藏着一个subRule ,这才是隐藏在下面的真正被执行的负载均衡策略,RetryRule正是要为它添加重试功能(如果初始化时没指定subRule,将默认使用RoundRibinRule )
这个Rule继承自RoundRibonRule ,他会根据服务节点的响应时间计算权重,响应时间越长权重就越低,响应越快则权重越高,权重的高低决定了机器被选中概率的低。也就是说,响应时间越小的机器,被选中的概率越大。
应该说这个Rule有点智能的味道了,在过滤掉故啤服务以后,它会基于过去30分钟的统计结果选取当前并发量最小的服务节点,也就是最%闲”"的节点作为目标地址。如果统计结果尚未生成,则采用轮询的方式选定节点。
这个规则底层依赖RoundRobinRule来选取节点,但并非来者不拒,它也是有一些底线的,必须要满足它的最低要求的节点才会被选中。如果节点满足了要求,无论其响应时间或者当前并发量是什么,都会被选中。
每次AvailabilityFilteringRule(简称AFR)都会请求RobinRule挑选一个节点,然后对这个节点做以下两步检查:
是否处于熔断状态(这里大家可以把熔断当做服务不可用)
节点当前的active请求连接数超过阈值,超过了则表示节点目前太忙,不适合接客
如果被选中的server不幸挂掉了检查,那么AFR会自动重试(次数最多10次),让RobinRule重新选择一个服务节点。
这个过滤器包含了组合过滤条件,分别是Zone级别和可用性级别。
ZoneFilter:在Eureka注册中一个服务节点有Zone,Region和URL三个身份信息,其中Zone可以理解为机房大区(未指定则由Eureka给定默认值),而这里会对这个Zone的健康情况过滤其下面所有服务节点。
可用性过滤∶这里和AvailabilityFilteringRule的验证非常像,会过滤掉当前并发量较大,或者处于熔断状态的服务节点。
同样,我们的例程是用上一章的例程接着往下做
上个章节例程
首先copy出一个新的user-service
如何复制工程
我给它命名为user-service-other
设置端口为1002
为了方便查看效果,我们修改一下启动类名,和响应内容
如果你发现启动eureka时,有报错很正常,因为上个章节我们做了eureka集群,所以我们取消集群就行,修改一下eureka配置即可
server:
port: 11111
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:11111/eureka
register-with-eureka: false
fetch-registry: false
server:
eviction-interval-timer-in-ms: 60000
enable-self-preservation: true
然后运行测试一下eureka和两个user-service,看看工程是否复制成功
eureka中心可以看到两个user-service注册了
且能够通过1002端口访问返回信息
首先在启动类CustomService的RestTemplate配置上加上负载均衡注解@LoadBalanced
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableEurekaClient
public class CustomService {
public static void main(String[] args) {
SpringApplication.run(CustomService.class, args);
}
@Bean
@LoadBalanced //负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
修改UserHandler,访问的方式改为直接通过服务名的方式获取服务,原本需要获取ip处,我们直接换成服务名。
import org.antry.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
/**
* @ClassName UserHandler
* @Description TODO
* @Autor T_Antry
* @Date 2020/11/11 11:32
* @Version 1.0
*/
@RestController
@RequestMapping("user")
public class UserHandler {
@Autowired
private RestTemplate restTemplate;
@Autowired
private UserService userService;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/{id}")
public String doGet(@PathVariable Long id){
// String url = "http://127.0.0.1:1001/user/"+id;
// return "custom-Service回应:
"+restTemplate.getForObject(url, String.class);
// return userService.doGetUser(id);
// List serviceInstances= discoveryClient.getInstances("user-service");
// String url = "http://"+serviceInstances.get(0).getHost()+":"+serviceInstances.get(0).getPort()+"/user/"+id;
String url = "http://user-service/user/"+id;
return "custom-Service[通过注册中心拉取服务]回应:
"+restTemplate.getForObject(url, String.class);
}
}
2.3 运行
如果之前的eureka和两个user-service没关的话,直接运行custom-service就可以,如果关了,再运行起来,然后运行custom-service
在地址栏输入http://127.0.0.1:9001/user/123,因为custom的工程端口我们在之前的案例中给它设置成9001端口
一直刷新,我们可以看到,拿到是来自两个不同服务的响应,这是默认的轮询策略
2.4 如何修改策略
在消费者服务的配置文件中按下面个规则修改,
这个案例是给user-service配置策略为随机策略
配置完重新运行工程,会发现,响应不再像上面那样有规律地变化,而是无规律的响应了。
user-service: #要配置策略的服务名
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #要配置的策略名
本章资源
原本我选择0币下载,但是会自动要求收币,所以只好改成关注免费下载。