技术背景
我们利用COnsul注册中心实现了服务的注册与发现功能,这一章我们聊聊微服务的调用,在单体应用中,代码可以直接依赖,在带码中直接调用即可;但是在微服务框架(分布式框架)中,服务都运行在各自的进程之中, 甚至部署在不同的主机和地区, 就需要相关的远程调用技术了。
Spring Cloud体系中应用比较广泛的服务调用方式有两种:
(1)使用REstTemplate进行服务调用, 可以通过Ribbon注解REstTemplate模板,使其拥有负载均衡功能。
(2)使用Feign进行声明式服务调用, 声明之后就像调用本地服务一样, Feign默认使用Ribbon实现负载均衡。
两种方式都可以实现负载均衡,可以根据情况选择使用,下面我们分别实现案例来进行讲解。
服务提供者
- 新建一个项目hcnet-website-1,添加一下依赖
- swagger:API文档
- Consul : 注册中心
- Spring Boot Admin: 服务监控
<!--集成swagger2文档-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--集成服务监控-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!-- <!–集成服务发现–>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
- 配置文件
在配置文件添加内容如下, 将服务注册到注册中心并添加服务监控相关配置
consul:
host: 172.17.0.1
port: 8500
discovery:
service-name: ${spring.application.name}
hostname: 172.17.0.1
health-check-url: http://172.17.0.1:8211/actuator/health
boot:
admin:
client:
url: "http://172.17.0.1:8205"
instance:
service-base-url: "http://172.17.0.1:8205"
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: '*'
- 修改启动器类, 添加@EnableDiscoveryClient注解, 开启服务发现注解
//开启服务发现
@EnableDiscoveryClient
@SpringBootApplication
public class HcnetWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(HcnetWebsiteApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
4. 部署到线上
服务消费者
新建一个项目micro-consumer,添加一下依赖
- swagger: API文档
- Consul: 注册中心
- Spring Boot Admin: 服务监控
<!--集成swagger2文档-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!--集成服务监控-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>${spring-boot-admin.version}</version>
</dependency>
<!-- <!–集成服务发现–>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
添加配置
consul:
host: 172.17.0.1
port: 8500
discovery:
service-name: ${spring.application.name}
hostname: 172.17.0.1
health-check-url: http://172.17.0.1:8211/actuator/health
boot:
admin:
client:
url: "http://172.17.0.1:8205"
instance:
service-base-url: "http://172.17.0.1:8205"
management:
endpoint:
health:
show-details: always
endpoints:
web:
exposure:
include: '*'
- 启动类
添加@EnableDIscoveryClient注解, 开启服务发现支持
@EnableHystrix
//开启feigin
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class MicroConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(MicroConsumerApplication.class, args);
}
}
- 服务消费
添加服务消费测试类, 一个查询所有我们注册的服务,另一个从我们注册的服务中选取一个服务, 采用轮询的方式
@RestController
public class ServiceController {
@Autowired
private LoadBalancerClient loadBalancerClient;
@Autowired
private DiscoveryClient discoveryClient;
/**
* 获取所有服务
* @return
*/
@RequestMapping("/services")
public Object services(){
return discoveryClient.getInstances("hcnet-website-1");
}
/**
* 从所有服务中选择一个服务(轮询)
* @return
*/
@RequestMapping("/discover")
public Object discovery(){
return loadBalancerClient.choose("hcnet-website-1").getUri().toString();
}
}
添加完成之后, 启动项目,访问http://47.97.xxx.xxx:8500,服务消费者已经成功注册到注册中心,如图:
4. 负载均衡Ribbon
Ribbon是Netflix发布的负载均衡器,他有助于控制http和tcp客户端的行为。为Ribbon配置服务提供者地址之后, Ribbon就可以基于某种负载均衡算法自动的帮助服务消费者去请求。Ribbon默认为我们提供了很多负载均衡算法,例如轮询,随机登,当然,我们也可以为Ribbon实现自定义的负载均衡算法。
有两种选择:
- RoundRobinRule:轮询
- RandomRule:随机选择
6.修改器动类
注入RestTemplate, 并添加@LoadBalanced注解(用于拦截某些请求),以实现ribbon来进行负载均衡
//开启服务熔断
@EnableHystrix
//开启声明式服务消费客户端
@EnableFeignClients
//开启服务发现
@EnableDiscoveryClient
@SpringBootApplication
public class HcnetWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(HcnetWebsiteApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
7. 负载均衡策略
修改负载均衡策略,只需要在配置文件中指定对应的负载均衡器即可,如这里把策略修改为随机策略,之后负载均衡器会随机选择注册的服务
#负载均衡策略
service-producer: hcnet-website-1
ribbon:
NFLoadBalanceRuleClassName: com.netflix.loadbalancer.RandomRule
服务消费(Fegin)
Spring Cloud Feign是一套基于Netflix Feign实现的声明式服务调用客户端, 使编写Web服务客户端更加简单。 我们只需要通过创建接口并用注解来配置他即可完成对Web服务端口的绑定。它具有可插拔的注解支持,包括feign注解, JAX-RS注解, 他也支持可插拔的编码器和解码器。Spring Cloud Fegin 还扩展了对Spring MVC注解的支持,同时还整合了Ribbon来提供负载均衡的Http客户端实现
- 添加feign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 启动类
添加@EnableFeignClients注解, 开启扫描Spring Cloud Feign客户端的功能, 修改完成之后的启动类如下。
@EnableHystrix
//开启feigin
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class MicroConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(MicroConsumerApplication.class, args);
}
}
- 添加Feign接口
添加MangoProducerService接口,在类头添加注解 @FeignClient(“hcnet-website-1”),hcnetwebsite-1是要调用的服务名。
添加跟调用目标方法一样的方法声明, 只需要方法声明, 不需要具体实现, 注意跟目标方法定义保持一致