微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用

服务之间的调用

上一篇搭建了一个Product服务,今天记录一下学习过程: 服务消费者ribbon和feign实战和注册中心高可用
笔记如下:

  1. 常用的服务间调用方式
    1. RPC:
      1.1 远程过程调用,像调用本地服务(方法)一样调用服务器的服务
      1.2 支持同步、异步调用
      1.3 客户端和服务器之间建立TCP连接,可以一次建立一个,也可以多个调用复用一次链接
      1.4 PRC数据包小
      protobuf
      thrift
      rpc:编解码,序列化,链接,丢包,协议
    2. Rest(Http):
      http请求,支持多种协议和功能
      开发方便成本低
      http数据包大
      java开发:HttpClient,URLConnection

项目搭建:微服务调用方式之ribbon实战 订单调用商品服务
简介:实战电商项目 订单服务 调用商品服务获取商品信息
1、创建order_service项目
2、开发伪下单接口
3、使用ribbon. (类似httpClient,URLConnection)
启动类增加注解

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

4、根据名称进行调用商品,获取商品详情

一:order订单服务搭建:
搭建一个springboot应用,与搭建Product服务一样,依赖选择如下微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第1张图片
实体类:

package com.xt.tools.erueka.order_server.domain;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/*
 * @description: 说明
 * @author: 小谭
 * @date: 2019/12/7 0:08
 */
@Data
public class ProductOrder implements Serializable {
    private int id;
    /**
     * 商品名称
     */
    private String productName
    /**
     * 订单号
     */
    private  String tradeNo;
    /**
     * 价格,分
     */
    private int price;
    private Date createTime;
    private int userId;
    private String userName;
}

Servic:

package com.xt.tools.erueka.order_server.service;
import com.xt.tools.erueka.order_server.domain.ProductOrder;

/*
 * @description: 说明
 * @author: 小谭
 * @date: 2019/12/7 0:08
 */
public interface orderService {
    ProductOrder save(int userId, int product);
}

实现类:

package com.xt.tools.erueka.order_server.service;

import com.xt.tools.erueka.order_server.domain.ProductOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.Map;
import java.util.UUID;

/*
 * @description: 说明
 * @author: 小谭
 * @date: 2019/12/7 0:09
 */
@Service
public class orderServiceImpl implements orderService {

    @Autowired
    private RestTemplate restTemplate;

    @Override
    public ProductOrder save(int userId, int productId) {
        //获取商品详情  http://localhost:8771/api/v1/product/find?id=1
        String url="http://product-service/api/v1/product/find?id="+productId;
        System.out.println(url);
        Map<String,Object> productMap = restTemplate.getForObject(url, Map.class);
        ProductOrder productOrder = new ProductOrder();
        productOrder.setCreateTime(new Date());
        productOrder.setUserId(userId);
        productOrder.setTradeNo(UUID.randomUUID().toString());
        productOrder.setProductName(productMap.get("name").toString());
        productOrder.setPrice(Integer.parseInt(productMap.get("price").toString()));

        System.out.println(productOrder);
        return productOrder;
    }
}

其中product-service代表着之前的Product服务微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第2张图片

controller:

package com.xt.tools.erueka.order_server.controller;

import com.xt.tools.erueka.order_server.domain.ProductOrder;
import com.xt.tools.erueka.order_server.service.orderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/*
 * @description: 说明
 * @author: 小谭
 * @date: 2019/12/7 0:06
 */
@RestController
@RequestMapping("/api/v1/order")
public class orderController {
    @Autowired
    private orderService OrderService;
    //模拟下单接口
    @RequestMapping("save")
    public Object save(@RequestParam("userId") int userId,@RequestParam("productId") int product){
        return OrderService.save(userId,product);
    }
}

启动类:

package com.xt.tools.erueka.order_server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class OrderServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class, args);
    }
//    可做负载均衡
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

配置文件:


server:
  port: 8781
