ribbon
是一个客户端负载均衡器
spring-cloud把服务注册到 注册中心比如nacos 我们要的服务地址只需要写模块名 就可以掉到对应的服务上 这么个功能 ribbon给我们实现了 也就是当我们调用服务时 要先去注册中心找服务的地址 为了只关心业务 ribbon给我实现了去注册中心给我找地址然后调用
@Autowired
LoadBalancerClient loadBalancer;
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
// return new RestTemplate();
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList(new LoadBalancerInterceptor(loadBalancer)));
return restTemplate;
}
@Autowired
LoadBalancerClient loadBalancer; 这句代码 如果导入了ribbon依赖会创建RibbonLoadBalancerClient这样的一个实例 然后通过restTemplate.setInterceptors(Collections.singletonList(new LoadBalancerInterceptor(loadBalancer)));这句代码给RestTemplate设置拦截器 设置了拦截器 当我们使用RestTemplate调用接口时会进入ribbon的拦截器 给我解析请求 比如 aa是服务名 请求地址是http://aa/a 就是去访问aa服务中的a接口 这是ribbon会给我把aa当作服务名去注册中心查找这个服务的真实地址 比如127.0.0.1:9090 就会把地址拼接成http://127.0.0.1:9090/a 这样 然后根据这个真实地址去调用服务
Spring-Cloud 整合Ribbon
org.springframework.cloud spring-cloud-starter-netflix-ribbon
添加@loadBalanced注解
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
添加了@LoadBalanced这个注解 就是会给RestTemplate添加一个ribbon实现了拦截器 这个拦截器就是去注册中心根据服务名去找地址 然后调用
controller层
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/findOrderByUserId/{id}")
public R findOrderByUserId(@PathVariable("id") Integer id) {
// RestTemplate调用
//String url = "http://localhost:8020/order/findOrderByUserId/"+id;
//模拟ribbon实现 mall-order是服务名
//String url = getUri("mall-order")+"/order/findOrderByUserId/"+id;
// 添加@LoadBalanced mall-order是服务名
String url = "http://mall-order/order/findOrderByUserId/"+id;
R result = restTemplate.getForObject(url,R.class);
return result;
}
模拟ribbon实现
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/findOrderByUserId/{id}")
public R findOrderByUserId(@PathVariable("id") Integer id) {
// RestTemplate调用
//String url = "http://localhost:8020/order/findOrderByUserId/"+id;
//模拟ribbon实现
String url = getUri("mall-order")+"/order/findOrderByUserId/"+id;
// 添加@LoadBalanced
//String url = "http://mall-order/order/findOrderByUserId/"+id;
R result = restTemplate.getForObject(url,R.class);
return result;
}
@Autowired
private DiscoveryClient discoveryClient;
public String getUri(String serviceName) {
List serviceInstances = discoveryClient.getInstances(serviceName);
if (serviceInstances == null || serviceInstances.isEmpty()) {
return null;
}
int serviceSize = serviceInstances.size();
//轮询
int indexServer = incrementAndGetModulo(serviceSize);
return serviceInstances.get(indexServer).getUri().toString();
}
private AtomicInteger nextIndex = new AtomicInteger(0);
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextIndex.get();
int next = (current + 1) % modulo;
if (nextIndex.compareAndSet(current, next) && current < modulo){
return current;
}
}
}
Ribbon扩展点
参考: org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration
IClientConfig:Ribbon的客户端配置,默认采用DefaultClientConfigImpl实现。
IRule:Ribbon的负载均衡策略,默认采用ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问。
IPing:Ribbon的实例检查策略,默认采用DummyPing实现,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。
ServerList:服务实例清单的维护机制,默认采用ConfigurationbasedServerList实现。
ServerListFilter:服务实例清单过滤机制,默认采ZonePreferenceServerListFilter,该策略能够优先过滤出与请求方处于同区域的服务实例。
ILoadBalancer:负载均衡器,默认采用ZoneAwareLoadBalancer实现,它具备了区域感知的能力。
Spring Cloud LoadBalancer
LoadBalancer是spring cloud官方用来替代ribbon的
提供了两个客户端
RestTemplate
RestTemplate是spring提供的用来访问http服务的工具类 可以提高编程效率
WebClient
非阻塞的基于响应式编程的进行Http请求的客户端工具。
RestTemplate整合LoadBalancer
org.springframework.cloud spring-cloud-starter-loadbalancerorg.springframework.boot spring-boot-starter-webcom.alibaba.cloud spring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloud spring-cloud-starter-netflix-ribbon
在yml文件中设置不适用ribbon即可
spring:
application:
name: mall-user-loadbalancer-demo
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 不使用ribbon
loadbalancer:
ribbon:
enabled: false
使用@LoadBalanced配置RestTemplate
@Configuration
public class RestConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
使用
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/findOrderByUserId/{id}")
public R findOrderByUserId(@PathVariable("id") Integer id) {
String url = "http://mall-order/order/findOrderByUserId/"+id;
R result = restTemplate.getForObject(url,R.class);
return result;
}
}
WebClient整合LoadBalancer
引入依赖
org.springframework.cloud spring-cloud-starter-loadbalancerorg.springframework.boot spring-boot-starter-webfluxcom.alibaba.cloud spring-cloud-starter-alibaba-nacos-discoveryorg.springframework.cloud spring-cloud-starter-netflix-ribbon
配置WebClient作为负载均衡器的client
@Configuration
public class WebClientConfig {
@LoadBalanced
@Bean
WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
@Bean
WebClient webClient() {
return webClientBuilder().build();
}
}
使用
@Autowired
private WebClient webClient;
@RequestMapping(value = "/findOrderByUserId2/{id}")
public Mono findOrderByUserIdWithWebClient(@PathVariable("id") Integer id) {
String url = "http://mall-order/order/findOrderByUserId/"+id;
//基于WebClient
Mono result = webClient.get().uri(url)
.retrieve().bodyToMono(R.class);
return result;
}
使用webFlux
@Autowired
private ReactorLoadBalancerExchangeFilterFunction lbFunction;
@RequestMapping(value = "/findOrderByUserId3/{id}")
public Mono findOrderByUserIdWithWebFlux(@PathVariable("id") Integer id) {
String url = "http://mall-order/order/findOrderByUserId/"+id;
//基于WebClient+webFlux
Mono result = WebClient.builder()
.filter(lbFunction)
.build()
.get()
.uri(url)
.retrieve()
.bodyToMono(R.class);
return result;
}



