您的位置:首页 > 编程语言 > Java开发

3.springcloud中使用Ribbon和Feign调用服务以及服务的高可用

2017-11-10 17:28 966 查看

1.消费者使用Ribbon组件负载均衡的调用服务者接口

在上一节中只介绍了如何将服务者和消费者注册到Eureka注册中心中,消费者并没有调用服务者,现在开始介绍,首先为了避免混淆,不再用上一节的消费者,重新建一个名为microservice-consumer-movie-ribbon的消费者,代码跟microservice-consumer-movie的一样,下面介绍如何负载均衡的调用。

1.1 使用Ribbon默认的轮询方式调用服务者

引入jar包

如果调用者要使用Ribbon实现调用服务者的负载均衡首先想到的是引入Ribbon的jar包,这里Eureka中已经包含了此jar,我们上一节已经引入了Eureka的jar,这里可以不用再引入了。

Main方法中引入@LoadBalanced负载均衡注解

在MicroserviceConsumerMovieRibbonApplication的创建调用实例对象RestTemplate中加入注解@LoadBalanced注解,默认是轮询。

@SpringBootApplication
@EnableEurekaClient
public class MicroserviceConsumerMovieRibbonApplication {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return  new RestTemplate();
}
public static void main(String[] args) {        SpringApplication.run(MicroserviceConsumerMovieRibbonApplication.class, args);
}
}


启动两个或两个以上服务者进行测试

启动注册中项目和服务者,消费者项目,这里因为要测负载均衡,所以至少要启动两个服务者才行。启动完第一个服务者之后,修改application.yml的端口号,接着启动第二个服务者,如下图:



经过以上步骤即可创建另一个服务者实例MicroserviceProviderUserApplication2,启动它将其注册到注册中心中。

访问消费者的项目,多刷新一次会发现交替调用服务者MicroserviceProviderUserApplication和MicroserviceProviderUserApplication2,测试成功。

1.2自定义负载均衡算法调用服务者

可以自己定义一个负载均衡策略的类,我这里定义一个随机策略。

/**
* @author 刘俊重
* @Description 负载均衡配置,配置调用者调用服务者的调用策略
* @date 13:56
*/
@Configuration
public class BalanceConfiguration {
/**
* @Description 定义随机调用的负载均衡算法
*/
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
}


在Main方法中,RibbonClient注解中指明调用某个服务使用某个指定的策略。

@RibbonClient(name="microservice-provider-user",configuration = BalanceConfiguration.class)


调用microservice-provider-user服务时,使用BalanceConfiguration定义的负载均衡策略,完整的代码如下:

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="microservice-provider-user",configuration = BalanceConfiguration.class)
public class MicroserviceConsumerMovieRibbonApplication {

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return  new RestTemplate();
}

public static void main(String[] args) {    SpringApplication.run(MicroserviceConsumerMovieRibbonApplication.class, args);
}
}


注意:所有用到Ribbon负载均衡的均要有@LoadBalanced注解,只是我们没有定义自己的调用策略时,默认会使用轮询的策略。同时这里有坑,不能把定义的策略类BalanceConfiguration放在Main方法同级或子包下面,会有冲突(或者你自己用注解@ComponentScan再写方法,不让spring扫描这个自定义的策略类),官方文档中写的非常清楚,不懂的可以看看:https://springcloud.cc/spring-cloud-dalston.html#_customizing_the_ribbon_client

1.3使用配置文件自定义RibbonClient实现客户端负载均衡

springcloud从1.2.0版本之后支持通过自定义配置文件的方式配置负载均衡策略。官方在application.yml中这样配置的:

users:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.WeightedResponseTimeRule


你只需要把users改成你的服务提供者的应用名称即可,WeightedResponseTimeRule可以配置成其他的策略,这里为了不影响其它代码,我再重新创建一个microservice-consumer-movie-ribbon-custom-properties项目。之前Main方法的@RibbonClient可以去掉了,application.yml中这么配置:

microservice-provider-user:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule


