Spring Cloud 学习记录(二) Netflix-Ribbon

本文详细介绍了SpringCloud中的Ribbon组件,探讨其负载均衡机制、配置方法及与Feign、RestTemplate的集成应用,展示了如何通过Ribbon实现服务间的智能调度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring Cloud 学习记录(二) Netflix-Ribbon

Ribbon 简介

Ribbon 是 Netflix 下的负载均衡项目,它在集群中为各个客户端的通信提供了支持,它
主要实现中间层应用程序的负载均衡。Ribbon 提供以下特性:

  • 负载均衡器,可支持插拔式的负载均衡规则。
  • 对多种协议提供支持,例如 HTTP、TCP、UDP。
  • 集成了负载均衡功能的客户端。

同为 Netflix 项目,Ribbon 可以与 Eureka 整合使用,Ribbon 同样被集成到 Spring Cloud
中,作为 spring-cloud-netflix 项目中的子模块。Spring Cloud 将 Ribbon 的 API 进行了封装,
使用者可以使用封装后的 API 来实现负载均衡,也可以直接使用 Ribbon 的原生 API。

Ribbon 子模块

Ribbon 主要有以下三大子模块:

  • ribbon-core:该项目为Ribbon项目的核心,主要包括负载均衡接口定义、客户端接口定义、内置负载均衡实现等API。
  • ribbon-eureka:为Eureka提供的负载均衡实现类。
  • ribbon-httpclient:对Apache的HttpClient进行封装,该模块提供了含有负载均衡功能的REST客户端。

负载均衡器组件

Ribbon的负载均衡器主要与集群中的各个服务器进行通信,负载均衡器需要提供以下功能:

  • 维护服务的IP、DNS名称等信息
  • 根据特定的逻辑在服务器列表中循环。
    为了实现负载均衡的基础功能,Ribbon 的负载均衡器有以下三大子模块:
  • Rule:一个逻辑组件,这些逻辑将会决定,从服务器中返回哪个服务器实例
  • Ping:该组件主要使用定时器,来确保服务器网络可以连接
  • ServerList:服务器列表,可以通过静态的配置确定负载的服务器,也可以动态指定服务器列表。如果动态指定服务器列表,则会有后台线程来刷新该列表
    本次关于Ribbon的学习,主要围绕负载均衡器组件进行,下面搞个demo:

Ribbon程序

本程序直接使用Ribbon原生API,结构图如下:
在这里插入图片描述

首先创建一个springboot项目,添加web依赖,用作服务器端,并以不同的端口启动,修改入口类函数,代码如下:


import java.util.Scanner;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;

@SpringBootApplication
public class FirstRibbonServerApplication {

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		String port = scan.nextLine();
		new SpringApplicationBuilder(FirstRibbonServerApplication.class).properties("server.port="+port).run(args);
		//SpringApplication.run(FirstRibbonServerApplication.class, args);
	}
}

并随意创建一个controller,编写一个方法,用于返回Json/字符串,之后:
分别用8080/8081端口启动程序,之后使用Ribbon编写客户端调用两个服务,代码如下:

import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.netflix.client.ClientFactory;
import com.netflix.client.http.HttpRequest;
import com.netflix.client.http.HttpResponse;
import com.netflix.config.ConfigurationManager;
import com.netflix.niws.client.http.RestClient;

@SpringBootApplication
public class FirstRibbonClientApplication {

	public static void main(String[] args) throws Exception {
		//SpringApplication.run(FirstRibbonClientApplication.class, args);
		ConfigurationManager.getConfigInstance().setProperty("my-client.ribbon.listOfServers", "localhost:8080,localhost:8081");
		@SuppressWarnings("deprecation")
		RestClient client=(RestClient) ClientFactory.getNamedClient("my-client");
		HttpRequest request = HttpRequest.newBuilder().uri("/hello/jackshen").build();
		for (int i = 0; i < 6; i++) {
			HttpResponse response = client.executeWithLoadBalancer(request);
			String result = response.getEntity(String.class);
			System.out.println("+++++++++++++++++++++++++++++++++++"+result);
		}
	}
}

