微服务入门学习

1、学习路线

微服务基本概念,SpringCloud ,SpringCloud Alibaba ,RabbitMQ 消息队列,分布式事务解决方案

2、微服务

2.1 基本介绍

微服务是一种架构,这种架构是将单个的整体应用程序分割成更小的项目关联的独立的服务。一个服务通常实现一组独立的特性或功能,包含自己的业务逻辑和适配器。各个微服务之间的关联通过暴露api来实现。这些独立的微服务不需要部署在同一个虚拟机,同一个系统和同一个应用服务器中。

2.2 架构演变

架构的演变大致为:单一应用架构 ===> 垂直应用架构 ===> 分布式服务架构 ===> 流动计算架构微服务架构

2.2.1单体架构

将所有功能代码都部署在一起就可以,这样可以减少开发、部署和维护的成本
优点:

1.架构简单,容易上手
2.易于部署,可以实现快速维护、定位问题

缺点:

1.单点故障:有一个模块出现问题,可能会引发整个系统出现问题,无法单独对系统的某一个模块进行扩展,只能对整个系统进行水平扩展。无法单独定制实现弹性扩展。
2.因为All In One,整个项目的所有功能都部署在一台服务器上,无法承载高并发请求

2.2.2 垂直应用架构

就是将原来的一个应用拆成互不相干的几个应用,以提升效率。
单体应用拆分成多个应用,比如多个后台系统应用

优点:

系统拆分实现了流量分担,解决了并发问题,而且可以针对不同模块进行优化和水平扩展。
一个系统的问题不会影响到其他系统,提高容错率。

缺点:

系统之间相互独立, 无法进行相互调用。
系统之间相互独立, 会有重复的开发任务

2.2.3 分布式服务架构

垂直应用越来越多,重复的业务代码就会越来越多。这时候,我们就思考可不可以将重复的代码抽取出来,做成统一的业务层作为独立的服务,然后由前端控制层调用不同的业务层服务呢? 这就产生了新的分布式系统架构。它将把工程拆分成表现层和服务层两个部分,服务层中包含业务逻辑。表现层只需要处理和页面的交互,业务逻辑都是调用服务层的服务来实现。

优点:

抽取公共的功能为服务层,提高代码复用性。

缺点:

系统间耦合度变高,调用关系错综复杂,难以维护。

2.2.4 微服务架构
微服务架构在某种程度上是面向服务的架构,它更加强调服务的"彻底拆分"

特点:
1、为了满足高并发请求,对服务进行拆分,单独部署

2、服务独立、数据库独立、语言独立、团队独立

优势:
1、支持高并发场景

2、可以对某一个模块单独部署、运维、扩展等操作,而不影响其他业务。

缺点:

1、分布式系统开发的技术成本高(容错、分布式事务等)。
2、服务治理和服务监控关键。
3、多服务运维难度,随着服务的增加,运维的压力也在增大

微服务带来的难题:
这么多小服务,如何管理他们?
这么多小服务,他们之间如何通讯?
这么多小服务,客户端怎么访问他们?
这么多小服务,一旦出现问题了,应该如何自处理?
这么多小服务,一旦出现问题了,应该如何排错?

3、SpringCloud介绍

3.1 SpringCloud

Spring技术体系:
SpringFramework —> SpringBoot —> SpringCloud
微服务开发:
1、SpringCloud
2、SpringCloudAlibaba
3、ApacheDubbo 阿里开源的分布式RPC框架
4、其他自研微服务框架

3.2 SpringCloud 全家桶

SpringCloud

Eureka	注册中心
Gateway 网关
Openfeign 远程调用
Config  配置中心
Ribbon  负载均衡
Hystrix 熔断器

https://spring.io/projects/spring-cloud

3.2.1 SpringCloud – Eureka 注册中心

在这里插入图片描述

  • 0、实例化服务
  • 1、将服务注册到注册中心
  • 2、注册中心收录服务
  • 3、注册中心获取服务列表
  • user-service 127.0.0.1:9091
  • goods-service 127.0.0.1:9092
  • sso-service 127.0.0.1:9093
  • 4、基于负载均衡算法从地址列表选择一个服务地址进行服务调用
  • 5、定期发送心跳
  • 6、检查没有定期发送心跳的服务并在一定时间内剔除服务地址列表

通过服务中心来获取服务你不需要关注你调用的项目IP地址,由几台服务器组成,每次直接去服务中心获取可以使用的服务去调用既可。
作用:实现服务治理(服务注册与发现)
由两个组件组成:Eureka服务端和Eureka客户端。
Eureka服务端用作服务注册中心。支持集群部署。
Eureka客户端是一个java客户端,用来处理服务注册与发现。
在应用启动时,Eureka客户端向服务端注册自己的服务信息,同时将服务端的服务信息缓存到本地。客户端会和服务端周期性的进行心跳交互,以更新服务租约和服务信息。

1、Eureka是SpringCloud提供的注册中心组件!

注册中心: 提供服务的自动注册与服务自动发现!

Eureka使用层面来看,分为两块内容:

	Eureka服务端
	
		1、会开启一个定时任务,每60秒执行一次,超过90秒没有发送心跳的服务就会被从服务列表中剔除!
	
	Eureka客户端
	
		1、我们的微服务,作为Eureka的客户端,每30秒发送一次心跳检测,证明自己还活着,是一个健康示例

2、搭建Eureka服务端

2.1 创建eureka-server项目

2.2 依赖

	父项目:锁定springcloud版本  spring-cloud-dependencies
	
	            <!--锁定spring-cloud的版本-->
				<dependency>
					<groupId>org.springframework.cloud</groupId>
					<artifactId>spring-cloud-dependencies</artifactId>
					<version>Hoxton.SR9</version>
					<type>pom</type>
					<scope>import</scope>
				</dependency>

	eureka依赖:spring-cloud-starter-netflix-eureka-server
	
		        <!--引入Eureka服务端依赖-->
				<dependency>
					<groupId>org.springframework.cloud</groupId>
					<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
				</dependency>
				
				web启动器依赖
	
	
2.3 yml配置

	# 访问端口
	server:
	  port: 8761

	# 服务名称,一般和项目名称一样;注意:不要用下划线
	spring:
	  application:
		name: eureka-server

	# eureka 客户端配置
	eureka:
	  client:
		service-url:
		  defaultZone: http://localhost:8761/eureka
		# 不向注册中心注册自己,默认为true; 如果要搭建eureka集群,必须设置为true
		register-with-eureka: false
		#不从注册中心拉取服务
		fetch-registry: false

2.5 启动类

	// @EnableEurekaServer 开启Eureka服务端
	
	@SpringBootApplication
	@EnableEurekaServer
	
	public class EurekaApplication {  }

2.6 访问控制台

	http://localhost:8761/

3、Eureka服务端配置

