SpringCloud Eureka服务治理体系文章:https://blog.csdn.net/qq_41693034/article/details/105029809
客户端负载均衡:Spring Cloud Ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模板请求自动转换成客户端负载均衡的服务调用。
客户端负载均衡即是当浏览器向后台发出请求的时候,客户端会向Eureka Server读取注册到服务器的可用服务信息列表,然后根据设定的负载均衡策略(没有设置即用默认的),抉择出向哪台服务器发送请求。
通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单:
- 服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心;
- 服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。
RestTemplate详解
RestTemplate该对象会使用Ribbon的自动化配置,同时通过配置@LoadBalanced能够开启客户端负载均衡。
Get请求
- getForEntity函数。该方法返回的是ResponseEntity,该对象是Spring对HTTP请求响应的封装,其中主要存储了HTTP的几个重要元素。
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> responseEntity =
restTemplate.getForEntity(“http://USER-SERVER/user?name={1}”,String.class,”didi”);
String body = responseEntity.getBody();
- getForEntity(String url,Class responseType,Object... urlVariables)
- getForEntity(String url,Class responseType,Map urlVariables)
- getForEntity(URI url,Class responseType):使用URI对象替代之前的url和urlVariables参数来指定访问地址和参数绑定。
- getForObject函数。该方法可以理解为对getForEntity的进一步封装,它通过HttpMessageConverterExtractor对HTTP的请求响应体body内容进行对象转换,实现请求直接返回包装好的对象内容。
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(uri,String.class)
- getForObject(String url,Class responseType,Object... urlVariables)
- getForObject(String url,Class responseType,Map urlVariables)
- getForObject(URI url,Class responseType)
POST请求
- postForEntity函数。
RestTemplate restTemplate = new RestTemplate();
User user = new User(“didi”,30);
ResponseEntity<String> responseEntity =
restTemplate.postForEntity(“http://USER-SERVICE/user”,user,String.class);
String body = responseEntity.getBody();
- postForEntity(String url,Object request,Class responseType,Object... uriVariables)
- postForEntity(String url,Object request,Class responseType,Map uriVariables)
- postForEntity(URI url,Object request,Class responseType)
- postForObject函数。
RestTemplate restTemplate = new RestTemplate();
User user = new User(“didi”,30);
String postResult =
restTemplate.postForObject(“http://USER-SERVICE/user”,user,String.class)
- postForObject(String url,Object request,Class responseType,Object... uriVariables)
- postForObject(String url,Object request,Class responseType,Map uriVariables)
- postForObject(URI uri,Object request,Class responseType)
- postForLocation函数。该方法实现了以post请求提交资源,并返回新资源的URI
User user = new User(“didi”,30);
URI responseURI =
restTemplate.postForLocation(“http://USER-SERVICE/user”,user)
- postForLocation(String url,Object request,Object... urlVariables)
- postForLocation(String url,Object request,Map urlVariables)
- postForLocation(URI uri,Object request)
由于postForLocation函数会返回新资源的URI,该URI就相当于指定了返回类型,所以此方法实现的POST请求不需要像postForEntity和postForObject一样指定responseType。
PUT 请求
在RestTemplate中,对PUT 请求可以通过put方法进行调用实现:
RestTemplate restTemplate = new RestTemplate();
Long id = 10001L;
User user = new User(“didi”,40);
restTemplate.put(“http://USER-SERVICE/user/{1}”,user,id);
- put(String url,Object request,Object... urlVariables)
- put(String url,Object request,Map urlVariables)
- put(URI uri,Object request)
put函数为void类型,所以没有返回内容,也就没有其他函数定义的responseType参数。
DELETE请求
在RestTemplate中,对DELETE请求可以通过delete方法进行调用实现:
RestTemplate restTemplate = new RestTemplate();
Long id =10001L;
restTemplate.delete(“http://USER-SERVICE/user/{1}”,id);
- delete(String url,Object... uriVariables)
- delete(String url,Map uriVariables)
- delete(URI url)
我们在进行REST请求时,通常都将DELETE请求的唯一标识拼接在url中,所以DELETE请求也不需要request的body信息。
配置
可以通过使用@RibbonClient注解来实现更细粒度的客户端配置,比如下面的代码实现了为hello-service服务使用HelloServiceConfiguration中的配置。(可用于配置自定义负载均衡策略)
@Configuration
@RibbonClient(name=“hello-service”,configuration=HelloServiceConfiguration.class)
public class RibbonConfiguration{
}
自定义负载均衡算法
1、导包
2、自定义规则:MyRandomRule
package com.oy.myrule;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/*
* 负载均衡策略:每个服务访问5次,换下一个服务
*/
public class MyRandomRule extends AbstractLoadBalancerRule {
public MyRandomRule() {
}
private int total = 0;//每个服务访问次数
private int currentIndex = 0; //轮询到第几个服务
@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) {
if (Thread.interrupted()) {
return null;
}
List<Server> upList = lb.getReachableServers();//获得活着的服务
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
//===========================================================================
if(total < 5){
server = upList.get(currentIndex);
total ++;
}else{
total = 0;
currentIndex++;
if(currentIndex>=upList.size()){
currentIndex = 0;
}
server = upList.get(currentIndex);
}
//===========================================================================
// int index = this.chooseRandomInt(serverCount);
// server = (Server)upList.get(index);
if (server == null) {
Thread.yield();
} else {
if (server.isAlive()) {
return server;
}
server = null;
Thread.yield();
}
}
return server;
}
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
public Server choose(Object key) {
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
3、将MyRandomRule注册到spring容器中
4、配置服务去使用MyRule中的负载均衡算法
5、配置负载均衡实现RestTemplate
6、通过服务名访问
PS:本文参考《Spring Cloud微服务实战》翟永超著