SpringCloud学习2-Zookeeper_Consul_Ribbon_OpenFeign

1 Zookeeper服务注册和发现

1、介绍

image-20200711100730926

作用

(1)Zookeeper是一个分布式协调工具,可以实现注册中心功能。

(2)关闭Linux服务器的防火墙后启动Zookeeper服务器。

(3)Zookeeper服务器取代Eureka服务器,Zookeeper作为注册中心。

2、服务提供者cloud-provider-payment8004

1、创建项目

1、项目结构

image-20200817224410715

2、添加yml文件

#8004表示注册到zookeeper服务器的支付服务提供端口号
server:
  port: 8004

#服务别名 --- 注册zookeeper的注册中心名称
#使用下面的39.96.161.64的地址并开通端口号,可以进行服务器的注册
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      connect-string: 39.96.161.64:2181

3、主启动类

/**
 *  @EnableDiscoveryClient
 *  此时不用添加Eureka
 *  该注解用于向使用consul或者zookeeper作为注册中心时注册服务
 */
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8004 {
    
    
	public static void main(String[] args) {
    
    
		SpringApplication.run(PaymentMain8004.class, args);
	}
}

4、Controller

@RestController
@Slf4j
public class PaymentController {
    
    

	@Value("${server.port}")
	private String serverPort;

	@GetMapping(value = "/payment/zk")
	public String paymentzk(){
    
    
		return "springcloud with zookeeper:"+serverPort+"\t"+ UUID.randomUUID().toString();
	}
}

5、启动阿里云服务器上的zookeeper服务

6、启动cloud-provider-payment8004注册进zookeeper

(1)启动后遇到问题

image-20200817101518444

这是因为我们服务器上使用的zookeeper的版本是3.4.10,而IDEA中导入的依赖中的版本是3.5.3,导致zookeeper版本jar包冲突。

image-20200817225351688

(2)解决方法

 <!-- 只有这个是新的。SpringBoot整合Zookeeper客户端
            jar包冲突报错,jar包的排除和引入
         -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>-->
<!--        </dependency>-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <!--先排除自身的zk3.5.3-->
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--再添加zk 3.4.10版本,与服务器的zk一致-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.10</version>
</dependency>

7、测试

(1)输入下面的网址:

http://localhost:8004/payment/zk

会在网页上返回一个端口和一串流水号。

(2)获得json串后用在线工具查看。

首先,启动zookeeper服务端后,使用下面的指令启动客户端,进行查看:

./zkCli.sh

通过下面的指令获取服务节点:

ls /

image-20200817225634174cloud-provider-payment8004节点是临时节点。

3、服务消费者cloud-consumerzk-order80

1、创建项目

1、项目结构

image-20200817230023634

2、添加yml文件

server:
  port: 80

spring:
  application:
    name: cloud-consumer-order
  cloud:
    #注册到zookeeper中的地址
    zookeeper:
      connect-string: 39.96.161.64:2181

3、启动类

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

4、业务类

(1)配置Bean

@Configuration
public class ApplicationContextConfig {
    
    

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

(2)controller

@RestController
@Slf4j
public class OrderZKController {
    
    

	public static final String INVOME_URL = "http://cloud-provider-payment";

	@Resource
	private RestTemplate restTemplate;