3.1 客户端注册到Eureka服务端

	cinema-member-service 注册到Eureka
	
	A. 依赖
	
		    <!--Eureka客户端依赖包-->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
			</dependency>
	
	B. yml 配置
		eureka:
		  client:
			service-url:
			  defaultZone: http://localhost:8761/eureka
	C. 启动类
		
		/**
		 * Eureka客户端注解:
		 * 1、@EnableEurekaClient 只能开启Eureka的客户端
		 * 2、@EnableDiscoveryClient 开启服务自动发现客户端,支持:Eureka与Nacos
		 * 3、不写也可以,springboot2以后
		 */
		@SpringBootApplication
		@EnableDiscoveryClient
		public class MemberApplication { }

Eureka服务治理:服务自动注册与发现

		服务提供者或服务消费者一旦启动,会连上Eureka注册中心, 会向注册中心写入自身服务IP、端口、协议等信息;
		
		同时,也会从Eureka服务端拉取服务列表,缓存到本地,更方便服务之间的调用。
		
 Eureka服务心跳
	
		为了维护服务的可用,eureka客户端会每隔30秒发送一次心跳检测,证明自己活着;
		
		Eureka服务端,会通过一个定时任务,每60秒执行一次,检测超过90秒未发送心跳续约的服务,从服务列表中移除。
		
		这样,可能会导致,有些服务由于网络原因未把心跳请求送达到eureka服务端,但是服务本身是正常的,导致被意外剔除!
		造成服务不可用!Eureka通过自我保护机制解决这个问题。
		
 Eureka自我保护机制
		
		统计最后一分钟实际收到的心跳续约数,如果小于心跳续约阈值,就开启自我保护!
		
		心跳续约阈值? 总心跳数 * 0.85
		
		开启自我保护,
			
			1. Eureka不会再剔除没有发送心跳续约的服务示例;
			2.Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。
			3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。
			4. 当网络稳定后,eureka服务端收到客户端发送的心跳续约满足关闭条件,自我保护就关闭。
		
		
		自我保护?目的是为了保证服务的可用

4、Eureka集群

4.1 注册中心需要配置集群吗? 生产环境下,必须配置。否则单台注册中心出问题,整个微服务架构不可用。