#指定注册中心地址
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
#服务的名称
spring:
  application:
    name: order-service

最后,为了分辨服务在哪个端口调用,修改一下product服务代码

    @Value("${server.port}")
    private String port;
    @RequestMapping("find")
    public Object product(@RequestParam("id") int id){
        Product product = productService.findById(id);
        product.setName(product.getName()+"----"+port);
        return product;
    }

启动服务:
为了方便观察负载均衡现象,我这里创建了3个Product实例,当然也可以以其他方法运行多个实例来模拟集群

-Dserver.port=8773

微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第3张图片
刷新注册中心:
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第4张图片
到此:各个服务都已经注册到注册中心:
访问订单order服务接口:
http://localhost:8781/api/v1/order/save?userId=123&productId=1
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第5张图片
有数据返回,说明服务正常,并且调用端口是:8771,接下来不断刷新页面在这里插入图片描述
在这里插入图片描述
一直在8771-8773之间轮流调用,因为默认采用的是负载均衡策略中的轮询策略
ribbon服务间调用负载均衡源码分析
1、分析@LoadBalanced
1)首先从注册中心获取provider的列表
2)通过一定的策略选择其中一个节点
3)再返回给restTemplate调用

接下来修改一下负载均衡的策略
自定义负载均衡策略:http://cloud.spring.io/spring-cloud-static/Finchley.RELEASE/single/spring-cloud.html#_customizing_the_ribbon_client_by_setting_properties
在配置文件yml里面,自定义负载均衡策略
#自定义负载均衡策略

	product-service:
	  ribbon:
	    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

策略选择:
1、如果每个机器配置一样,则建议不修改策略 (推荐)
2、如果部分机器配置强,则可以改为 WeightedResponseTimeRule

微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第6张图片

刷新页面:
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第7张图片

第二次刷新:8773端口
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第8张图片
第三次刷新:8772端口:
在这里插入图片描述
至此,默认的负载均衡策略修改完毕(当然也可以在源码上打断点调试证明):

二:微服务调用方式之feign

Feign: 伪RPC客户端(本质还是用http)
官方文档: https://cloud.spring.io/spring-cloud-openfeign/

1、使用feign步骤讲解(新旧版本依赖名称不一样)
加入依赖
启动类增加 @EnableFeignClients
增加一个接口 并 @FeignClient(name=“product-service”)
2、注意点:
1、路径
2、Http方法必须对应
3、使用requestBody,应该使用@PostMapping
4、多个参数的时候,通过@RequestParam(“id”) int id)方式调用
3.编码实战:

添加依赖:

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

新建service接口:

package com.xt.tools.erueka.order_server.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/*
 * @description: 说明
 * @author: 小谭
 * @date: 2019/12/8 21:29
 */
@FeignClient(name="product-service")
public interface ProductClient {
    @RequestMapping("/api/v1/product/find")
    String findById(@RequestParam("id")int id);
}

修改service接口:
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第9张图片
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第10张图片
启动类:
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第11张图片
微服务SpringCloud+Docker入门实战(二):ribbon、feign服务之间的调用_第12张图片
数据正常返回

服务间的调用方式ribbon、feign选择

	1、ribbon和feign两个的区别和选择
		选择feign
			默认集成了ribbon
			写起来更加思路清晰和方便
			采用注解方式进行配置,配置熔断等方式方便

	2、超时配置
		默认optons readtimeout是60,但是由于hystrix默认是1秒超时

		#修改调用超时时间
		feign:
		  client:
		    config:
		      default:
		        connectTimeout: 2000
		        readTimeout: 2000

		模拟接口响应慢,线程睡眠新的方式
		  try {
	            TimeUnit.SECONDS.sleep(1);
	        } catch (InterruptedException e) {
	            e.printStackTrace();
	        }

GitHub项目: https://github.com/XT962464oo/Eureka_demo

你可能感兴趣的:(微服务)