企业网站定制开发负载均衡的实现方式
- 企业网站定制开发客户端的负载均衡
- 企业网站定制开发服务端的负载均衡(经常使用nginx来实现)
企业网站定制开发服务端负载均衡
- 接收请求
- 企业网站定制开发企业网站定制开发选择服务器地址
- 转发请求
企业网站定制开发客户端负载均衡
- 选择服务器地址
- 发请求
企业网站定制开发也可以分为企业网站定制开发企业网站定制开发集中式负载均衡和企业网站定制开发进程内负载均衡
集中式负载均衡
企业网站定制开发即在服务的消费方和提企业网站定制开发供方之间使用独立的负企业网站定制开发载均衡设施(可以是硬件,如F5,可以是软件,如nginx),由该实施负责把访问请求通过某种策略转发至服务的提供方
进程内负载均衡
将负载均衡逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选择出一个合适的服务器。
就属于进程内负载均衡,它只是一个类库,集成于消费方进程,消费方通过它来获取服务提供方的地址
Ribbon的简单介绍
Spring Cloud Ribbon是基于Netfilx Ribbon实现一套客户端负载均衡的工具。简单的说,Ribbon是Netfilx 发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项,如:连接超时、重试等。
简单的说,就是在配置文件列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如:简单轮询、随机连接等)去连接这些机器。
我们很容易使用Ribbon实现自定义负载均衡算法。
Ribbon 注册到 server之后,Ribbon会从nacos server获取服务列表
Ribbon 负载均衡策略的简单介绍
IRule 接口的实现类定义了一系列负载规则
IRule的类图
负载策略的大致功能实现
策略名 | 策略声明 | 策略描述 | 实现说明 |
---|---|---|---|
BestAvailableRule | public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule | 选择一个最小的并发请求的server | 逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server |
AvailabilityFilteringRule | public class AvailabilityFilteringRule extends PredicateBasedRule | 过滤掉那些因为一直连接失败的被标记为circuit | tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态 |
WeightedResponseTimeRule | public class WeightedResponseTimeRule extends RoundRobinRule | 根据响应时间分配一个weight,响应时间越长,weight越小,被选中的可能性越低。 | 一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成status时,使用roubine策略选择server。 |
RetryRule | public class RetryRule extends AbstractLoadBalancerRule | 对选定的负载均衡策略机上重试机制。 | 在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server |
RoundRobinRule | public class RoundRobinRule extends AbstractLoadBalancerRule | roundRobin方式轮询选择server | 轮询index,选择index对应位置的server |
RandomRule | public class RandomRule extends AbstractLoadBalancerRule | 随机选择一个server | 在index上随机,选择index对应位置的server |
ZoneAvoidanceRule | public class ZoneAvoidanceRule extends PredicateBasedRule | 复合判断server所在区域的性能和server的可用性选择server | 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的Server。 |
ResponseTimeWeightedRule已经被弃用,作用和WeightedResponseTimeRule一样。
还是以这篇博客为基础,我们来探究一下Ribbon负载均衡的基本使用
示例
nacos-provider(提供服务)
基本项目结构如下
还是这篇博客的代码,可以去这篇博客的nacos-provider章节查看,我就不搬运过来了
nacos-consumer(消费服务)
基本结构如下
其中包是使用feign调用远程服务不用管它
pom.xml文件
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud</artifactId> <groupId>com.xt</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>nacos-consumer</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies></project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
application.yml配置文件
server: port: 8085spring: application: name: nacos-consumer cloud: nacos: discovery: server-addr: 部署nacos server的服务器IP:8848feign: hystrix: enabled: true
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
RibbonConfig
写一个ribbon配置类
IRule 接口的实现类定义了一系列负载规则
如果自己不指定,默认使用的就是轮询算法。
先使用RandomRule的随机来做测试
@Configurationpublic class RibbonConfig { @Bean public IRule iRule() {// 权重负载策略 nacos的负载均衡实现// return new NacosRule(); 是spring cloud alibaba 继承了netflix.loadbalancer包的AbstractLoadBalancerRule抽象类的实现// 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务// return new BestAvailableRule();// 复合判断server所在区域的性能和server的可用性选择服务器// return new ZoneAvoidanceRule();// 先过滤掉故障实例,再选择并发较小的实例// return new AvailabilityFilteringRule();// 对RoundRobinRule 轮询的扩展,响应速度越快的实例选择权重越多大,越容易被选择// return new WeightedResponseTimeRule();// return new ResponseTimeWeightedRule(); 已经被弃用// 随机 return new RandomRule();// 先按照RoundRobinRule 轮询的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务// return new RetryRule(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
controller
@RestControllerpublic class TestController { private final RestTemplate restTemplate; @Autowired public TestController(RestTemplate restTemplate) {this.restTemplate = restTemplate;} @RequestMapping(value = "/echo-restemplate/{str}", method = RequestMethod.GET) public String echo(@PathVariable String str) { return restTemplate.getForObject("http://nacos-provider/echo/" + str, String.class); } @Autowired EchoService echoService; @RequestMapping(value = "/echo-feign/{str}",method = RequestMethod.GET) public String feign(@PathVariable String str) { return echoService.echo(str); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
feign(远程调用服务的东西)
@Component@FeignClient(name = "nacos-provider")public interface EchoService { @RequestMapping(value = "/echo-error/{str}",method = RequestMethod.GET) String echo(@PathVariable("str") String str); //fallback实现类 @Component class EchoServiceFallback implements EchoService{ @Override public String echo(@PathVariable("str") String str) { return "接口请求失败"; } }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
MyLoadBalancer类(自定义负载均衡的实现,我这里写死了,只访问一个实例)
public class MyLoadBalancer extends AbstractLoadBalancerRule{ public MyLoadBalancer() { } @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"}) public Server choose(ILoadBalancer lb, Object key) { if (lb == null) { return null; } else { Server server = null; while(server == null) { //测试当前线程是否被中断(检查中断标志),返回一个boolean并清除中断状态,第二次再调用时中断状态已经被清除,将返回一个false。 if (Thread.interrupted()) { return null; } //获取已启动且可访问的服务器。 List<Server> upList = lb.getReachableServers(); //获取所有已知的服务器(可访问和不可访问) List<Server> allList = lb.getAllServers(); //全部服务的实例个数 int serverCount = allList.size(); if (serverCount == 0) { return null; } //RandomRule使用ThreadLocalRandom获取随机数,我这里直接写死,我只要1实例提供服务 int index = 1; server = (Server)upList.get(index); if (server == null) { //放出CPU资源 Thread.yield(); } else { if (server.isAlive()) { return server; } server = null; Thread.yield(); } } return server; } } protected int chooseRandomInt(int serverCount) { //ThreadLocalRandom,在多线程下,它为每个线程维护一个 seed 变量 return ThreadLocalRandom.current().nextInt(serverCount); } @Override public Server choose(Object key) { return this.choose(this.getLoadBalancer(), key); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
NacosConsumerApplication启动类
使用RestTemplate来请求服务,向Spring的IOC注入一个bean: restTemplate;并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。
@SpringBootApplication@EnableDiscoveryClient@EnableFeignClients@RibbonClient(name="nacos-provider",configuration= RibbonConfig.class)public class NacosConsumerApplication {// @Bean// @Scope(value = "prototype")// public IRule loadBalanceRule() {// return new NacosRule();// } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args){ SpringApplication.run(NacosConsumerApplication.class, args); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
像这篇博客一样,先开启三个nacos-provider服务。再开启一个nacos-consumer服务
登录服务器部署的nacos服务的控制台(默认账号和密码都是nacos)
服务器IP:8848/nacos
- 1
我们可以看到我们注册好的4个服务实例
测试Ribbon自带的随机策略
配置类,设置成 RandomRule
return new RandomRule();
- 1
如下所示,将RandomRule注入到Spring 的IOC 容器中进行管理
@Configurationpublic class RibbonConfig { @Bean public IRule iRule() {// 权重负载策略 nacos的负载均衡实现// return new NacosRule(); 是spring cloud alibaba 继承了netflix.loadbalancer包的AbstractLoadBalancerRule抽象类的实现// 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务// return new BestAvailableRule();// 复合判断server所在区域的性能和server的可用性选择服务器// return new ZoneAvoidanceRule();// 先过滤掉故障实例,再选择并发较小的实例// return new AvailabilityFilteringRule();// 对RoundRobinRule 轮询的扩展,响应速度越快的实例选择权重越多大,越容易被选择// return new WeightedResponseTimeRule();// return new ResponseTimeWeightedRule(); 已经被弃用// 随机 return new RandomRule();// 先按照RoundRobinRule 轮询的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务// return new RetryRule(); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
访问nacos-consumer服务,然后nacos-consumer服务访问请求nacos-provider服务,点击刷新多次
1号provider服务实例
2号provider服务实例
3号provider服务实例
可以看出,确实是随机策略
测试自定义的负载均衡策略
修改RibbonConfig,向Spring IOC容器中注入MyLoadBalancer
return new MyLoadBalancer();
- 1
@Configurationpublic class RibbonConfig { @Bean public IRule iRule() {// 权重负载策略 nacos的负载均衡实现// return new NacosRule(); 是spring cloud alibaba 继承了netflix.loadbalancer包的AbstractLoadBalancerRule抽象类的实现// 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务// return new BestAvailableRule();// 复合判断server所在区域的性能和server的可用性选择服务器// return new ZoneAvoidanceRule();// 先过滤掉故障实例,再选择并发较小的实例// return new AvailabilityFilteringRule();// 对RoundRobinRule 轮询的扩展,响应速度越快的实例选择权重越多大,越容易被选择// return new WeightedResponseTimeRule();// return new ResponseTimeWeightedRule(); 已经被弃用// 随机// return new RandomRule();// 先按照RoundRobinRule 轮询的策略获取服务,如果获取服务失败则在指定时间内进行重试,获取可用的服务// return new RetryRule(); //自己的负载均衡策略,只访问可访问服务列表的下标为1的服务实例 return new MyLoadBalancer(); }}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
重新运行nacos-consumer服务实例
然后再次使用浏览器访问nacos-consumer服务,让他去消费nacos-provider服务。
我多次点击刷新浏览器,只有3号provider服务实例的被调用次数在增加,说明我们的修改生效了。
注意:虽然我的负载均衡策略是设置的活动服务实例列表中的下标为1的服务实例接收消费。这里虽然是3号provider实例,但是下标为1是指列表里面的下标为1
//获取已启动且可访问的服务器。List<Server> upList = lb.getReachableServers();
- 1
- 2
References:
- https://www.cnblogs.com/roytian/p/12176321.html
- https://zhuanlan.zhihu.com/p/180300022
- https://www.jianshu.com/p/861ed1960014
(写博客主要是对自己学习的归纳整理,资料大部分来源于书籍、网络资料和自己的实践,整理不易,但是难免有不足之处,如有错误,请大家评论区批评指正。同时感谢广大博主和广大作者辛苦整理出来的资源和分享的知识。)