4.2 如何搭建注册中心集群?

	本地模拟:
		
		动态端口的方式:
			
			A. 配置中:
				eureka:
				  client:
					service-url:
					  defaultZone: ${defaultZone111:http://localhost:8762/eureka}
			
			B. 运行时期,指定VM Options 参数
			
				-Dport=8762 -DdefaultZone111=http://localhost:8761/eureka

		Eureka客户端:
			eureka:
			  client:
				service-url:
				  defaultZone: http://localhost:8761/eureka,http://localhost:8762/eureka


4.3 Eureka之间服务实例,如何同步?

	1、请求转发:cinema-member-service服务注册到某一个节点后,该节点会把注册请求转发到集群中的其他节点,从而实现服务同步。
	这样只要客户端需要用到服务,拉取任意节点的服务列表就可以获取服务的完整信息。

	2、若转发注册请求失败,会转发心跳请求。eureka1转发注册请求到eureka2失败,就会在eureka1发送心跳请求时候转发到eureka2,eureka2发现在自己的服务缓存中不存在就会对该服务进行注册。

	3、转发心跳请求失败,eureka内部会维护一个批处理流,保存转发失败的请求,每隔1秒重试,宕机的节点恢复后就可以收到服务注册请求,保证数据的可用性。

	4、通过设置fetch-registry 和 register-with-eureka, 主动拉取方式

3.2.2 springCloud – Ribbon 负载均衡

场景: 服务提供者有多个,在客户端这里需要进行负载均衡(Load Balance)

1 服务端负载均衡

	A. LB 把请求通过负载均衡策略分摊到不同的处理单元上; 前提:集群环境
	
	B. Nginx就是服务端负载均衡
	
		说明:
			1、nginx负载均衡,单独的服务器,建立在客户端与服务端之间的一个web服务器
			2、客户端发出请求,首先经过的就是nginx服务器,通过nginx进行负载均衡,找到具体处理请求的服务器
			3、服务端与nginx之间通过心跳维持可用关系,如果服务端未发送心跳请求到nginx就会从可用服务中剔除

2 客户端负载均衡

	特点:
		1、通过代码实现,客户端调用服务端时候,需要获取可用服务列表清单,再通过负载均衡算法选择一个可用服务
		
		2、要借助于注册中心实现,因为要通过注册中心获取服务列表 (eureka已经提供负载均衡的能力,内置了ribbon)
		
			通过Ribbon实现,eureka集成了ribbon的包
		
		3、不需要单独搭建负载均衡服务器

对于nginx服务器,所有请求到达nginx服务器后,由nginx服务器进行请求路由的分发,实现负载均衡。

对于Ribbon,是由客户端主动拉取注册中心的服务列表,然后通过负载均衡算法选取一个可用服务实例(其中通过自旋锁的cas来保证服务不被多个线程重复获取),整个过程是发生在客户端服务的

为什么说Nginx是服务端的负载均衡,Ribbon是客户端的负载均衡呢?

(1)用户发送请求到nginx,nginx是服务端。

(2)Ribbon是微服务之间通信的负载均衡,订单服务调用商品服务时,订单服务就是客户端,商品服务就是服务端

3、Ribbon负载均衡应用

3.1 依赖

	不需要添加:
	
		spring-cloud-starter-netflix-eureka-client 注册中心已经集成了
		
		spring-cloud-starter-netflix-ribbon 依赖包
		
3.2 @LoadBalanced 注解

    @Bean
	@LoadBalanced
	public RestTemplate restTemplate(){
		return new RestTemplate();
	}
	
3.3 通过restTemplate,远程调用通过服务名完成

	@GetMapping("/{memberId}")
	public String findMemberById(@PathVariable("memberId") String memberId) {
	
		String url = "http://cinema-member-service/member/" + memberId;
		
		return restTemplate.getForObject(url, String.class);
		
	}
			
3.4 现在已经实现了负载均衡,默认的策略是轮询

	RandomRule
	RoundRobinRule
	RetryRule

3.5 修改负载均衡策略

	局部:针对某一个服务有效
	
		cinema-member-service: # 服务名称
		  ribbon:
			NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
	
	全局:针对所有服务有效
	
		// 负载均衡全局配置, 所有的服务都使用RandomRule随机
		@Bean
		public IRule rules(){
			return new RandomRule();
		}

4、Ribbon负载均衡实现原理

4.1 通过RestTemplate上添加@LoadBalanced注解实现了客户端负载均衡。实现原理?

4.2 原理:SpringBoot自动配置(LoadBalancerAutoConfiguration)  +   LoadBalancedInterceptor


4.3 分析

	A. spring-cound-commons包的META-INF/spring.factories
	
		查看自动配置类:LoadBalancerAutoConfiguration
		
			1、创建LoadBalancerInterceptor, 负载均衡拦截器对象
			
			2、把LoadBalancerInterceptor添加到 List<ClientHttpRequestInterceptor> 拦截器的集合中
			
			3、最后把拦截器集合设置到restTemplate中。这样确保restTemplate执行时候会执行拦截器
			
	B. LoadBalancerInterceptor 负载均衡拦截器
	
		1、客户端通过restTemplate发送请求时候,会执行拦截器
		
		2、在LoadBalancerInterceptor拦截器中,获取负载聚合策略
		
			ILoadBalancer loadBalancer = this.getLoadBalancer(serviceId);
			
		3、再从可用服务列表中,选择一个可用服务处理请求
		
			Server server = this.getServer(loadBalancer, hint);
			
		4、最终就可用根据负载均衡设置,选择可用服务,处理请求

3.2.3 SpringCloud – Openfeign 远程调用

https://blog.csdn.net/weixin_43888891/article/details/126171740
1、Openfeign

1.1 SpringCloud提供的声明式远程调用的方式

1.2 Openfegin 实现原理:动态代理.

2、如何使用?
远程调用接口当中,一般我们称提供接口的服务为提供者,而调用接口的服务为消费者。而OpenFeign一定是用在消费者上

2.1 依赖

	spring-cloud-starter-openfeign
	
2.2 开启feign注解支持

	@SpringBootApplication
	// 开启feign的客户端支持,实现远程调用
	@EnableFeignClients
	public class PortalApplication {  }
	

2.3 定义feign接口: 从服务提供者拷贝其控制器方法

	@FeignClient(value = "cinema-member-service")  // value指定服务名称
	public interface MemberFeignClient {

		/**
		 * 远程调用的接口名称,要与服务提供者接口名称、参数类型与值保持一致。
		 * 注意:路径要完整
		 */
		@GetMapping("/member/{id}")
		String findOne(@PathVariable("id") String id);
	}
		

2.4 远程调用,直接通过@Autowired注入MemberFeignClient对象即可

	@RestController
	@RequestMapping("fegin")
	@Slf4j
	public class PortalOpenFeginController {

		// 注入feign的客户端对象,代理对象
		@Autowired
		private MemberFeignClient memberFeignClient;

		@GetMapping("{id}")
		public String findMemberByfeign(@PathVariable("id")String id){
			log.info("通过feign远程调用,参数:{}",id);
			String result = memberFeignClient.findOne(id);
			return result;
		}
	}

3、openfeign集成ribbon

默认在openfeign的依赖中已经集成了ribbon,我们可用直接使用。

局部配置:

	cinema-member-service: # 服务名称
	  ribbon:
		NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

全局配置:

	// 负载均衡全局配置, 所有的服务都使用RandomRule随机
	@Bean
	public IRule rules(){
		return new RoundRobinRule();
	}

feign的其他功能
4、feign日志集成

4.1 配置feign日志级别

    // feign日志输出级别
	@Bean
	public Logger.Level loggerLevel(){
		return Logger.Level.FULL;
	}

4.2 日志配置
	logging:
	  level:
		com.wnxy: debug
		
4.3 结果:查看feign远程调用过程日志

	---> GET http://cinema-member-service/member/100 HTTP/1.1   【请求头】
	
	<--- HTTP/1.1 200 (407ms)				【响应信息】
	connection: keep-alive
	content-length: 12
	content-type: text/plain;charset=UTF-8
	date: Tue, 28 Jun 2022 09:33:17 GMT
	keep-alive: timeout=60
	会员信息
	<--- END HTTP (12-byte body)

5、feign配置

需求: 模拟一个超时方法,远程调用该超时方法,看看会发生什么

5.1 服务提供者,添加一个休眠

	...
	public class MemberController {

		@GetMapping("/{id}")
		public String findOne(@PathVariable("id") String id) {
			log.info("根据会员ID查询,会员ID:{}",id);
			try {
				TimeUnit.SECONDS.sleep(2);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return "会员信息";
		}
	}

5.2 远程调用,报错:java.net.SocketTimeoutException: Read timed out

5.3 服务消费者,客户端配置超时时间

	feign:
	  client:
		config:
		  default:
			# 连接超时
			connectTimeout: 1000
			# 业务处理超时
			readTimeout: 3000
			
	测试1:配置超时时间3秒后,没有报错!
	测试2:readTimeout: 3000 改为 2000 后,在访问就报错,超时!
	测试3:此时,超时,我想要自己配置重试次数
	
	    // feign 超时重试
		@Bean
		public Retryer feignRetryer() {
			// 默认尝试5次
			return new Retryer.Default();
		}

作业:
一、面试题
1、Ribbon是什么?
ribbon是springclould 一个组件,提供负载均衡的功能,客户端调用服务端时候,获取服务列表清单,然后通过负载均衡算法选择一个可用服务处理请求
2、客户端负载均衡与服务端负载均衡区别?
服务端负载均衡一般指的是 nginx 负载均衡,客户端发送请求,首先会经过nginx服务器,,通过nginx 负载均衡,找到具体处理请求的、的服务器
客户端负载均衡:一般指的是ribbon 负载均衡,客户端在调用服务端的时候,获取服务列表,然后通过负载
3、服务之间,如何进行远程调用?

3.2.4 springcCloud – hystrix 熔断器

1、分布式系统遇到的问题

1.1 服务之间的调用错综复杂,当某一个服务出现问题,整个调用链都会收到影响

	ServiceA----->ServiceB----->ServiceC----->ServiceD (出问题?)
	
1.2 某个服务调用时间过长,或者出现错误,引起整个微服务架构出现故障,设置导致系统崩溃,这种现象叫做雪崩!

1.3 为了避免服务的雪崩,对服务进行隔离或管理 (降级:快速返回错误信息)

1.4 通过hystrix可以对服务进行降级、熔断、还可以对服务进行实时的监控,服务限流,从而保证整个微服务系统的健壮

2、Hystrix实现服务降级

2.1 服务降级

	当服务调用出现错误、超时,快速返回失败信息,这个就是服务降级!

2.2 如何实现?

	第一步:依赖
	
		spring-cloud-starter-netflix-hystrix
		
	第二步:开启熔断降级注解
	
		@SpringBootApplication
		@EnableFeignClients
		@EnableCircuitBreaker
		public class PortalApplication { }
		
		或者
		@SpringCloudApplication
		@EnableFeignClients
		public class PortalApplication { }
		
		原理:
		
		@SpringBootApplication
		@EnableDiscoveryClient
		@EnableCircuitBreaker
		public @interface SpringCloudApplication {
		
	第三步:编写降级方法
	
		@RestController
		@RequestMapping("fegin")
		@Slf4j
		@DefaultProperties(defaultFallback = "errorFallback")  		// --> 指定服务降级的默认方法
		public class PortalOpenFeginController {

			// 注入feign的客户端对象,代理对象
			@Autowired
			private MemberFeignClient memberFeignClient;

			@GetMapping("{id}")
			@HystrixCommand										    // ---> 需要降级的方法
			public String findMemberByfeign(@PathVariable("id")String id){
				log.info("通过feign远程调用,参数:{}",id);
				String result = memberFeignClient.findOne(id);
				return result;
			}

			// 降级方法
			public String errorFallback(){						   // ---> 自定义方法
				return "服务降级,服务调用超时、异常!";
			}
		}
		
		
		局部降级方法:针对某一个控制器单独编写降级方法
		
		    @GetMapping("{id}")
			@HystrixCommand(defaultFallback = "errorFallback2")	  // 针对当前控制器方法单独编写的降级方法
			public String findMemberByfeign(@PathVariable("id")String id){
				log.info("通过feign远程调用,参数:{}",id);
				String result = memberFeignClient.findOne(id);
				return result;
			}

			public String errorFallback2(){
				return "服务降级,局部,针对某一个方法";
			}
				
	第四步:feign集成hystrix
	
		feign:
		  hystrix:
		     enable: true
		
		
		
2.3 对feign接口编写降级方法

	上面的服务降级方法与业务代码耦合,非常不友好。可以对fegin接口的每一个方法都对应降级处理操作。
	
	实现步骤:
	
	第一:编写降级类, 实现feign接口
	
		// 针对feign接口编写的降级类
		@Component
		public class MemberFeignClientCallback implements MemberFeignClient {
			@Override
			public String findOne(String id) {
				return "根据会员id查询,出现未知错误!";
			}
		}
		
	第二:修改feign接口
	
		@FeignClient(
				value = "cinema-member-service",
				fallback = MemberFeignClientFallback.class
		)
		public interface MemberFeignClient {
		
		
	第三:删除@HystrixCommand、@DefaultProperties 注解以及对应的降级方法

3、服务熔断

3.1 什么时服务熔断?

	服务熔断一般是指软件系统中,由于某些原因使得服务出现了过载现象,为防止造成整个系统故障,
	
	从而采用的一种保护措施,所以很多地方把熔断亦称为过载保护。
	
	如果访问某个服务总是出现错误,会对接口做降级处理,老是出现错误达到一定的条件就进行熔断!
	一旦进入熔断状态,即使正常的请求,也会直接返回错误信息。
	
3.2 熔断的三个状态

	关闭状态 Closed
	
		默认,所有的请求都可以正常访问服务,熔断器默认是关闭的。		
	
	打开状态 Open
	
		在时间窗口内,默认是10秒,有50%的请求都出现异常,熔断器(断路器)就会打开
		
		一旦熔断器处于打开状态,所有正常的请求也会直接返回降级方法。
	
	半开状态 Half Open
	
		熔断器不能一直处于打开状态,这样的话正常的请求也访问不了了;
		
		所以熔断器打开后,5秒就进入半开状态,半开状态就会尝试关闭熔断器;
		
		什么时候关闭? 当有正常的请求访问接口,就关闭熔断器。
		
		当请求继续失败,熔断器就一直处理半开状态。
	
	
3.3 熔断测试	
		
		
	@GetMapping("{id}")
	@HystrixCommand(fallbackMethod = "errorFallback",commandProperties = {
			// 是否开启断路器
			@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED,value = "true"),
			// 请求错误率大于 50% 就启动熔断器
			@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value = "50"),
			// 默认10秒内访问接口失败达到20次,打开断路器,触发熔断; 为了方便测试,这里修改10秒内错误达到10次触发熔断。
			@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "10"),
			//断路多久以后开始尝试是否恢复,默认5s
			@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,value = "10000")
	})
	public String findMemberByfeign(@PathVariable("id")Integer id){
		log.info("通过feign远程调用,参数:{}",id);
		if (id<=0) {
			throw new RuntimeException("参数错误!");
		}
//        String result = memberFeignClient.findOne(id);
//        return result;
		return "success";
	}

	// 默认降级方法,返回string
	public String errorFallback(@PathVariable("id")Integer id){
		return "控制器接口的熔断降级方法!";
	}