最终在客户端会返回如下信息:

http://localhost:8080/hello/jackshen
http://localhost:8081/hello/jackshen
http://localhost:8080/hello/jackshen
http://localhost:8081/hello/jackshen
http://localhost:8080/hello/jackshen
http://localhost:8081/hello/jackshen

以上是:Ribbon原生API使用方式

Ribbon配置

在编写客户端时,使用了 ConfigurationManager 来设置配置项,除了在代码中指定配
置 项 外 , 还 可 以 将 配 置 放 到 “ .properties ” 文 件 中 , ConfigurationManager 的
loadPropertiesFromResources 方法可以指定 properties 文件的位置,配置格式如下:

<client>.<nameSpace>.<property>=<value>

其中为客户的名称,声明该配置属于哪一个客户端,在使用 ClientFactory 时可
传入客户端的名称,即可返回对应的“请求客户端”实例。为该配置的命名
空间,默认为“ribbon”,为属性名,为属性值。如果想对全部的客户端
生效,可以将客户端名称去掉,直接以“.”的格式进行配置。以
下的配置,为客户端指定服务器列表:

my-client.ribbon.listOfServers=localhost:8080,localhost:8081

Ribbon 的配置,同样可以使用在 Spring Cloud 的配置文件(即 application.yml)中使
用。

spring 的application.yml 中配置自定义规则和ping类,配置内容如下:

cloud-provider:
  ribbon:
    NFLoadBalancerRuleClassName: org.crazyit.cloud.MyRule
    NFLoadBalancerPingClassName: org.crazyit.cloud.MyPing
    listOfServers: http://localhost:8080/,http://localhost:8081/

springboot类配置方法如下:

package com.panku.conf;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.panku.domain.MyPing;
import com.panku.domain.MyRule;

@Configuration
public class MyConf {

	@Bean
	public IRule getRule() {
		return new MyRule();
	}
	
	@Bean
	public IPing getPing() {
		return new MyPing();
	}
	
	
	
}

package com.panku.conf;

import org.springframework.cloud.netflix.ribbon.RibbonClient;

@RibbonClient(name="cloud-provider",configuration=MyConf.class)
public class CloudProviderConfig {

}

调用方法如下:

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;

@RestController
@Configuration
public class InvokerController {

	@Bean
	@LoadBalanced
	public RestTemplate  getRestTpl() {
		return new RestTemplate();
	}
	
	@RequestMapping("/hello/{name}")
	public String hello(@PathVariable("name")String name) {
		RestTemplate restTpl = getRestTpl();
		String json = restTpl.getForObject("http://cloud-provider/hello/"+name, String.class);
		return json;
	}
	
}

RestTemplate 负载均衡原理

@LoadBalanced 注解概述

RestTemplate 本是 spring-web 项目中的一个 REST 客户端访问类,它遵循 REST 的
设计原则,提供简单的 API 让调用去访问 HTTP 服务器。RestTemplate 本身不具有负载均
衡的功能,该类也与 Spring Cloud 没有关系,但为何加入@LoadBalanced 注解后,一个
RestTemplate 实例就具有负载均衡的功能呢?实际上这要得益于 RestTemplate 的拦截器
功能。
在 Spring Cloud 中,使用@LoadBalanced 修饰的 RestTemplate,在 Spring 容器启动
时,会为这些被修饰过的 RestTemplate 添加拦截器,拦截器中使用了 LoadBalancerClient
来处理请求,LoadBalancerClient 本来就是 Spring 封装的负载均衡客户端,通过这样间接
处理,使得 RestTemplate 就拥有了负载均衡的功能

REST 客户端 Feign 介绍

Feign 是一个 Github 上一个开源项目,目的是为了简化 Web Service 客户端的开发。
在使用 Feign 时,可以使用注解来修饰接口,被注解修饰的接口具有访问 Web Service 的
能力,这些注解中既包括了 Feign 自带的注解,也支持使用第三方的注解。除此之外,Feign
还支持插件式的编码器和解码器,使用者可以通过该特性,对请求和响应进行不同的封装与
解析。
Spring Cloud 将 Feign 集成到 netflix 项目中,当与 Eureka、Ribbon 集成时,Feign 就
具有负载均衡的功能。Feign 本身在使用上的简便性,加上与 Spring Cloud 的高度整合,使
用该框架在 Spring Cloud 中调用集群服务,将会大大降低开发的工作量