	@GetMapping("/consumer/payment/zk")
	public String payment (){
    
    
		String result = restTemplate.getForObject(INVOME_URL+"/payment/zk",String.class);
		return result;
	}
}

5、启动cloud-consumerzk-order80注册进zookeeper

6、测试

​ 此时,在环境中有cloud-provider-payment8004cloud-consumerzk-order80同时运行。

(1)查看阿里云服务器的zookeeper的节点

image-20200817230538582

(2)输入网址:

http://localhost:8004/payment/zk

会在网页上返回一个端口和一串流水号。

image-20200817231032580

(3)输入网址:

http://localhost/consumer/payment/zk
image-20200817231502460

2 Consul服务注册和发现

1、介绍

1、网址

介绍网址:

https://www.consul.io/intro/index.html

下载网址:

https://www.consul.io/downloads.html
image-20200817231701528

2、作用

(1)服务发现:提供HTTP和DNS两种发现方式。

(2)健康监测:支持多种协议,HTTP、TCP、Docker、Shell脚本定制化。

(3)KV存储:key , Value的存储方式。

(4)多数据中心:Consul支持多数据中心。

(5)可视化Web界面。

2、安装并运行Consul

1、下载完成后只有一个consul.exe文件,硬盘路径下双击运行,使用下面的指令查看版本信息。

consul --version
image-20200817232019096

2、使用开发模式启动

(1)使用下面的指令启动consul:

consul agent -dev

(2)通过以下地址可以访问Consul的首页:

http://localhost:8500

(3)结果页面

image-20200817232215825

3、服务提供者cloud-providerconsul-payment8006

1、创建项目

1、项目结构

image-20200817232337382

2、添加yml文件

#consul服务端口号
server:
  port: 8006

spring:
  application:
    name: consul-provider-payment
#consul 注册中心地址
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${
    
    spring.application.name}

3、主启动类

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

4、业务类controller

@RestController
@Slf4j
public class PaymentController {
    
    

   @Value("${server.port}")
   private String serverPort;

   @GetMapping(value = "/payment/consul")
   public String paymentConsul() {
    
    
      return "springcloud with consul: " + serverPort + "\t" + UUID.randomUUID().toString();
   }
}

5、测试

​ 输入网址:

http://localhost:8006/payment/consul

将会有一个端口号+ 一串流水号;输入网址:

http://localhost:8500

将会弹出下面的界面:

image-20200817232546649

4、服务消费者cloud-consumerconsul-order80

1、创建项目

1、项目结构

image-20200817232737391

2、添加yml文件

server:
  port: 80

spring:
  application:
    name: consul-consumer-order
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${
    
    spring.application.name}

3、主启动类

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

4、业务类

(1)配置Bean

@Configuration
public class ApplicationContextConfig {
    
    

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

}

(2)controller

@RestController
@Slf4j
public class OrderConsulController {
    
    
	public static final String INVOME_URL = "http://consul-provider-payment";
	@Resource
	private RestTemplate restTemplate;

	@GetMapping("/consumer/payment/consul")
	public String payment() {
    
    
		String result = restTemplate.getForObject(INVOME_URL + "/payment/consul", String.class);
		return result;
	}
}

5、测试

(1)输入网址:

http://localhost:8500

将会弹出下面的界面:

image-20200817233015020

(2)输入网址:http://localhost/consumer/payment/consul,将会获得

cloud-providerconsul-payment8006的端口号+一串流水号。

5、三个注册中心的异同点

1、CAP

(1)C:Consistency(强一致性)

(2)A:Availability(可用性)

(3)P:Partition tolerance(分区容错)

CAP理论关注粒度是数据,而不是整体系统设计的策略。

2、分析

image-20200817233733267 image-20200817234843232
组件名 语言 CAP 服务器健康检查 对外保留接口 SpringBoot集成
Eureka Java AP 可配支持 HTTP 已集成
Consul Go CP 支持 HTTP/DNS 已集成
Zookeeper Java CP 支持 客户端 已集成

(1)AP(Eureka)

image-20200817233600030 image-20200817233607656

(2)CP(Zookeeper/Consul)

image-20200817233634551 image-20200817233647176

3 Ribbon负载均衡服务调用

1、介绍

image-20200820083732769

1、官网资料

网址:https://github.com/Netflix/ribbon/wiki/Getting-Started

目前Ribbon也进入维护阶段:

image-20200820083848170

替代方案:

image-20200820084009441

2、作用

(1)负载均衡

image-20200820084102765

(a)集中式LB

image-20200820084157828

(b)进程式LB

image-20200820084240600

(2)总结

负载均衡+RestTemplate调用(80通过轮询负载访问8001/8002)。

2、负载均衡演示

1、架构说明

​ Ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例。

image-20200820084959642 image-20200820085017075

2、pom文件

image-20200820085338979 image-20200820085351457

3、RestTemplate的使用

(1)官网

https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html
image-20200820085727229

(2)getForObject方法/getForEntity方法

image-20200820085745989

(3)postForObject/postForEntity

image-20200820085833394

3、Ribbon核心组件IRule

1、根据特定算法从服务列表中选取一个要访问的服务。

image-20200820090333139 image-20200820090348766

2、如何替换

(1)修改cloud-consumer-order80模块

配置细节:

image-20200820102909584 image-20200820102929250

(2)新建package-com.xiaolun.myrule

image-20200820103023940

(3)添加规则类

@Configuration
public class MySelfRule {
    
    