4、服务监控

通过Hystrix Dashboard 实现对微服务接口调用情况的监控。

步骤:

	1、搭建监控中心微服务项目:hystrix-dashboard
	
	2、配置要监听的微服务
	
	3、访问监控中心
	
		http://localhost:9002/hystrix
		
		访问后,配置要监控的微服务地址:http://localhost:8000/hystrix.stream
	
步骤实现:

	1、搭建监控中心微服务项目:hystrix-dashboard
	
		第一:依赖
		
		        <!--配置hystrix dashboard-->
				<dependency>
					<groupId>org.springframework.cloud</groupId>
					<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
				</dependency>
				
		第二:yml 配置
		
					server:
					  port: 9002
					hystrix:
					  dashboard:
						proxy-stream-allow-list: "*"
		第三:启动类
		
					@SpringBootApplication
					@EnableHystrixDashboard
					public class HystrixApplication {
						public static void main(String[] args) {
							SpringApplication.run(HystrixApplication.class, args);
						}
					}
		
		
	
	2、配置要监听的微服务
	
		cinema-portal-service (端口8000)
		
			第一:依赖
			        <!--hystrix监控-->
					<dependency>
						<groupId>com.netflix.hystrix</groupId>
						<artifactId>hystrix-metrics-event-stream</artifactId>
					</dependency>
			第二:配置bean
			
					 /**
					 *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
					 *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
					 *只要在自己的项目里配置上下面的servlet就可以了
					 */
					@Bean
					public ServletRegistrationBean getServlet() {
						HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
						ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
						registrationBean.setLoadOnStartup(1);
						registrationBean.addUrlMappings("/hystrix.stream");
						registrationBean.setName("HystrixMetricsStreamServlet");
						return registrationBean;
					}
	
	
	3、访问监控中心
	
		http://localhost:9002/hystrix
		
		访问后,配置要监控的微服务地址:http://localhost:8000/hystrix.stream	

面试题:

一、熔断与降级区别?

1、先进行服务降级:当访问接口出现异常、超时、线程池已满,就走降级方法

2、当服务降级达到一定的条件,比如:时间窗口内失败比率达到50%就进行服务熔断

3、再熔断状态下,所有的请求都会被降级

4、熔断打开5秒后,就进入半开状态,会尝试关闭熔断器; 当有正常请求访问就关闭熔断器,否则,一直处理半开状态

二、Hystrix是什么?包含哪些功能?

Hystrix是熔断器,提供了熔断、降级、服务监听等一些列功能。


特性:

	1、服务降级
	
	2、服务熔断
	
	3、线程隔离
	
		hystrix通过对每一个接口分配线程池,实现接口之间的隔离
		
	4、请求缓存

		会对调用结果进行缓存,后续的请求会走缓存,提高效率
		
		举例:查询id=100的数据,把查询结果放入缓存中后续的查询会直接从缓存中获取。自带内存缓存。
		
	5、请求合并
	
		是指短时间内多个请求合并为一个请求,节省资源,降低服务的负载。

3.2.5 springcCloud – Gateway 网关

1、分布式系统遇到的问题

1.1 随着业务越来越复杂,微服务也越来越多

	前端要调用后端接口,需要访问这些微服务,需要记住这些微服务的地址,比较繁琐
	
1.2 每隔微服务都要做安全认证,涉及大量的重复操作,不利于代码维护。

1.3 上述问题,都可以通过Gateway网关解决!

2、Gateway 网关

2.1 介绍

	什么是Gateway?
		
		A. 网关是建立在客户端与业务微服务之间的一个微服务,我们可以在网关中完成:
		
			统一鉴权、请求路由、限流等一系列功能
			
		B. 网关是作为微服务的统一访问入口
		
		C. 我们要访问微服务,首先要先通过网关,再在网关中对请求进行断言(predicate)判断,
		
		   根据断言结果把请求路由(转发)到不同的微服务

