Ribbon 是 Netflix 下的负载均衡项目,它在集群中为各个客户端的通信提供了支持,它
主要实现中间层应用程序的负载均衡。Ribbon 提供以下特性:
同为 Netflix 项目,Ribbon 可以与 Eureka 整合使用,Ribbon 同样被集成到 Spring Cloud
中,作为 spring-cloud-netflix 项目中的子模块。Spring Cloud 将 Ribbon 的 API 进行了封装,
使用者可以使用封装后的 API 来实现负载均衡,也可以直接使用 Ribbon 的原生 API。
Ribbon 主要有以下三大子模块:
Ribbon的负载均衡器主要与集群中的各个服务器进行通信,负载均衡器需要提供以下功能:
首先创建一个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使用方式
在编写客户端时,使用了 ConfigurationManager 来设置配置项,除了在代码中指定配
置 项 外 , 还 可 以 将 配 置 放 到 “ .properties ” 文 件 中 , ConfigurationManager 的
loadPropertiesFromResources 方法可以指定 properties 文件的位置,配置格式如下:
..=
其中为客户的名称,声明该配置属于哪一个客户端,在使用 ClientFactory 时可
传入客户端的名称,即可返回对应的“请求客户端”实例。为该配置的命名
空间,默认为“ribbon”,为属性名,为属性值。如果想对全部的客户端
生效,可以将客户端名称去掉,直接以“.”的格式进行配置。以
下的配置,为客户端指定服务器列表:
my-client.ribbon.listOfServers=localhost:8080,localhost:8081
Ribbon 的配置,同样可以使用在 Spring Cloud 的配置文件(即 application.yml)中使
用。
cloud-provider:
ribbon:
NFLoadBalancerRuleClassName: org.crazyit.cloud.MyRule
NFLoadBalancerPingClassName: org.crazyit.cloud.MyPing
listOfServers: http://localhost:8080/,http://localhost:8081/
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 本是 spring-web 项目中的一个 REST 客户端访问类,它遵循 REST 的
设计原则,提供简单的 API 让调用去访问 HTTP 服务器。RestTemplate 本身不具有负载均
衡的功能,该类也与 Spring Cloud 没有关系,但为何加入@LoadBalanced 注解后,一个
RestTemplate 实例就具有负载均衡的功能呢?实际上这要得益于 RestTemplate 的拦截器
功能。
在 Spring Cloud 中,使用@LoadBalanced 修饰的 RestTemplate,在 Spring 容器启动
时,会为这些被修饰过的 RestTemplate 添加拦截器,拦截器中使用了 LoadBalancerClient
来处理请求,LoadBalancerClient 本来就是 Spring 封装的负载均衡客户端,通过这样间接
处理,使得 RestTemplate 就拥有了负载均衡的功能
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