    @Bean
    public IRule myRule(){
    
    
        return new RandomRule();//定义为随机
    }
}

(4)主启动类添加注解@RibbonClient

@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(OrderMain80.class,args);
    }

}

(5)测试

输入网址:

http://localhost/consumer/payment/get/5

可以随机访问。

4、手写负载均衡算法

1、原理

image-20200820103408449

2、手写算法

(1)启动cloud-eureka-Server-7001/7002。

(2)改造cloud-provider-payment8001/8002

//controller中添加下面的内容,当消费者访问时,可以将端口号返回
@GetMapping(value = "/payment/lb")
    public String getPaymentLB() {
    
    
    return serverPort;
}

(3)改造cloud-consumer-order80

(a)ApplicationContextBean去掉@LoadBalanced,主要是使用自己写的负载均衡。

(b)创建LoadBalancer接口

image-20200820104857726
public interface LoadBalancer {
    
    
	//收集服务器总共有多少台能够提供服务的机器,并放到list里面
	ServiceInstance instances(List<ServiceInstance> serviceInstances);

}

(c)LoadBalancer接口实现类

@Component
public class MyLB implements LoadBalancer {
    
    

	private AtomicInteger atomicInteger = new AtomicInteger(0);

	//坐标
	private final int getAndIncrement() {
    
    
		int current;
		int next;
		do {
    
    
			current = this.atomicInteger.get();
			next = current >= 2147483647 ? 0 : current + 1;
		} while (!this.atomicInteger.compareAndSet(current, next));  //第一个参数是期望值,第二个参数是修改值
		System.out.println("*******第几次访问,次数next: " + next);
		return next;
	}

	@Override
	public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
    
      //得到机器的列表
		int index = getAndIncrement() % serviceInstances.size(); //得到服务器的下标位置
		return serviceInstances.get(index);
	}
}

(d)改造controller

@Resource
private LoadBalancer loadBalancer;

@Resource
private DiscoveryClient discoveryClient;

@GetMapping(value = "/consumer/payment/lb")
	public String getPaymentLB() {
    
    
		List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
		if (instances == null || instances.size() <= 0) {
    
    
			return null;
		}
		ServiceInstance serviceInstance = loadBalancer.instances(instances);
		URI uri = serviceInstance.getUri();
		log.info("uri-----"+uri);
		return restTemplate.getForObject(uri + "/payment/lb", String.class);
	}

(e)测试

输入网址:

http://localhost/consumer/payment/lb

浏览器输出:

image-20200820105142930

端口8001/8002可以交替变换,即实现了负载均衡。

5 OpenFeign服务接口调用

1、介绍

1、概述

image-20200820105358611

Feign是一个声明式的web服务客户端,让编写web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。

GitHub:

https://github.com/spring-cloud/spring-cloud-openfeign

2、作用

image-20200820105421099

3、Feign和OpenFeign的区别

image-20200820105522759

2、OpenFeign使用步骤

核心:接口+注解:微服务调用接口+@FeignClient。

项目结构:

image-20200820112843704

1、新建cloud-consumer-feign-order80,Feign在消费端使用。

2、添加pom文件

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

3、添加yml文件

server:
  port: 80

spring:
  application:
    name: cloud-order-service
eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka

4、添加主启动类

@SpringBootApplication
@EnableFeignClients //添加该注解
@EnableEurekaClient
public class OrderFeignMain80 {
    
    
	public static void main(String[] args) {
    
    
		SpringApplication.run(OrderFeignMain80.class, args);
	}
}

5、添加业务类

实现:业务逻辑接口+@FeignClient配置调用provider服务。

(1)新建PaymentFeignService接口并新增注解@FeignClient

