最近在系统性的学习Spring Cloud方面的知识点。
强推一波:https://segmentfault.com/ls/1650000011386794
上面是大佬小马哥的教学视频。
今天的内容是学习完章节七后的课后总结。
负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。
1、服务端负载均衡:客户端请求到负载均衡服务器,负载均衡服务器根据自身的算法将该请求转给某台真正提供业务的服务器,该服务器将响应数据给负载均衡服务器,负载均衡服务器最后将数据返回给客服端。(nginx)
2、客服端负载均衡:基于客户端的负载均衡,简单的说就是在客户端程序里面,自己设定一个调度算法,在向服务器发起请求的时候,先执行调度算法计算出向哪台服务器发起请求,然后再发起请求给服务器。
基于客户端负载均衡的特点:
由客户端内部程序实现,不需要额外的负载均衡器软硬件投入。
程序内部需要解决业务服务器不可用的问题,服务器故障对应用程序的透明度小。
程序内部需要解决业务服务器压力过载的问题。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
@RestController
@RequestMapping(value = "/users")
public class DemoController {
private User providerUser = null;
@PostMapping
public Object save(@RequestBody User user) {
providerUser = user;
return providerUser;
}
@GetMapping
public Object get() {
return providerUser;
}
}
提供一个save方法,便于我们区分我们访问的服务信息,在测试的时候,provider端我们会同时启动两个实例.分别赋予不同的值.
application.properties配置
## 用户服务提供方应用信息
spring.application.name = ribbon-provider
## 关闭 Eureka Client,显示地通过配置方式注册 Ribbon 服务地址
eureka.client.enabled = false
配置两个实例并启动,通过saveAPI分别赋值。
@SpringBootApplication
@RibbonClient("ribbon-provider")//与application.properties文件中的配置呼应
public class ClientApplication {
public static void main(String[] args) {
SpringApplication.run(ClientApplication.class, args);
}
}
application.properties
## 用户 Ribbon 客户端应用
spring.application.name = ribbon-client
## 服务端口
server.port = 8080
## 提供方服务名称
provider.service.name = ribbon-provider
## 提供方服务主机
provider.service.host = localhost
## 提供方服务端口
provider.service.port1 = 9090
provider.service.port2 = 9091
## 关闭 Eureka Client,显示地通过配置方式注册 Ribbon 服务地址
eureka.client.enabled = false
## 定义 user-service-provider Ribbon 的服务器地址
## 为 RibbonLoadBalancerClient 提供服务列表
ribbon-provider.ribbon.listOfServers = \
http://${provider.service.host}:${provider.service.port1} ,\
http://${provider.service.host}:${provider.service.port2}
核心代码
@RestController
@RequestMapping(value = "/client")
public class ClientController {
/**
* 负载均衡器客户端
*/
@Autowired
private LoadBalancerClient loadBalancerClient;
@Value("${provider.service.name}")
private String providerServiceName;
@GetMapping
public User index() throws IOException {
// 选择指定的 service Id
ServiceInstance serviceInstance = loadBalancerClient.choose(providerServiceName);
return loadBalancerClient.execute(providerServiceName, serviceInstance, instance -> {
//服务器实例,获取 主机名(IP) 和 端口
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/users";
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject(url, User.class);
});
}
}
访问客户端API:
默认配置下,ribbon提供的负载均衡方式是轮训,从访问的结果也可以看出来
1. RoundRobinRule(轮询模式)ribbon的默认策略;
2. RandomRule(随机策略) public class RandomRule extends AbstractLoadBalancerRule 随机选择一个server 在index上随机,选择index对应位置的server。
3. BestAvailableRule(并发量) public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule 选择一个最小的并发请求的server 逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
4.AvailabilityFilteringRule(服务器状态) public class AvailabilityFilteringRule extends PredicateBasedRule 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态
4. WeightedResponseTimeRule(根据响应时间) public class WeightedResponseTimeRule extends RoundRobinRule 根据响应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。 一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择server。
5. ZoneAvoidanceRule(Zone状态+服务状态) public class ZoneAvoidanceRule extends PredicateBasedRule 复合判断server所在区域的性能和server的可用性选择server 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的
Server。
ribbon-provider.ribbon.NFLoadBalancerRuleClassName= \
com.netflix.loadbalancer.RandomRule
在ClientApplication.java 中加入
@Bean
public IRule ribbonRule() {
return new RandomRule();//这里配置策略,和配置文件对应
}
其他漏由方式与此一致
public class MyRule extends AbstractLoadBalancerRule {
public MyRule() {
}
@SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
public Server choose(ILoadBalancer lb, Object key) {
//自定义获取Server逻辑 可以参考其他规则的获取方式
return null;
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
自定义规则的使用方式与官方提供的其他规则使用方式一致
阅读源码可知,ribbon的健康检查机制实现了
package com.netflix.loadbalancer;
import com.netflix.loadbalancer.Server;
public interface IPing {
boolean isAlive(Server var1);
}
/**
* 实现 {@link IPing} 接口:检查对象 /health 是否正常状态码:200
*
* 如何实现可以根据实际情况考虑
*/
public class MyPing implements IPing {
@Override
public boolean isAlive(Server server) {
String host = server.getHost();
int port = server.getPort();
// /health endpoint
// 通过 Spring 组件来实现URL 拼装
UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
builder.scheme("http");
builder.host(host);
builder.port(port);
builder.path("/health");
URI uri = builder.build().toUri();
RestTemplate restTemplate = new RestTemplate();
ResponseEntity responseEntity = restTemplate.getForEntity(uri, String.class);
// 当响应状态等于 200 时,返回 true ,否则 false
return HttpStatus.OK.equals(responseEntity.getStatusCode());
}
}
## 扩展 IPing 实现
ribbon-provider.ribbon.NFLoadBalancerPingClassName = \
pikachu.com.ping.MyPing
以上为该课程后的小结,如有不正确的地方,小伙伴么评论区QAQ.
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有