网关作用:负载均衡ribbon,熔断降级hystrix,限流(基于redis实现),断言,过滤器,跨域

	网关解决方案?
	
		zuul  一代网关
		
		Gateway 基于springboot2 + reactor构建
		
		Nginx + Lua 
		
		Kong
		
	
	网关高可用?
	
		因为网关是微服务统一入口,所以必须要保证网关的高可用。
		
		一旦搭建网关集群,这里就需要引入Nginx作为负载均衡服务器。
		
		请求流转:
		
			客户端---> Nginx ----> Gateway ----> 微服务

2.2 核心概念

	(1)Route(路由):
		
		路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

	(2)Predicate(断言):
	
		路由断言,判断请求是否符合要求,符合则转发到路由目的地。

	(3)Filter(过滤器):
		
		指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前后对请求进行修改。

3、Route Predicate 路由断言

3.1 Path Route Predicate:发送指定路径的请求会匹配该路由

	server:
	  port: 10000  # 不要用6000
	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-service
			  uri: http://localhost:9000
			  predicates:
				- Path=/member/**
				
	
	A. 先访问微服务,确保微服务OK: http://localhost:9000/member/100
	B. 再通过网关访问微服务: http://localhost:10000/member/100
	   路径匹配:
		1、判断判断,符合/member/**要求
		2、找到微服务:http://localhost:9000
		3、匹配微服务地址:
		   http://localhost:9000/member/100
	   

	路由:是由一组断言工厂组成,刚才用的是PathRoutePredicateFactory这个断言工厂
	
		|-- RoutePredicateFactory
		
			|-- PathRoutePredicateFactory
		
		
3.2 Query Route Predicate:带指定查询参数的请求可以匹配该路由

	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-service
			  uri: http://localhost:9000
			  predicates:
				- Query=name
	
	查询必须要带上参数:name
	
	举例: http://localhost:10000/member/100
	
	断言工厂: QueryRoutePredicateFactory
		
		
3.3 After Route Predicate:在指定时间之后的请求会匹配该路由

	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-service
			  uri: http://localhost:9000
			  predicates:
				- After=2022-06-30T14:15:00+08:00[Asia/Shanghai]
	
	
	 - After: 在指定的时间之后,才可以访问微服务。
	
	 - Before: 之前
	
	 - Between=2022-03-24T16:30:00+08:00[Asia/Shanghai], 2022-03-24T16:30:00+08:00[Asia/Shanghai]


3.4 Method Route Predicate:路由匹配指定的请求方式

	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-service
			  uri: http://localhost:9000
			  predicates:
				- Method=post

	必须post请求才可以通过网关路由到微服务。
	
	
3.5 Weight Route Predicate:使用权重来路由相应请求,以下表示有80%的请求会被路由到localhost:9000,20%会被路由到localhost:8999
	
	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-high
			  uri: http://localhost:8999
			  predicates:
				- Weight=group1,8
			- id: api-member-low
			  uri: http://localhost:9000
			  predicates:
				- Weight=group1,2


	带权重的断言
	
	
小结:

	断言作用: 对访问网关的请求url地址进行断言判断,如果符合断言要求, 才会对请求地址进行路由,路由到对应的微服务!

4、动态路由:微服务的负载均衡配置
https://zhuanlan.zhihu.com/p/681456240

spring:
  application:
	name: gateway
  cloud:
	gateway:
	  routes:
		- id: api-member-high
		  uri: lb://cinema-member-service
		  predicates:
			- Path=/member/**
		
			
说明:
	lb://cinema-member-service  lb表示负载均衡配置;后面的是服务名称
	
默认负载均衡策略是轮询,如果要改为随机,可以这样:

	cinema-member-service:
	  ribbon:
		NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

原理:

	Eureka客户端集成了Ribbon;
	
	而网关集成了Eureka,所以网关中可以直接使用Ribbon!

5、网关中配置过滤器

5.1 StripPrefix GatewayFilter:对指定数量的路径前缀进行去除的过滤器  【GatewayFilterFactory】

	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-high
			  uri: lb://cinema-member-service
			  predicates:
				- Path=/member/**
			  filters:
				- StripPrefix=1


	StripPrefix=1 对访问路径表示去除一位前缀。
	
	访问路径:
	
		举例1: http://localhost:10000/member/100 --> 去除一位前缀 http://localhost:10000/100 
	
		举例2: http://localhost:10000/api/member/100  直接就不符合断言规则。
		
		举例3: http://localhost:10000/member/member/100   符合断言规则; 再去除1位前缀;  最终可以访问。
	

	重新配置测试:
	
		spring:
		  application:
			name: gateway
		  cloud:
			gateway:
			  routes:
				- id: api-member-high
				  uri: lb://cinema-member-service
				  predicates:
					- Path=/member-service/**
				  filters:
					- StripPrefix=1

		访问地址:
		
			http://localhost:10000/member-service/member/100
			
				1、先进行断言判断: 符合
				
				2、再执行过滤器,去除一个前缀,地址为:
				
					http://localhost:10000/member/100
				
				3、再路由到微服务
					
					http://localhost:9000/member/100
					


5.2 PrefixPath GatewayFilter:与StripPrefix过滤器恰好相反,会对原有路径进行增加操作的过滤器

	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-high
			  uri: lb://cinema-member-service
			  predicates:
				- Method=get
			  filters:
				- PrefixPath=/member


	- PrefixPath=/member 对请求添加一个路径前缀/member
	
	地址1:http://localhost:10000/member/100 -->添加前缀后http://localhost:10000/member/member/100
	
	
	地址2:http://localhost:10000/100 -->添加前缀后http://localhost:10000/member/100

6、Gateway网关集成Hystrix降级熔断

第一步:添加Hystrix依赖

	<!--Gateway集成Hystrix-->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
	</dependency>

第二步:编写降级类

	@RestController
	public class FallbackController {

		@GetMapping("/fallback")
		public Map<String,Object> fallback(){
			Map<String,Object> map = new HashMap<>();
			map.put("code",500);
			map.put("message","服务不可用");
			return map;
		}
	}

第三步:yml配置,集成hystrix

	spring:
	  application:
		name: gateway
	  cloud:
		gateway:
		  routes:
			- id: api-member-high
			  uri: lb://cinema-member-service
			  predicates:
				- Path=/member-service/**
			  filters:
				- StripPrefix=1
				- name: Hystrix
				  args:
					name: fallbackcmd
					fallbackUri: forward:/fallback


第四步:停掉一台服务,测试。浏览器会返回降级信息。

第五步:超时降级配置

	全局配置:
	
		spring:
		  application:
			name: gateway
		  cloud:
			gateway:
			  routes:
				- id: api-member-high
				  uri: lb://cinema-member-service
				  predicates:
					- Path=/member-service/**
				  filters:
					- StripPrefix=1
					- name: Hystrix
					  args:
						name: fallbackcmd
						fallbackUri: forward:/fallback
			  httpclient:
				connect-timeout: 1000    # 建立连接的超时时间
				response-timeout: 5000   # 响应的超时时间(处理业务的超时时间)			
		hystrix:
		  command:
			default:
			  execution:
				isolation:
				  thread:
					timeoutInMilliseconds: 5000  # hystrix线程隔离超时时间,默认是1秒



		测试逻辑: 
			cinema-member-service微服务接口中休眠2秒,不配置超时,默认会返回降级信息; 
		
			配置完超时时间为两个5秒后,就不会再降级了。


	局部配置:
		spring:
		  application:
			name: gateway
		  cloud:
			gateway:
			  routes:
				- id: api-member-high
				  uri: lb://cinema-member-service
				  predicates:
					- Path=/member-service/**
				  filters:
					- StripPrefix=1
					- name: Hystrix
					  args:
						name: fallbackcmd
						fallbackUri: forward:/fallback
					  metadata:
						connection-timeout: 1000     # 局部配置,针对当前路由有效  (当前版本测试未生效!)
						response-timeout: 4000

	
	在gateway中配置服务的超时时间,推荐采用: 【全局配置】

7、Gateway 限流

7.1 介绍

	基于Redis实现的限流。
	
	原理:令牌桶算法。 以固定的频率生产令牌放入令牌桶中,桶的容量大小决定并发能力。由请求过来时候就从令牌桶中
	
	获取令牌,获取不到拒绝访问。获取到令牌才可以访问处理业务。
	

7.2 实现

	第一步:添加Redis依赖
	
	        <!--限流-->
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
			</dependency>
	
	第二步:限流策略:根据ip限流
							
		@Configuration
		public class RatelimitConfig {
			/**
			 * 根据IP限流,即以每秒内请求数按IP分组统计,超出限流的url请求都将返回429状态
			 */
			@Bean
			public KeyResolver ipKeyResolver(){
			   return new KeyResolver() {
				   @Override
				   public Mono<String> resolve(ServerWebExchange exchange) {
					   //获取请求的IP地址
					   String hostName = exchange.getRequest().getRemoteAddress().getHostName();
					   //创建Mono发布者对象,发布数据源
					   return Mono.just(hostName);
				   }
			   };
			}
		}


	第三步:配置限流过滤器
		spring:
		  application:
			name: gateway
		  redis:
			host: localhost
			port: 6379
		  cloud:
			gateway:
			  routes:
				- id: api-member-high
				  uri: lb://cinema-member-service
				  predicates:
					- Path=/member-service/**
				  filters:
					- StripPrefix=1
					- name: Hystrix
					  args:
						name: fallbackcmd
						fallbackUri: forward:/fallback
						
					- name: RequestRateLimiter #限流过滤器
					  args:
						#每秒补充1个,令牌桶每秒填充平均速率, 允许用户每秒处理多少个请求。
						redis-rate-limiter.replenishRate: 1
						#令牌桶总容量,每秒最大处理的请求数量
						redis-rate-limiter.burstCapacity: 3
						#限流策略,通过SpEL从容器中获取对象
						key-resolver: "#{@ipKeyResolver}"

	第四步:启动Redis (我上课用的是windows版本)
	
	
	第五步:如何测试? 
	
		Jmeter 并发测试工具.
		
		使用:
		
			测试计划右键--->添加--->线程--->线程组
			
			选中【线程组】--> 【添加】--> 【取样器】--->【http请求】
		
		
			选中【http请求】 ---> 【添加】---> 【监听器】-->【查看结果树】
			
			
			最后:输入请求地址!
			
		
		并发测试5个请求,因为桶的容量是3,所以有2个请求返回429,表示请求过多,拒绝!

八、重试过滤器使用

spring:
  cloud:
	gateway:
	  routes:
		- id: api-member-high
		  uri: lb://cinema-member-service
		  predicates:
			- Path=/member-service/**
		  filters:
			- StripPrefix=1
			- name: Hystrix
			  args:
				name: fallbackcmd
				fallbackUri: forward:/fallback
			- name: RequestRateLimiter #限流过滤器
			  args:
				#每秒补充1个,令牌桶每秒填充平均速率, 允许用户每秒处理多少个请求。
				redis-rate-limiter.replenishRate: 1
				#令牌桶总容量,每秒最大处理的请求数量
				redis-rate-limiter.burstCapacity: 3
				#限流策略,通过SpEL从容器中获取对象
				key-resolver: "#{@ipKeyResolver}"
			- name: Retry
			  args:
				retries: 1   # 重试次数
				series:
				  - SERVER_ERROR #返回哪个状态码需要进行重试,这里表示返回状态码为5XX进行重试


Retry 重试过滤器:可以对指定的响应状态码进行重试。一般状态码都是错误状态码或自定义的状态码。

SERVER_ERROR 对应 HttpStatus中的枚举对象

九、网关跨域

@Configuration
public class CorsFilter {
	// 跨域:协议、主机、端口三者有一个不一样,就产生跨域。
	@Bean
	public CorsWebFilter corsFilter() {
		CorsConfiguration config = new CorsConfiguration();
		config.addAllowedMethod("*");
		config.addAllowedOrigin("*");
		config.addAllowedHeader("*");
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
		source.registerCorsConfiguration("/**", config);
		return new CorsWebFilter(source);
	}
}

Nginx与API gateway网关
本质上API网关也是做了请求的转发,那既然Nginx也可以做请求转发,那这两者有什么区别
在这里插入图片描述
在具体架构设计时Nginx做负载均衡时,考虑到API网关在系统中不止一个(以集群的方式做高可用),通常可以将Nginx至于API网关前,负责对API网关的负载均衡,然后再由网关决定进入根据判定到哪个真实的web 服务器。 让两者的分工更加明确,也就是:API网关聚合服务,Nginx请求转发

业务网关(gateway):对于具体的后端业务应用或者是服务和业务有一定关联性的策略网关。业务网关针对具体的业务需要提供特定的流控策略、缓存策略、鉴权认证策略

流量网关(Nginx):与业务网关相反,定义全局性的、跟具体的后端业务应用和服务完全无关的策略网关。流量网关通常只专注于全局的Api管理策略,比如全局流量监控、日志记录、全局限流、黑白名单控制、接入请求到业务系统的负载均衡等

业务网关一般部署在流量网关之后、业务系统之前,比流量网关更靠近业务系统。通常API网指的是业务网关。 有时候我们也会模糊流量网关和业务网关,让一个网关承担所有的工作,所以这两者之间并没有严格的界线。

3.2.6 springcCloud – Config 配置中心

1、微服务架构中,配置如何管理?

1.1 目前

	每个微服务,单独管理自己的配置文件!
	
	application.yml 或 application.properties 文件存储配置!
	
1.2 问题

	维护困难:后台对配置文件进行维护,变得很困难! (100个微服务)
	
	安全性差:配置信息与代码一起保存在同一个项目中,一旦泄露风险大
	
	局限性:配置的动态维护无法实现!
	
1.3 解决

	引入统一的配置中心,解决上述问题!
	
	市面上常见:
	
		A. SpringCloud Alibaba Nacos 作为配置中心(或者注册中心)
		
		B. SpringCloud Config 配置中心 【要学习】
		
		C. 百度 disconf
		
		D. 携程 Appollo

2、SpringCloud Config 组成

两部分

	* Config 配置中心服务端
	
		需要单独去搭建配置中心服务端
		
		主要用来连接远程仓库,获取配置信息,再把获取的配置信息返回给对应的微服务
		
	* Config 客户端
	
		连上配置中心服务端
		
		自动从配置中心服务端获取配置信息,配置中心服务端再从远程仓库获取配置

3、搭建配置中心服务端

3.1 目标

	搭建项目config-server, 作为配置中心服务端,能够连上git
	
3.2 准备git仓库

	登陆gitee.com,新建一个仓库,记住仓库地址、登陆gitee的账号和密码
	
3.3 动手搭建配置中心服务端

	第一:依赖
		    <dependencies>
				<dependency>
					<groupId>org.springframework.cloud</groupId>
					<artifactId>spring-cloud-config-server</artifactId>
				</dependency>
				<dependency>
					<groupId>org.springframework.cloud</groupId>
					<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
				</dependency>
			</dependencies>
	
	第二:启动类
	
		@SpringBootApplication
		@EnableConfigServer
		@EnableDiscoveryClient
		public class ConfigServerApplication { }
	
	第三:yml配置
	
		server:
		  port: 8000
		spring:
		  application:
			name: config-server
		  cloud:
			config:
			  server:
				git:
				  uri: https://gitee.com/yuanjie8080/cinema-mico-config.git
				  username: yuanjie8080
				  password: WONIU8080
		eureka:
		  client:
			service-url:
			  defaultZone: http://jet:123@localhost:8761/eureka
	
	第四:gitee上创建配置文件cinema-member-service-dev.yml, 并拷贝微服务中配置信息到gitee上
	
	第五:http://localhost:8000/cinema-member-service-dev.yml 
	
		确保: config-server 配置中心服务端 ----> 连上gitee

4、cinema-member-service 配置中心客户端

4.0 配置中心客户端依赖

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

4.1 删除原来的application.yml, 因为这里的配置信息已经拷贝到gitee上了

4.2 新建【bootstrap.yml】

	spring:
	  cloud:
		config:
		  name: cinema-member-service	  # 对应的是微服务名称,gitee上的文件名称的一部分
		  profile: dev					  # 激活的配置,与上面的name拼接共同构造了完整的配置文件名
		  label: master					  # git 上的分支名称
		  uri: http://localhost:8000/     # 配置中心服务端地址,就是config-server地址

4.3 启动,查看日志

	... Fetching config from server at : http://localhost:8000/
	
	表示连接配置中心8000,从其上获取配置信息
	
	最后,访问cinema-member-service,进行测试:
	
		http://localhost:9000/member/100

5、配置动态刷新

5.1 目标: 改了配置文件,不需要重启。 但是要发送一个post请求实现配置的动态更新。

5.2 步骤

	第一:引入依赖
	
		<!--配置动态刷新,引入actuator-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		
	第二:yml配置动态刷新
	
		management:
		  endpoints:
			web:
			  exposure:
				include: 'refresh'

	第三:在希望动态刷新配置的控制器上,使用注解@RefreshScope
	
		@RestController
		@RequestMapping("refresh")
		@RefreshScope
		public class RefreshController {

			@Value("${title}")
			private String title;

			@GetMapping("/test")
			public String test() {
				return title;
			}
		}
		
	第四步:重新后。修改git上的配置信息,发现并没有动态刷新。
	
		最后,还需要手动发送一个post请求:http://localhost:9000/actuator/refresh
		
		访问的是配置中心客户端(cinema-member-service),此时会通知配置中心服务端重新去git上拉取最新的配置返回。

6、配置中心重试机制

6.1 为什么要使用重试?

	cinema-member-service   ------->    config-server
	  
	  配置中心客户端         连接?       配置中心服务端
	  
	
	配置中心客户端 在启动时候,如果没有连上配置中心服务端,就启动不了报错 timeout。
	
	引入重试机制就是为了解决这个问题。
	
6.2 实现:

	第一:引入spring-retry依赖
	
	第二:重试相关配置 yml   cinema-member-service的yml配置
	
		spring:
		  cloud:
			config:
			  name: cinema-member-service
			  profile: dev
			  label: master
			  uri: http://localhost:8000/

			  fail-fast: true #快速失败,进行重试
			  retry:
				initial-interval: 5000 #初始间隔时间
				max-interval: 30000 #最大间隔时间
				max-attempts: 5 # 重试次数
				multiplier: 2 #重试间隔时间倍数
	
	第三:测试
	
		停掉配置中心服务端,再启动配置中心客户端,通过日志就可以看到重试的过程!

7、多仓库配置

7.1 为什么要使用多仓库配置?

	一个仓库,对应一个微服务的配置文件。
	
	方便管理微服务的配置文件。
	
	举例:10个微服务,10个仓库分别存放这10个微服务需要的配置文件。
	
	问题? 配置中心服务端仓库地址不能够写死!
	
7.2 使用

	第一:config-server 配置中心服务端,修改仓库地址,动态获取服务名称

		spring:
		  application:
			name: config-server
		  cloud:
			config:
			  server:
				git:
				  uri: https://gitee.com/yuanjie8080/{application}
				  username: yuanjie8080
				  password: WONIU8080


	第二:cinema-member-service 客户端
	
		spring:
		  application:
			name: cinema-member-service # 服务名称,对于配置中心客户端来说也是仓库名称
		  cloud:
			config:
			  #name: cinema-member-service   # 注释
			  profile: dev
			  label: master
			  uri: http://localhost:8000/


		添加的配置:服务名称,作为仓库名称,以及仓库中配置文件的名称
		
		
	第三:新建仓库cinema-member-service,再在仓库下新建配置文件 cinema-member-service-dev.yml
			
	OK!

8、配置中心高可用

8.1 搭建两台配置中心服务端,分别是8000、8001

	config-server:
	
		server:
		  port: ${port:8000}

	通过VM Option配置多个端口,启动多个配置中心服务端
	
	
8.2 cinema-member-service 配置中心客户端,连接多个config服务端

	spring:
	  application:
		name: cinema-member-service # 服务名称,对于配置中心客户端来说也是仓库名称
	  cloud:
		config:
		  #name: cinema-member-service
		  profile: dev
		  label: master
		  uri: http://localhost:8000,http://localhost:8001   # 多个config服务端

		  fail-fast: true #快速失败,进行重试
		  retry:
			initial-interval: 5000 #初始间隔时间
			max-interval: 30000 #最大间隔时间
			max-attempts: 5 # 重试次数
			multiplier: 2 #重试间隔时间倍数

8.3 测试

	停掉8000,重启cinema-member-service客户端;
	
	刚好看到日志:
	
		 Multiple Config Server Urls found listed.
		 Fetching config from server at : http://localhost:8000
		 Connect Timeout Exception on Url - http://localhost:8000. Will be trying the next url if available
		 Fetching config from server at : http://localhost:8001

		从上面可以看出,先连接config服务端8000,连接超时,切换另外一个节点8001. 
		
		最终:做到了配置中心高可用!

3.2.7 Nacos

1、nacos作用:配置中心、注册中心

2、nacos配置中心

项目:
	bootstrap.yml
		spring:
		  application:
			name: user-service
		  cloud:
			nacos:
			  config:
				server-addr: localhost:8848
				file-extension: yaml
		  profiles:
			active: dev
		
nacos控制台,新建配置

	命名:服务名+环境.yaml
	
	举例:user-service-dev.yaml
	
编写控制器,通过@RefreshScope注解,自动实现配置的读取与自动更新!

3、Nacos配置管理三元组

问题:nacos配置中心如何管理配置文件?

方案1:dataId

	Nacps配置中心: 
	
		user-service-dev.yaml
		user-service-test.yaml
		user-service-prod.yaml
		
	程序中切换环境:
		spring:
		  profiles:
			active: prod
		
方案2:group

	Nacps配置中心: 
	
		配置user-service-prod.yaml,
		
			默认分组是DEFAULT_GROUP,创建完不能修改。可用先删除,再重新创建
			
			现在指定为: PROD_GROUP
	
	程序中:
		spring:
		  application:
			name: user-service
		  cloud:
			nacos:
			  config:
				server-addr: localhost:8848
				file-extension: yaml
				group: PROD_GROUP    # 默认分组 DEFAULT_GROUP
		  profiles:
			active: prod
		
		
方案3:namespace

	第一:创建一个namespace叫做dev
	
	第二:先选中namepsace为dev(id是:9b90ad-1902-4026-b8ae-db2b70cda9f9),再新建配置
		
		dataId: user-service-prod.yaml
		group:   PROD_GROUP
		
	第三:boostrap.yml中		
		spring:
		  application:
			name: user-service		# dataId
		  cloud:
			nacos:
			  config:
				server-addr: localhost:8848
				file-extension: yaml
				namespace: 1b9b90ad-1902-4026-b8ae-db2b70cda9f9   # namespace
				group: PROD_GROUP   # group
		  profiles:
			active: prod

4、MySQL存储配置信息

Nacos内嵌的数据库存储了配置信息,重启Nacos配置依赖存在。

当然也可以把配置信息存储到mysql中,实现配置的持久化存储。

修改nacos的conf目录下application.properties配置即可!

5、Nacos注解中心

5.1 实现

	依赖:spring-cloud-starter-alibaba-nacos-discovery
	配置:
		spring:
		  cloud:
		    discovery:
				server-addr: localhost:8848
		
		
	这里也可以配置namespace与group
		spring:
		  cloud:
		    discovery:
				server-addr: localhost:8848
				namespace: 57bb4bb9-8f8c-47a9-bffd-9134ad2fbefc
				group: PROD_GROUP
		
5.2 多实例,服务集群

	第一:在nacos配置中心创建三个配置文件
	
		user-service-dev.yaml    端口:8888
		user-service-test.yaml   端口:8887
		user-service-prod.yaml   端口:8886
		
	第二:idea配置同一个启动类,可以执行多次: Edit Configuration --> Allow parallel run
	
	第三:微服务bootstrap.yml配置
		spring:
		  profiles:
			active: dev/test/prod  # 分别配置

6、gateway网关

第一:父项目锁定spring-cloud-dependencies版本

第二:启动类

第三:yml配置
	server:
	  port: 10010
	spring:
	  application:
		name: gateway-service
	  cloud:
		nacos:
		  discovery:
			server-addr: localhost:8848
			group: PROD_GROUP
			namespace: 57bb4bb9-8f8c-47a9-bffd-9134ad2fbefc
		gateway:
		  routes:
			- id: api-gateway-service
			  uri: lb://user-service
			  predicates:
				- Path=/user-service/**
			  filters:
				- StripPrefix=1
第四:访问测试
	
	用户微服务:http://localhost:8888/user

	通过网关访问:http://localhost:10010/user-service/user

7、nacos 权重设置

7.1 控制台设置
7.2 配置bean
	// 如果配置了服务权重,这里需要配置才会生效
	@Bean
	public IRule loadBalanceRule(){
		return new NacosRule();
	}

8、nacos实例

分类:
	临时实例     AP架构,保证可用性
	持久化实例   CP架构,保证一致性

保护阈值:

	配置保护阈值,是0到1之间的数,比如设置为:0.6
	
	当健康实例/总实例 < 保护阈值,就会返回所有的实例给客户端; 否则只返回健康实例
	
演示:

	设置的保护阈值是:0.6

	停止一台服务器: 健康实例/总实例 = 2/3 = 0.66 > 0.6, 只会返回健康实例,测试效果:页面不会报错。

	停止两台服务器:健康实例/总实例 = 1/3 = 0.33 < 0.6, 返回所有实例,测试效果:会有报错 

9、删除持久实例

持久化实例nacos不会删除,我们可用通过运维操作手动删除。

比如:查看nacos官网 open api章节中,有一章:注销实例

https://nacos.io/zh-cn/docs/open-api.html

nacos 和eureka 的区别
1.CAP理论 :C一致性,A高可用,P分区容错性
eureka只支持AP
nacos支持CP和AP两种
nacos是根据配置识别CP或AP模式,如果注册Nacos的client节点注册时是ephemeral=true即为临时节点,那么Naocs集群对这个client节点效果就是AP,反之则是CP,即不是临时节点

 #false为永久实例,true表示临时实例开启,注册为临时实例
 spring.cloud.nacos.discovery.ephemeral=true

2.连接方式
nacs使用的是netty和服务直接进行连接,属于长连接
eureka是使用定时发送和服务进行联系,属于短连接

3.服务异常剔除
Eureka client在默认情况每隔30s想Eureka Server发送一次心跳,当Eureka Server在默认连续90s秒的情况下没有收到心跳, 会把Eureka client 从注册表中剔除,在由Eureka-Server 60秒的清除间隔,把Eureka client 给下线
nacos:
nacos client 通过心跳上报方式告诉 nacos注册中心健康状态,默认心跳间隔5秒,
nacos会在超过15秒未收到心跳后将实例设置为不健康状态,可以正常接收到请求
超过30秒nacos将实例删除,不会再接收请求
4.自我保护机制
相同点:保护阈值都是个比例,0-1 范围,表示健康的 instance 占全部instance 的比例。
不同点:
1)保护方式不同
Eureka保护方式:当在短时间内,统计续约失败的比例,如果达到一定阈值,则会触发自我保护的机制,在该机制下,Eureka Server不会剔除任何的微服务,服务端也可以接受新的注册和查询请求,但是不会同步到其他节点,只保证当前节点可用,等到恢复正常后,再退出自我保护机制,同时将新的注册请求同步到其他节点。自我保护开关(eureka.server.enable-self-preservation: false)
Nacos保护方式:当域名健康实例 (Instance) 占总服务实例(Instance) 的比例小于阈值时,无论实例 (Instance) 是否健康,都会将这个实例 (Instance) 返回给客户端。这样做虽然损失了一部分流量,但是保证了集群的剩余健康实例 (Instance) 能正常工作。

  • 44
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

简兮冫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值