@Component
//CLOUD-PAYMENT-SERVICE服务的的名字
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    
    
	@GetMapping("/payment/get/{id}")
	public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

注解@FeignClient是一个使用的标识,在启动类的注解@EnableFeignClients是一个启用标识。

(2)添加controller

@RestController
public class OrderFeignController {
    
    

	@Resource
	private PaymentFeignService paymentFeignService;

	@GetMapping(value = "/consumer/payment/get/{id}")
	public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){
    
    
		return paymentFeignService.getPaymentById(id);
	}
}

5、测试

先启动2个eureka集群cloud-eureka-Server7001/7002,再启动2个微服务cloud-provider-payment8001/8002,最后启动cloud-consumer-feign-order80启动,输入地址:

http://localhost/consumer/payment/get/5
image-20200820113647003

可以发现Feign自带负载均衡配置项,上图中的端口号8001/8002来回切换。

执行逻辑:

cloud-consumer-feign-order80模块此时作为消费者,当客户端输入地址后,地址首先会进入到cloud-consumer-feign-order80模块中controller中,即OrderFeignController的方法,执行完成后,该方法会到接口类PaymentFeignService中执行@GetMapping的方法,这样通过OpenFeign就可以调用cloud-provider-payment8001/8002,即消费者到服务者之间的网路就打通了。

image-20200820114749976

3、超时控制

1、案例

(1)在服务提供方cloud-provider-payment8001/8002中的com.xiaolun.springcloud.controller中添加延时程序:

@GetMapping(value = "/payment/feign/timeout")
public String paymentFeignTimeout() {
    
    
   try {
    
    
      TimeUnit.SECONDS.sleep(2);
   } catch (Exception e) {
    
    
      e.printStackTrace();
   }
   return serverPort;
}

(2)服务消费方cloud-consumer-feign-order80的接口com.xiaolun.service.PaymentFeignService中添加超时方法PaymentFeignService(和(1)中的方法对应)

@GetMapping(value = "/payment/feign/timeout")
	public String paymentFeignTimeout();

(3)服务消费方cloud-consumer-feign-order80的控制类com.xiaolun.controller.OrderFeignController中添加超时方法PaymentFeignService

@GetMapping(value = "/consumer/payment/feign/timeout")
public String paymentFeignTimeout(){
    
    
	return paymentFeignService.paymentFeignTimeout();
}

(4)测试

​ 先启动2个eureka集群cloud-eureka-Server7001/7002,再启动2个微服务cloud-provider-payment8001/8002,最后启动cloud-consumer-feign-order80启动,输入地址:

http://localhost/consumer/payment/feign/timeout

会有下面的错误界面:

image-20200820144238384

2、超时问题的解决

image-20200820143336511

​ 所以,我们需要在yml文件中开启超时的配置信息。因为OpenFeign默认支持Ribbon,如下图所示:

image-20200820144338334

​ 我们只需要在yml文件中添加如下的配置即可开启OpenFeign客户端超时控制:

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  #指的是建立连接后从服务器读取可用资源所用的时间
  ReadTimeout:  5000
  #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接时间
  ConnectTimeout: 5000

注:当我们只在cloud-provider-payment8001中添加方法时,而未在cloud-provider-payment8002中添加超时方式法,由于cloud-consumer-feign-order80会轮询的访问服务提供者,所以,在访问的过程中,有一次会出错。

4、日志打印

1、介绍

image-20200820144702027

日志级别:

image-20200820144732569

2、日志打印的配置

(1)目录结构

image-20200820144823293

(2)在com.xiaolun.config下配置日志bean

@Configuration
public class FeignConfig {
    
    

   @Bean
   Logger.Level feignLoggerLevel(){
    
    
      //代表自己开启的是一个详细日志
      return Logger.Level.FULL;
   }
}

(3)在yml文件中开启日志的Feign客户端

logging:
  level:
    #feign日志以debug级别监控下面这个接口,并打印出全部日志信息
    com.xiaolun.service.PaymentFeignService: debug

(4)后台日志查看

image-20200820145032605

猜你喜欢

转载自blog.csdn.net/weixin_43334389/article/details/114011017
今日推荐