目录
本文介绍微服务的服务调用和负载均衡,使用spring cloud的loadbalancer及openfeign两种技术来实现。
本文的操作是在微服务的初步使用的基础上进行。
jdk1.8
maven3.6.3
mysql8
spring cloud2021.0.8
spring boot2.7.12
idea2022
为了方便测试,把高可用Eureka还原为单节点Eureka。
修改eureka_server的application.yml
- spring:
- application:
- name: eureka-server
- server:
- port: 9000
- eureka:
- instance:
- hostname: localhost
- client:
- registerWithEureka: false
- fetchRegistry: false
- serviceUrl:
- defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- server:
- enable-self-preservation: false
- eviction-interval-timer-in-ms: 4000
修改product-service服务和order-service服务的application.yml的Eureka配置如下
- eureka:
- client:
- service-url:
- defaultZone: http://localhost:9000/eureka/
spring-cloud-loadbalancer和ribbon类似,之前的spring cloud版本eureka内部继承了ribbon ,但spring cloud版本升级后,不再内置ribbon(可查看依赖关系),spring cloud提供了自己的负载均衡的实现,可查看 官方文档
Spring Cloud provides its own client-side load-balancer abstraction and implementation. For the load-balancing mechanism,
ReactiveLoadBalancerinterface has been added and a Round-Robin-based and Random implementations have been provided for it. In order to get instances to select from reactiveServiceInstanceListSupplieris used. Currently we support a service-discovery-based implementation ofServiceInstanceListSupplierthat retrieves available instances from Service Discovery using a Discovery Client available in the classpath.
之前服务调用时,使用host:ip拼接成URL的方式进行调用,较为麻烦,使用@LoadBalanced注解后,可以使用微服务的服务名称来进行调用,更加方便。
在创建RestTemplate的时候,申明@LoadBalanced
使用restTemplate调用远程微服务:不需要拼接微服务的URL,用服务名称替换IP地址
修改OrderController.java,使用服务名称代替host:port的形式,避免了之前的使用实例元数据进行拼接。
修改前
product = restTemplate.getForObject("http://"+host+":"+port+"/product/1", Product.class);
修改后
product = restTemplate.getForObject("http://service-product/product/1", Product.class);
启动测试
启动eureka、product、order服务
浏览器访问

能访问到数据,说明服务调用成功了。
使用@LoadBalanced注解后,除了方便使用服务名称进行调用之外,更重要的是也实现了服务调用的负载均衡功能。准备两个商品服务,端口号分别为9001、9011,两个商品服务的作用:1.增加系统吞吐率 2.商品服务高可用。
服务架构及流程如下图:

修改product-service的controller
- @Value("${spring.cloud.client.ip-address}") //springcloud自动获取应用的ip地址
- private String ip;
启动product服务(9001端口)
修改product服务的yml,修改服务端口为9011

复制运行配置得到另一个proudct服务


启动product2服务(9011端口)

查看Eureka Web页面
看到SERVICE-PRODUCT,有2个在线状态的实例,端口分别是:9001和9011

启动order服务
分别访问9001和9011
http://localhost:9001/product/1
http://localhost:9011/product/1

两个商品服务均正常
测试负载均衡
访问如下链接2次
发现实现 第一次访问9001商品服务,第二次访问了9011商品服务,说明实现了客户端的负载均衡

多次刷新访问http://localhost:9002/order/buy/1,发现9001和9011是交替出现,说明默认使用的负载均衡是轮询策略。
此前的服务调用代码如下:
restTemplate.getForObject("http://service-product/product/1", Product.class);
如果请求参数过多是,拼接URL的方式显得麻烦,可以使用OpenFeign来解决。
OpenFeign 全称 Spring Cloud OpenFeign,它是 Spring 官方推出的一种声明式服务调用与负载均衡组件,它的出现就是为了替代进入停更维护状态的 Feign。
OpenFeign 是 Spring Cloud 对 Feign 的二次封装,它具有 Feign 的所有功能,并在 Feign 的基础上增加了对 Spring MVC 注解的支持。
在order-service操作
1.导入依赖
- <dependency>
- <groupId>org.springframework.cloudgroupId>
- <artifactId>spring-cloud-starter-openfeignartifactId>
- dependency>
2.配置调用接口
业务需求:order服务调用product服务

- @FeignClient(name = "service-product")
- public interface ProductFeignClient {
-
- /**
- * 配置需要调用的微服务接口
- * @return
- */
- @RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
- Product findById(@PathVariable("id") Long id);
- }
3.在启动类上激活feign
- //激活feign
- @EnableFeignClients
- public class OrderApplication {
4.通过自动注入的接口调用远程微服务
修改之前的Controller代码
- @RestController
- @RequestMapping("/order")
- public class OrderController {
-
- @Autowired
- private RestTemplate restTemplate;
-
- @Autowired
- private DiscoveryClient discoveryClient;
-
- @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
- public Product findById(@PathVariable Long id){
- Product product = null;
-
- product = restTemplate.getForObject("http://service-product/product/1", Product.class);
-
- return product;
- }
-
- }
修改之后的代码
- @RestController
- @RequestMapping("/order")
- public class OrderController {
-
- @Autowired
- private ProductFeignClient productFeignClient;
-
- @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
- public Product findById(@PathVariable Long id){
- Product product = null;
-
- //调用微服务
- product = productFeignClient.findById(id);
-
- return product;
- }
-
- }
可以看出,OrderController通过注入ProductFeignClient接口实例,并调用接口方法实现了调用。 可以看出不需要自己构建http请求,就像是调用自身工程的方法调用。如果有多个参数可以传递对象参数,避免了拼接url的麻烦。
测试
启动服务
启动eureka、启动product(启动两个实例:9000和9011)、启动order
浏览器访问
分别访问,确保product服务能正常访问
访问order两次


多次访问,发现9001和9011交替出现,说明实现了负载均衡。
如果需要配置OpenFeign,在application.yml添加相关配置
配置案例如下:
- feign:
- client:
- config:
- feignName: #FeginClient的名称
- connectTimeout: 5000 #建立链接的超时时长
- readTimeout: 5000 #读取超时时长
- loggerLevel: full #Fegin的日志级别
- errorDecoder: com.example.SimpleErrorDecoder #Feign的错误解码器
- retryer: com.example.SimpleRetryer #配置重试
- requestInterceptors: #添加请求拦截器
- - com.example.FooRequestInterceptor
- - com.example.BarRequestInterceptor
- decode404: false #配置熔断不处理404异常
- #日志配置
- #NONE : 不输出日志(高)
- #BASIC: 适用于生产环境追踪问题
- #HEADERS : 在BASIC的基础上,记录请求和响应头信息
- #FULL : 记录所有
- service-product:
- logger-level: FULL #配置商品服务日志
- compression:
- request:
- enabled: true #开启请求压缩
- mime-types: text/html,application/xml,application/json #设置压缩的数据类型
- min-request-size: 2048 #设置触发压缩的大小下限
- response:
- enabled: true #开启相应压缩
- logging:
- level:
- org.example.order.feign.ProductFeignClient: debug #配置具体接口的日志级别
两种服务调用及负载均衡技术:@LoadBalanced方式和OpenFeign的方式。
1.@LoadBalanced方式是借助于RestTemplate方式进行,可以直接使用服务名称来调用,但需要拼接URL。
2.OpenFeign的方式是通过声明接口并注入接口进行调用,避免了拼接URL的麻烦。
完成!enjoy it!