这段配置的意思就是通过Ribbon调用microservice-provider-user服务时采用RandomRule(随机)的策略。

小结:消费者调用服务者时,我们使用Ribbon实现请求的负载均衡,而且Eureka的jar中已经集成了Ribbon,不用再引jar包即可直接使用。使用有三种方法:1.直接在RestTemplate实例中添加@LoadBalanced即可实现默认轮询的负载均衡,2.自定义负载均衡策略类,并在RibbonClient中引入这个策略类,3.在yml配置文件中自定义负载策略,其中第三种比较方便。

2.使用Ribbon不使用Eureka

为防止污染其它代码,再创建一个microservice-consumer-movie-ribbon-without-eureka项目,用来演示使用Ribbon时不适用Eureka。

官方文档中在application.yml中这样配置:

stores:
ribbon:
listOfServers: example.com,google.com


意为通过ribbon调用stores不适用Eureka中注册的服务者,而是调用example.com和google.com这两个服务。

那我也这样做,配置文件如下:

microservice-provider-user:
ribbon:
listOfServers: localhost:7100


当使用ribbon调用microservice-provider-user服务时调用localhost:7100的服务,虽然Eureka中microservice-provider-user注册了好几个服务提供者(比如localhost:7100,localhost:7101,localhost:7102),但只会调用localhost:7100,这就是使用Ribbon不使用Eureka。注意:@LoadBalanced注解不要落下,因为listOfServers这里也可以配置多个主机,同样需要负载均衡。

文档地址:https://springcloud.cc/spring-cloud-dalston.html#spring-cloud-ribbon-without-eureka

3.在Ribbon中禁用Eureka

application.yml中这样配置即可:

ribbon:
eureka:
enabled: false


文档地址:https://springcloud.cc/spring-cloud-dalston.html#_example_disable_eureka_use_in_ribbon

4.声明式的Rest客户端:Feign

Feign是一种声明式的Web服务客户端,通过它可以方便的调用服务提供者的服务。使用Feign的步骤如下:

- 引入Feign的jar

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>


自定义Feign客户端类

/**
* @Description 用户自定义Feign客户端
* @Author 刘俊重
* @Date 2017/11/8
*/
@FeignClient("microservice-provider-user")
public interface UserFeign {

@RequestMapping(value = "/simple/{id}",method = RequestMethod.GET)
public User findUserbyId(@PathVariable("id") Long id);
}


@FeignClient注明要调用的服务microservice-provider-user,public User findUserbyId(@PathVariable(“id”) Long id)这个接口是服务提供者接受调用的。

- Main方法中加入@EnableFeignClients表明这个Feign客户端

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class MicroserviceConsumerMovieFeignApplication {
public static void main(String[] args) {    SpringApplication.run(MicroserviceConsumerMovieFeignApplication.class, args);
}
}


消费者调用端注入自定义的Feign客户端,发起调用请求。

@RestController
public class MovieController {
@Autowired
private UserFeign userFeign;
@GetMapping("/simple/{id}")
public User findUserById(@PathVariable Long id){
return userFeign.findUserbyId(id);
}
}


自定义了Feign客户端就不需要再使用RestTemplate调用了,现在的调用顺序是调用者通过调用自定义Feign客户端调用,自定义的Feign客户端又通过@FeignClient声明要调用的服务,通过跟服务者同名的方法调用。但是这里还有几个坑:

1. @GetMapping不支持,需要使用@RequestMapping,在括号里面指定请求方式。

2. @PathVariable得设置value,@PathVariable(“id”)如果没有(“id”)会报错

3. Feign里面方法的参数如果是复杂对象(引用数据类型),即使你通过method = RequestMethod.GET指定这个get请求,请求到达服务提供者时依然是以Post请求方式到达的。

5.覆盖Feign的默认值(自定义Feign的配置方式)

默认情况下,Feign使用的是SpringMvcContract(Springmvc的契约),可以在Feign客户端中使用

@RequestMapping(value = "/simple/{id}",method = RequestMethod.GET)


