Ribbon也是netfix开源的负载均衡框架。而feign则是spring对Ribbon和hystrix进行了进一步的封装的组件。
1.Ribbon
单机实现:关于注册中心的搭建在上篇文章中进行了描述就不赘述了。准备两个相同的服务模块,再准备一个消费者模块。
服务者模块:
端口8001服务者 application.yml配置:
server:
port: 8001
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka
instance:
prefer-ip-address: true #在Eureka注册中心显示服务者的ip
spring:
application:
name: PRODUCER
端口8002 服务者 application.yml配置
server:
port: 8002
spring:
application:
name: PRODUCER
eureka:
client:
service-url:
defaultZone: http://eureka-7001.com:7001/eureka
instance:
prefer-ip-address: true #在Eureka注册中心显示服务者的ip
准备服务者的controller
@RestController
@RequestMapping("/producer")
public class ProducerController {
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
//两个服务者的controller可以通过后面的字符串来进行区分。方便观查负载均衡的思想
return new User(id, "shine on your crazydiamond");
}
}
准备消费者模块
application.yml配置
server:
port: 9002
eureka:
client:
registerWithEureka: false #不注册到Eureka,不在注册中心显示
service-url:
#defaultZone: http://localhost:7001/eureka
defaultZone: http://eureka-7001.com:7001/eureka
准备消费者模块的controller
通过消费者拿到服务者提供的服务。
在这需要通过ribbon的RestTemplate对象实现访问服务者的服务。
我们需要将RestTemplate交于spring容器托管,在springboot都是通过java类进行配置
代码如下
@Configuration //相当于一个独立的spring的xml配置文件
public class ConsumerConfig {
/**
* 该对象用于消费者通过注册中心访问服务
* @return
*/
@Bean //表示返回的对象是一个bean
@LoadBalanced //Ribbon用于配置负载均衡
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
//在传统调用中都是直接访问生产者的服务的地址,在ribbon中使用服务的名称进行访问
private static final String URL_PREFIX = "http://PRODUCER";
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
//服务者提供的服务的地址
String url = URL_PREFIX+"/producer/user/"+id;
return restTemplate.getForObject(url, User.class);
}
}
然后依次启动注册中心,服务者/消费者
发现注册了两个服务
然后通过访问消费者的地址进行服务的获取
分别访问了两个服务者的controller进行了服务的获取。
这就是简单的ribbon负载均衡的实现
ribbon提供了多种算法进行了负载均衡的实现
算法 | 描述 |
RoundRobinRule(默认) | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。注意:可以通过修改配置loadbalancer..connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上线,可以由客户端的..ActiveConnectionsLimit属性进行配置。 |
– | – |
WeightedResponseTimeRule | 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。 |
– | – |
BestAvailableRule | 忽略哪些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
可以通过配置进行算法的选择
简单实现
@Configuration
public class ConsumerConfig {
/**
* 设置 ribbon负载均衡的计算方法
* @return
*/
@Bean
public IRule getRule(){
return new RandomRule();
}
}
2.Feign
feign对ribbon进行了封装,通过webservice式的方式实现获取服务,即提供一个公共接口,该接口会通过代理对象帮我们实现服务调用
具体实现步骤:
抽取一个服务者和消费者的公共接口模块
导入依赖:
<!--导入feign的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
代理接口
只需要打上FeignClient注解即可,在该接口中写服务者中要提供的服务。以及访问的地址。
@FeignClient(value = "PRODUCER")//name要与服务名称一致
@RequestMapping("/producer")//和生产者路径要一致
public interface UserClient {
@RequestMapping("/user/{id}")
User getUser(@PathVariable("id") Long id);
}
服务者最好实现该接口,使服务者和消费者保持一致。
@RestController
@RequestMapping("/producer")
//实现UserClient进行限制 生产者和消费者保持一致
public class ProducerController implements UserClient {
@RequestMapping("/user/{id}")//RESTful风格
public User getUser(@PathVariable("id")Long id){
return new User(id, "close to the edge");
}
}
在消费者模块导入feign的依赖
<!--导入feign的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
消费者的controller
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
@Autowired
private UserClient userClient;
@RequestMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id){
return userClient.getUser(id);//直接通过该接口的代理对象访问服务者提供的服务
}
}
消费者的入口类
@SpringBootApplication
@EnableEurekaClient
//对代理接口所在的包进行扫描,才能在controller注入该对象
@EnableFeignClients(basePackages = "cn.itsource.springcloud.client")
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class);
}
}
feign的实现思路将我们可能进行的重复的操作,例如使用ribbon时url的拼接等繁复的步骤封装了,简洁。