调用方法:
1.在入口类添加注解:@EnableFeignClients
2.编写接口类:内容如下:

package com.panku.icloud;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("cloud-provider")
public interface HelloClient {

	@RequestMapping("/hello/{name}")
	String hello(@PathVariable("name")String name);
	
}

3.编写调用控制器,内容如下:

package com.panku.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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 com.panku.icloud.HelloClient;

@RestController
public class InvokerController {


	
	@Autowired
	private HelloClient helloClient;
	
	@RequestMapping("/simhello/{name}")
	public String simHello(@PathVariable("name")String name) {
		return helloClient.hello(name);
	}
	
}

注意:springboot2.0之后所feign的starter名称变为:spring-cloud-starter-openfeign

### 关于 Spring Cloud Starter Netflix Ribbon 的常见错误及其解决方案 #### 1. **依赖冲突** 如果项目中存在多个版本的 `spring-cloud-starter-netflix-ribbon` 或其他相关依赖(如 Eureka),可能会引发兼容性问题。建议检查项目的 Maven 或 Gradle 文件中的依赖树,确保所有依赖版本一致。 可以通过以下命令查看依赖树并排查冲突: ```bash mvn dependency:tree ``` 解决方法:统一使用同一版本Spring CloudSpring Boot 组件[^1]。 --- #### 2. **未正确加载 Ribbon 配置** 当 `@LoadBalanced` 注解未被正确识别时,可能导致负载均衡功能失效。这通常是因为缺少必要的自动配置类 `LoadBalancerAutoConfiguration`。 解决方法:确认已导入正确的依赖项,并确保 Spring Boot 自动化机制正常运行。可以尝试手动引入 `LoadBalancerAutoConfiguration` 类来验证问题所在[^4]。 --- #### 3. **Eureka 客户端连接失败** 如果 Ribbon 使用的是基于 Eureka 的服务发现,则需要确保 Eureka Server 正常启动且客户端能够成功注册到服务器上。常见的问题是 Eureka URL 配置不正确或网络不通。 解决方法:检查 `application.yml` 中的 Eureka 配置是否正确[^5]。例如: ```yaml eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ ``` 同时,可以在日志中查找与 Eureka 连接相关的异常信息以进一步定位问题。 --- #### 4. **RestTemplate 调用返回空指针或其他异常** 这种情况可能发生在 Ribbon 未能找到目标服务的情况下。原因可能是服务名称拼写错误、服务未注册到 Eureka 或者 Ribbon 缺少必要配置。 解决方法:确认调用的服务名和服务提供者的实际注册名完全匹配;并通过调试模式打印日志,观察 Ribbon 是否能正确解析服务列表[^3]。 --- #### 5. **Ribbon 默认超时时间过短** 默认情况下,Ribbon 的 HTTP 请求超时时间为 1 秒钟。对于某些较慢的服务响应来说,这个值可能太低,从而导致请求频繁失败。 解决方法:调整 Ribbon 的超时设置,在 `application.yml` 中增加如下配置: ```yaml ribbon: ReadTimeout: 5000 ConnectTimeout: 5000 ``` 上述配置将读取和连接超时分别设为 5 秒。 --- #### 示例代码修正 以下是完整的 Ribbon 集成示例,包含 RestTemplate 加载平衡器以及基本配置: ```java @Configuration public class RibbonConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } } ``` 配合以下 YAML 配置文件内容: ```yaml server: port: 8081 spring: application: name: ribbon-app-client eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ ribbon: ReadTimeout: 5000 ConnectTimeout: 5000 ``` --- ### 总结 以上列举了几种典型的 `spring-cloud-starter-netflix-ribbon` 错误场景及对应的解决方案。通过合理配置依赖、检查服务发现状态以及优化超时参数等方式,可有效减少开发过程中的潜在问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值