这种方式调用服务者,但是假如我们不想采用这种方式,而是通过自定义的方式那就可以定义这样一个类。

- 定义Feign配置类,覆盖默认配置

/**
* @author 刘俊重
* @Description 自定义Feign的配置
*/
@Configuration
public class CustomFeignConfiguration {
@Bean
public Contract feignContract() {
return new feign.Contract.Default();
}
}


在Feign客户端中引入刚才定义的配置类

@FeignClient(name="microservice-provider-user",configuration = CustomFeignConfiguration.class)
public interface UserFeign {
@RequestLine("GET /simple/{id}")
public User findUserbyId(@Param("id") Long id);
}


因为我们已经覆盖了Feign的默认配置,自定义了CustomFeignConfiguration,里面定义契约不再采用springmvc的而是采用Feign的,所以这里请求注解@RequestMapping要改成@RequestLine,相应参数也要改变了,不然会报错。参考文档:https://springcloud.cc/spring-cloud-dalston.html#spring-cloud-feign-overriding-defaults

6.解决Feign第一次请求超时的问题

在实际测试中发现如果机器配置比较低,第一次使用Feign调用服务者时经常会出现超时的现象,之后再调用就没有问题了,可以通过以下方法解决。

# 解决第一次请求报超时异常的方案:
# hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000   (将请求超时时间设为5秒)
# 或者: (直接禁用超时提醒)
# hystrix.command.default.execution.timeout.enabled: false
# 或者:
feign.hystrix.enabled: false ## 索性禁用feign的hystrix支持


Eureka的高可用设置

Eureka在这里充当的是注册中心的作用,所以必须要保证高可用,每个Eureka服务器同时也是一个Eureka客户端,同时还需要至少一个服务来定位对等体。Eureka的高可用可以采用下面的步骤来完成。

- application.xml中配置多个Eureka对等体

spring:
application:
name: EUREKA-HA
---
server:
port: 8761
spring:
profiles: peer1
eureka:
instance:
hostname: peer1
client:
serviceUrl:
defaultZone: http://peer2:8762/eureka/ ---
server:
port: 8762
spring:
profiles: peer2
eureka:
instance:
hostname: peer2
client:
serviceUrl:
defaultZone: http://peer1:8761/eureka/[/code] 
上面的意思就是定义一个应用名为EUREKA-HA,定义一个profiles名为peer1,它的主机名是peer1,将其注册到http://peer2:8762/eureka/ 服务器上,peer2跟它同理,现在peer1跟peer2就是对等体(名字可以随便定)。

- window系统修改hosts文件。进入“C:\Windows\System32\drivers\etc”,修改hosts文件

127.0.0.1 peer1 peer2


依次启动peer1和peer2。

启动pee1时可能会报错,因为它要把服务注册到peer2上,但是peer2还未启动,不用管它,访问http://localhost:8761 ,发现什么都没有;接着启动peer2,访问http://localhost:8762 ,发现8761和8762都注册在了8762上,此时在刷新8761的浏览器页面发现8761和8762已经都在了,因为peer1和peer2是对等体,他们互相注册,服务注册表也是共享了,由此就组成了Eureka的高可用。启动peer1和peer2图片如下图(Active profiles必须配置,否则报错):



注意:如果你引入了spring-boot-starter-security包,但是并没有指定用户名和密码,那么Eureka会为你生成一个随机密码,导致你登录不上,所以请不要引入spring-boot-starter-security或者自己指定密码。参考地址:https://springcloud.cc/spring-cloud-dalston.html#spring-cloud-eureka-server-zones-and-regions

总结:本节首先是将服务提供者和消费者注册在了Eureka的注册中心上,之后消费者通过两种方式调用服务者,一种是Ribbon负载均衡调用,一种是用Feign客户端调用,当然在每种调用方式中都可以进行自定义配置;鉴于Eureka注册中心的地位非常重要,一旦宕机将导致其它服务都不可用,所以需要保证Eureka注册中心的高可用。

代码地址:https://gitee.com/catchu/springcloud-study
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