简介
随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。单体架构将业务的所有功能集中在一个项目中开发,打成一个包部署。
优点:架构简单,部署成本低 缺点:耦合度高(维护困难、升级困难)
分布式微服务架构,将单个的整体应用程序分割成更小的项目关联的独立的服务。一个服务通常实现一组独立的特性或功能,包含自己的业务逻辑和适配器。各个微服务之间的关联通过暴露api来实现。这些独立的微服务不需要部署在同一个虚拟机,同一个系统和同一个应用服务器中。
微服务架构是一种系统架构的设计风格。与传统的单体式架构不同,微服务架构提倡将一个单一的应用程序拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间使用轻量级通信机制(通常是 HTTP RESTFUL API)进行通讯。
1.优点
-
将服务拆分成多个单一职责的小的服务,进行单独部署,服务之间通过网络进行通信
-
每个服务应该有自己单独的管理团队,高度自治
-
服务各自有自己单独的职责,服务之间松耦合,避免因一个模块的问题导致服务崩溃
2.缺点
-
开发人员要处理分布式系统的复杂性
-
多服务运维难度,随着服务的增加,运维的压力也在增大
-
服务治理 和 服务监控难度增加
微服务方案
常见的实现微服务的三种方案
-
Spring Cloud NetFlix
基于美国Netflix公司开源的组件进行封装,提供了微服务一栈式的解决方案。
-
Spring Cloud alibaba 在Spring cloud netflix基础上封装了阿里巴巴的微服务解决方案。
-
dubbo+zookeeper
核心问题
微服务的要解决的核心问题
- 这么多服务,客户端如何访问?
- 这么多服务,服务间如何通信?
- 这么多服务,如何管理?
- 服务挂了,怎么办?
核心组件
微服务核心组件以及常用方案
-
eureka、consul、nacos 服务注册中心组件
-
rabbion 、 openfeign 服务负载均衡 和 服务调用组件
-
hystrix 、hystrix dashboard 服务断路器 和 服务监控组件
-
zuul、gateway 服务网关组件
-
config 统一配置中心组件
-
bus 消息总线组件
版本对应
左侧spring cloud,右侧spring boot版本
bootstrap与application
spring cloud 构建于spring boot 之上,在spring boot中有两种上下文,一种是bootstrap,另外一种是application。
- bootstrap.yml/bootstrap.properties :用来程序引导时执行,应用于更加早期配置信息读取。可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
- application.yml/application.yml :可以用来定义应用级别的, 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
文件名.properties /文件名.yml文件名相同且同时存在时,先加载 .properties 文件,再加载 .yml 文件。
bootstrap(.yml/.properties)应用
- 配置alibaba-nacos-config基本连接信息,用于获取远程所需配置。alibaba-nacos-config 基本连接信息就不能写到 application.yml/.properties中等到 Application Context 初始化时才读取。必须在 bootstrap.yml/.properties 里配置,在初始化Bootstrap Context时完成读取, 在Application Context 初始化时利用已读取的alibaba-nacos-config 基本连接信息从alibaba-nacos-config 中获取所需的远程配置信息。
- 一些固定的不希望被覆盖的属性,如程序的名字。
- 一些加解密的场景。
Spring Cloud NetFlix
聚合工厂创建
1.首先创建一个springboot工程,可以创建git仓库
2.删除src,.md,mvnm,.cmd文件
3.父工程的pom文件使用dependencyManagement,管理依赖版本而不引入jar包
4.右键父工程创建maven工程的module,因为依赖有传递性,子工程也自然成为springboot工程
服务注册中心
服务注册中心
-
可以对所有的微服务的信息进行存储,如微服务的名称、IP、端口等
-
可以在进行服务调用时通过服务发现查询可用的微服务列表及网络地址进行服务调用
-
可以对所有的微服务进行心跳检测,如发现某实例长时间无法访问,就会从服务注册表移除该实例
常用的注册中心:Eureka、Consul(GO)、Zookeeper(java)、以及阿里巴巴推出Nacos(java)。这些注册中心在本质上都是用来管理服务的注册和发现以及服务状态的检查的。
Eureka
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务注册和发现功能。Eureka包含两个组件:
-
Eureka Server
-
Eureka Client
1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--引入 eureka server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!--引入eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2.编写配置文件
服务端要配置register-with-eureka和fetch-registry,客户端不用。
server:
port: 8761 # eureka 默认的端口号
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka #指定服务注册中心的地址
register-with-eureka: false # 不注册自己
fetch-registry: false # false表示自己为服务中心
#指定服务注册中心的名字
spring:
application:
name: EUREKASERVER #服务名称不要使用下划线 服务名称不区分大小写 推荐服务名大写
eureka集群
当有集群时,注册中心要相互配置其他的注册中心地址
例:http://127.0.0.1:8761/eureka
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8762/eureka,http://127.0.0.1:8763/eureka
提供者向一个注册中心注册时,其他注册中心也能获取到
3.配置启动类
在启动类上添加注解标识
@EnableEurekaServer // 开启eureka服务注册中心服务
@EnableEurekaClient // 标识当前服务是eureka的客户端
Eureka自我保护机制
默认情况下,如果Eureka Server在一定时间内(默认90秒)没有接收到某个微服务实例的心跳,Eureka Server将会移除该实例。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,而微服务本身是正常运行的,此时不应该移除这个微服务,所以引入了自我保护机制。
Eureka Server在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,让这些实例不会过期。这种设计的哲学原理就是"宁可信其有不可信其无!"。自我保护模式正是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。
自我保护机制不建议关闭
eureka:
server:
enable-self-preservation: false # 关闭自我保护机制
eviction-interval-timer-in-ms: 2000 # 每隔多久(ms)触发一次服务剔除
Consul注册中心
consul是一个可以提供服务发现,健康检查,多数据中心,Key/Value存储等功能的分布式服务框架,用于实现分布式系统的服务发现与配置。与其他分布式服务注册与发现的方案,使用起来也较为简单。Consul用Golang实现,因此具有天然可移植性(支持Linux、Windows和Mac OS X);安装包仅包含一个可执行文件,方便部署。
官方安装地址: Deploy Consul on VMs | Consul | HashiCorp Developer
下载安装后配置环境变量,开启consul:命令行输入consul agent -dev,consul端口号:8500
1.导入依赖
<!--引入consul依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
2.配置yml
spring:
application:
name: USERSERVICE
cloud:
consul:
host: localhost
port: 8500
配置好后consul就是注册中心
consul健康监控
1.导入依赖
默认情况consul监控健康是开启的,但是必须依赖健康监控依赖才能正确监控健康状态所以直接启动会显示错误,引入健康监控依赖之后服务正常
<!-- 健康度监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
CAP原则
CAP定理:CAP定理又称CAP原则,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾
分区容错性是分布式系统中必须保证的
一致性(C):
在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):
在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容忍性(P):
就是高可用性,一个节点崩了,并不影响其它的节点(100个节点,挂了几个,不影响服务,越多机器越好)
1.Eureka特点
-
Eureka中没有使用任何的数据强一致性算法保证不同集群间的Server的数据一致,仅通过数据拷贝的方式争取注册中心数据的最终一致性,虽然放弃数据强一致性但是换来了Server的可用性,降低了注册的代价,提高了集群运行的健壮性。
2.Consul特点
-
基于Raft算法,Consul提供强一致性的注册中心服务,但是由于Leader节点承担了所有的处理工作,势必加大了注册和发现的代价,降低了服务的可用性。通过Gossip协议,Consul可以很好地监控Consul集群的运行,同时可以方便通知各类事件,如Leader选择发生、Server地址变更等。
3.zookeeper特点
-
基于Zab协议,Zookeeper可以用于构建具备数据强一致性的服务注册与发现中心,而与此相对地牺牲了服务的可用性和提高了注册需要的时间。
服务间通信方式
RestTemplate+Ribbon
spring框架提供的RestTemplate类可用于在应用中调用rest服务,它简化了与http服务的通信方式,统一了RESTful的标准,封装了http链接, 我们只需要传入url及返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更优雅的调用RESTful服务的方式。
Spring Cloud Ribbon是一个基于HTTP和TCP的 客户端 负载均衡工具,将用户请求平摊到多个服务上,实现系统的高可用。它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。
1.使用RestTemplate调用不同服务,启动类添加@EnableDiscoveryClient 注解
使用eureka作为注册中心,就直接使用@EnableEurekaClient注解;如果使用其他注册中心,就使用@EnableDiscoveryClient注解。
@Controller
public class UserController {
private Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping("/user")
@ResponseBody
public String invokeOrder(){
logger.info("用户服务被调用!");
// 创建发送http请求的 RestTemplate 对象
RestTemplate restTemplate = new RestTemplate();
String rest = restTemplate.getForObject("http://localhost:8889/order",
String.class);
// restTemplate.getForObject方法传递一个url和返回的参数类型,要是java类
logger.info("订单服务调用成功,返回结果"+rest);
return " Invoke UsersService ok "+rest;
}
}
@Controller
public class OrderController {
private Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping("/order")
@ResponseBody
public String OrderTest(){
logger.info("订单服务被调用!");
return " invoke OrderService ok";
}
}
2.使用ribbon负载均衡
导入依赖
<!--引入ribbon依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
controller类代码
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private LoadBalancerClient loadBalancerClient;
// RestTemplate+Ribbon 实现服务间通信
@RequestMapping("m2")
public String method2(){
RestTemplate restTemplate = new RestTemplate();
// 通过ribbon负载均衡组件拉取通信节点
List<ServiceInstance> scoreservice =
discoveryClient.getInstances("SCORESERVICE");
//discoveryClient通过服务id获取所有的注册中心节点
//自定义策略实现节点的选择
int index = new Random().nextInt(scoreservice.size());
ServiceInstance serviceInstance = scoreservice.get(index);
// 获取实例的通信地址和端口号
URI uri = serviceInstance.getUri();
System.out.println("uri = " + uri);
String result = restTemplate.getForObject(uri + "/score/m1", String.class);
return "studentService OK ==> scoreService : " +result;
}
@RequestMapping("m3")
public String method3(){
RestTemplate restTemplate = new RestTemplate();
// 从consul注册中心拉取通信节点 默认策略 轮循
//loadBalancerClient 通过负载均衡策略获取指定服务名的一个节点
ServiceInstance scoreservice = loadBalancerClient.choose("SCORESERVICE");
URI uri = scoreservice.getUri();
String result = restTemplate.getForObject(uri + "/score/m1", String.class);
return "studentService OK ==> scoreService : "+result;
}
优化:
每次获取都要url拼接
添加配置类
@Configuration
public class BeanConfig {
@Bean
@LoadBalanced //ribbon让托管的RestTemplate具有负载均衡的能力
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
controller代码
@Autowired
private RestTemplate restTemplate;
@RequestMapping("m4")
public String method4(){
//该方式解决了服务间通信和负载均衡问题,但是代码难维护 服务间调用时路径存在强耦合关系
String result = restTemplate.getForObject("http://SCORESERVICE/score/m1",
String.class);
return "studentService OK ==> scoreService : "+result;
}
轮循策略的修改,在yml配置
# 设置负载均衡策略
SCORESERVICE: # 服务的名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
但仍有缺点,url路径是固定的,大量使用这种方式以后修改很麻烦,增加了维护难度
OpenFeign组件
RestTemplate+Ribbon存在的问题:
-
1.每次调用服务都需要写这些代码,存在大量的代码冗余
-
2.服务地址如果修改,维护成本增高
-
3.使用时不够灵活
Feign是一个声明式的伪Http客户端,它使得服务间的通信变得更简单。使用Feign,只需要创建一个接口并添加注解。同时可以完成数据的自动转换,它具有可插拔的注解特性(可以使用springmvc的注解),可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,默认实现了负载均衡的效果并且springcloud为feign添加了springmvc注解的支持
1.导入依赖
<!--引入openfeign依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.添加接口类
@FeignClient("ORDERSERVICE")
public interface OrderClient {
@RequestMapping("/order/m1") //和想要调用的一致
String method1();
}
3.启动类上添加注解
@EnableFeignClients // 开启openfeign服务
openFeign默认使用轮循这种策略,内部集成的就是ribbon,要改变策略和ribbon一样
带参数的通信
接口
@FeignClient("ORDERSERVICE") // 注解属性表示需要调用服务的id
public interface OrderClient {
@RequestMapping("/order/m1")
String method1();
// http://localhost:8508/order/m2?id=10
@RequestMapping("/order/m2")
String method2(@RequestParam("id") Integer id);
// http://localhost:8508/order/m2/10 Restful
@RequestMapping("/order/m3/{id}")
String method3(@PathVariable("id") Integer id);
// http://localhost:8508/order/m4?id=10&name=mate60
@RequestMapping("/order/m4")
String method4(@RequestParam("id") Integer id,@RequestParam("name")String name);
// 通过在参数列表上添加@RequestBody注解 实现参数以json格式进行传递
@RequestMapping("/order/m5")
String method5(@RequestBody Order order);
// ?ids=1&ids=2&ids=3
@RequestMapping("/order/m6")
String method6(@RequestParam("ids") Integer[] ids);
@RequestMapping("/order/m7/{id}")
Order method7(@PathVariable("id") Integer id);
@RequestMapping("/order/m8")
List<Order > method8();
}
消费者
@RequestMapping("m2")
public String method2(Integer id){
log.info("id={}",id);
//向order服务发起http请求
String result = orderClient.method2(id);
return " UserService ok ==请求==>OrderService ==结果==> "+result;
}
@RequestMapping("m3/{id}")
public String method3(@PathVariable("id") Integer id){
log.info("id={}",id);
//向order服务发起http请求
String result = orderClient.method3(id);
return " UserService ok ==请求==>OrderService ==结果==> "+result;
}
@RequestMapping("m4")
public String method4(Integer id,String name){
log.info("id={}",id);
//向order服务发起http请求
String result = orderClient.method4(id,name);
return " UserService ok ==请求==>OrderService ==结果==> "+result;
}
@RequestMapping("m5")
public String method5(Integer id,String name){
Order order = new Order();
order.setName(name);
order.setId(id);
log.info("id={}",id);
//向order服务发起http请求
String result = orderClient.method5(order);
return " UserService ok ==请求==>OrderService ==结果==> "+result;
}
@RequestMapping("m6")
public String method6(Integer[] ids){
log.info("ids={}",ids);
//向order服务发起http请求
String result = orderClient.method6(ids);
return " UserService ok ==请求==>OrderService ==结果==> "+result;
}
//接受id,返回对象,模拟查询
@RequestMapping("m7")
public String method7(Integer id){
//向order服务发起http请求
Order result = orderClient.method7(id);
System.out.println(result);
return " UserService ok ==请求==>OrderService ==结果==> "+result;
}
//模拟查询所有
@RequestMapping("m8")
public String method8(){
//向order服务发起http请求
List<Order> orders = orderClient.method8();
orders.forEach(System.out::println);
return " UserService ok ==请求==>OrderService ==结果==> "+orders;
}
restful风格使用@PathVariable 注解,url拼接使用@RequestParam 注解,json类型使用@RequestBody 注解
断路器组件
使用Hystrix
-
在分布式环境中,许多服务依赖项不可避免地会失败。Hystrix是一个库,它通过添加延迟容忍和容错逻辑来帮助您控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止它们之间的级联故障以及提供后备选项来实现这一点,所有这些都可以提高系统的整体弹性。
-
通俗定义: Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统中,许多依赖不可避免的会调用失败,超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障(服务雪崩现象),提高分布式系统的弹性。
-
hystrix 用来保护微服务系统 实现 服务降级 服务熔断
服务雪崩:在微服务之间进行服务调用是由于某一个服务故障,导致级联服务故障的现象,称为雪崩效应。雪崩效应描述的是提供方不可用,导致消费方不可用并将不可用逐渐放大的过程
导入依赖
<!--引入hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
在启动类上添加注解
@EnableCircuitBreaker // 开启hystrix监控
服务熔断
“熔断器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器(hystrix)的故障监控,某个异常条件被触发,直接熔断整个服务。向调用方法返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法处理的异常,就保证了服务调用方的线程不会被长时间占用,避免故障在分布式系统中蔓延,乃至雪崩。如果目标服务情况好转则恢复调用。服务熔断是解决服务雪崩的重要手段
断路器打开条件
1、 当满足一定的阀值的时候(默认10秒内超过20个请求失败)
2、 当失败率达到一定的时候(默认10秒内超过50%的请求失败)
3、 到达以上阀值,断路器将会开启
4、 当开启的时候,所有请求都不会进行转发
5、 一段时间之后(默认是5秒),这个时候断路器是半开状态,会让其中一个请求进行转发。如果成功,断路器会关闭,若失败,继续开启。重复4和5。
服务熔断在提供者上添加
@RequestMapping("m1")
// 指明通过哪个方法实现快速响应
@HystrixCommand(fallbackMethod = "fallbackMethod1")
public String method1(Integer id){
System.out.println("=========HystrixController id = "+id+"===========");
if (id<0){
throw new RuntimeException("参数异常");
}
return "HystrixController ok";
}
// 备选/快速响应方法 参数列表 要和method1保持一致
public String fallbackMethod1(Integer id){
return "参数异常,param="+id;
}
服务降级
服务压力剧增的时候根据当前的业务情况及流量对一些服务和页面有策略的降级,以此缓解服务器的压力,以保证核心任务的进行。同时保证部分甚至大部分任务客户能得到正确的响应。也就是当前的请求处理不了了或者出错了,给一个默认的返回。
服务降级在消费者端上添加
1.yml配置
feign.hystrix.enabled=true #开启openfeign支持降级
2.在openfeign客户端中加Hystrix接口,接口里是要调用的方法,和之前openfeign一样
@FeignClient(value = "HYSTRIXCLIENT",fallback = HysClientFallback.class)
public interface HysClient {
@GetMapping("/h2")
String test02(@RequestParam Integer id);
}
3.实现接口的实现类
@Component
public class HysClientFallback implements HysClient{
@Override
public String test02(Integer id) {
return "服务器繁忙,请稍后再试!"+id;
}
}
降级和熔断总结
1.共同点
-
目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段;
-
最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用;
-
粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改);
-
自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;sentinel
2.异同点
-
触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
-
管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务边缘服务开始)
3.总结
-
熔断必会触发降级,所以熔断也是降级一种,区别在于熔断是对调用链路的保护,而降级是对系统过载的一种保护处理
Dashboard监控
1.导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
2.启动类添加@EnableHystrixDashboard 注解
启动类里添加servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean=
new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
retuen registrationBean;
}
localhost:端口号/hystrix访问,点击Monitor Stream进入
绿球越大说明请求越多,颜色代表健康程度(绿>黄>橙>红),线条代表最近的请求数
服务网关
网关统一服务入口,可方便实现对平台众多服务接口进行管控,对访问服务的身份认证、防报文重放与防数据篡改、功能调用的业务鉴权、响应数据的脱敏、流量与并发控制,甚至基于API调用的计量或者计费等等。
-
网关 = 路由转发 + 过滤器+负载均衡 路由转发:接收一切外界请求,转发到后端的微服务上去
-
网关组件在微服务中架构
zuul是从设备和网站到Netflix流媒体应用程序后端的所有请求的前门。作为一个边缘服务应用程序,zuul被构建为支持动态路由、监视、弹性和安全性。zuul组件已经从1.0更新到2.0,但是作为springcloud官方不再推荐使用zuul2.0,但是依然支持zuul2
Spring Cloud Gateway是Spring Cloud生态系统中的一部分,它是一个基于Spring Framework 5,Spring Boot 2和Project Reactor等技术开发的全新的API网关服务器。它旨在提供一种简单而有效的方式来路由到API,提供过滤器,以及在执行请求和响应之间的操作。
1.导入依赖
<!--引入gateway网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2.yml配置
server:
port: 9090
spring:
application:
name: GATEWAY
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: category_router #路由唯一标识
uri: http://localhost:9090 #路由转发地址
predicates: # 断言
- Path=/order/m1 # 根据路径断言,只匹配/order/m1
- Path=/order/m1,/order/m1 # 匹配/order/m1,/order/m2
- Path=/order/* # 匹配/order下一级所有
- Path=/order/** # 匹配/order下所有
filters:
- StripPrefix=0 #剥离请求路径的前缀,0不剥离,1剥离一级,2剥离二级
- id: user_router # 配置第二个路由
uri: http://localhost:9091 #路由转发地址
predicates: # 断言
- Path=/order/m1 # 根据路径断言,只匹配/order/m1
开启根据服务名动态获取路由
spring:
application:
name: gateway
cloud:
consul:
host: localhost
port: 8500
gateway:
routes:
- id: priducts_router #路由唯一标识
uri: lb://PRODUCTS # 根据服务名动态获取路由
predicates:
- Path=/p/**
discovery:
locator:
enabled: true #开启根据服务名动态获取路由
其他断言方式
- After=2023-01-06T11:32:53.698+08:00[Asia/Shanghai] # 指定日期之后的请求进行路由
- Before=2021-12-25T23:29:38.905+08:00[Asia/Shanghai] # 指定日期之前的请求进行路由
- Between=2021-12-25T23:29:38.905+08:00[Asia/Shanghai], 2021-12-27T23:29:38.905+08:00[Asia/Shanghai]
- Cookie=username,mosin 基于指定cookie的请求进行路由
- Cookie=username,[A-Za-z0-9]+ 基于指定cookie的请求进行路由
curl http://localhost:8989/user/findAll --cookie "username=zhangsna"
- Header=X-Request-Id, \d ``基于请求头中的指定属性的正则匹配路由(这里全是整数)
curl http://localhost:8989/user/findAll -H "X-Request-Id:11"
- Method=GET,POST 基于指定的请求方式请求进行路由
隐藏路径
gateway:
routes:
mydept.serviceId: xxx路径名 # mydept.serviceId和mydept.path是自定义的
mydept.path: /mydept/**
ignored-services: xxx # 不能使用这个路径访问了
配置管理
Config提供分布式系统的中心化外部配置,Config分为客户端和服务端两个部分
配置配置中心
1.导入依赖
<!--引入统一配置中心-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2.启动类添加 @EnableConfigServer 注解
3.指定远程仓库(config配置中心必须设置)
spring:
cloud:
config:
server:
git:
uri: https://gitee.com/classmeng/config.git # 配置远程仓库的地址
default-label: master # 设置分支
# username:
# password: 私有仓库需要设置用户名和密码
default-label: master #配置分支
获取yml要分环境(-dev,-pro...),会自动合并配置文件
服务拉取配置中心的配置
1.导入依赖
<!--引入config client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2.修改yml
将application.(properties|yml)改为bootstrap.(properties|yml)。让项目启动时先等待拉取远程配置,拉取远程配置成功之后再根据远程配置信息启动,application.yml启动项目,使用这个配置文件在springboot项目启动过程中不会等待远程配置拉取,直接根据配置文件中内容启动,因此当需要注册中心,服务端口等信息时,远程配置还没有拉取到,会直接报错。
spring:
cloud:
config:
discovery:
enabled: true #开启根据服务id 获取configServer ip地址
service-id: CONFIGSERVER
label: master #分支
name: configclient #文件的名字
profile: dev #配置环境 哪个文件生效
consul:
port: 8500
host: localhost
手动配置刷新
1.在config client端加入刷新暴露端点
management:
endpoints:
web:
exposure:
include: "*"
2.在需要刷新代码的类中加入刷新配置的注解
@RefreshScope(proxyMode = ScopedProxyMode.DEFAULT) //不重启服务实现数据的刷新
3.cmd命令窗口输入:curl -X POST http://localhost:8889/actuator/refresh //地址+端口号是配置中心的。
Spring Cloud Alibaba
简介
功能组件
- Sentinel:把流量作为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
- Nacos:一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
- RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的消息发布与订阅服务。
- Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架。
- Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。
- Alibaba Cloud OSS: 阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
- Alibaba Cloud SchedulerX: 阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
- Alibaba Cloud SMS: 覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速搭建客户触达通道。
构建父工程
<properties>
<spring.cloud.alibaba.version>2.2.1.RELEASE</spring.cloud.alibaba.version>
<spring.cloud-version>Hoxton.SR6</spring.cloud-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Nacos
Nacos:即Nacos Name Service(服务注册与发现) & Configurations Services(统一配置中心),具有双重功能。Nacos是一个内部微服务组件,需要在可信的内部网络中运行,不可暴露在公网环境。
下载地址:Releases · alibaba/nacos · GitHub
cmd执行命令:startup.cmd -m standalone
访问页面:http://localhost:8848/nacos/
Nacos配置(高版本需要):
1.在conf文件的application.properties里配置
### If turn on auth system:
nacos.core.auth.system.type=nacos
nacos.core.auth.enabled=true
2.并在后面设置用户名密码
nacos.core.auth.username=your.username
nacos.core.auth.password=your.password
3.自定义密钥,推荐将配置项设置为Base64编码的字符串,且原始密钥长度不得低于32字符。
### The default token (Base64 String):
nacos.core.auth.plugin.nacos.token.secret.key=your.token
服务注册
1.导入依赖
<!--引入nacos client的依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2.配置yml
server:
port: 8851
spring:
application:
name: ORDERS
cloud:
nacos:
server-addr: localhost:8848
3.启动类加入注解@EnableDiscoveryClient
修改权重
服务列表里的详情可以修改每个服务的权重
yml添加配置让权重生效
NACOSCLIENT: # 被调用服务的名称
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule
高版本nacos需要客户端鉴权
yml配置里添加用户名和密码
spring:
application:
name: CLAZZSERVICE
cloud:
nacos:
config:
group: DEFAULT_GROUP
name: clazz-dev
file-extension: yml
refresh-enabled: true
username: username
password: username
discovery:
server-addr: localhost:8848
username: username
password: username
配置中心
1.导入依赖
<!--引入nacos client 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--引入配置中心依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2.yml配置
spring:
cloud:
nacos:
server-addr: localhost:8848
config:
group: DEFAULT_GROUP
name: user-dev
file-extension: yml
namespace: public
3.在nacos中创建配置,复制yml配置即可
DataId
- 用来读取远程配置中心的中具体配置文件其完整格式如下:
- ${prefix}-${spring.profile.active}.${file-extension}
a. prefix 默认为 spring.application.name 的值,也可以通过配置项
spring.cloud.nacos.config.prefix来配置。
b. spring.profile.active 即为当前环境对应的 profile,详情可以参考 Spring Boot文档。
注意:
当 spring.profile.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成
${prefix}.${file-extension}
c. file-exetension 为配置内容的数据格式,可以通过配置项
spring.cloud.nacos.config.file-extension 来配置。目前只支持 properties 和 yaml 类型。
实现自动配置刷新
默认情况下nacos已经实现了自动配置刷新功能,如果需要刷新配置直接在控制器类中上加入@RefreshScope 注解即可
日志频繁刷新,可设置日志输出的级别进行调整
# Nacos 注册中心客户端心跳日志禁用 get changedGroupKeys:[]
logging:
level:
com.alibaba.nacos.client.config.impl: WARN
遇到的错误:Nacos作为配置中心控制台一直循环打印ClientWorker日志
将配置文件里的 spring.cloud.nacos.config.namespace=public
注释掉
Sentinel流量卫兵
sentinel和hystrix 类似,提供了两个服务组件:一个是 sentinel 用来实现微服务系统中服务熔断、降级等功能。一个是 sentinel dashboard 用来监控微服务系统中流量调用等情况 流控 熔断 降级 配置。sentinel相比hystrix不需要写代码注解,没有嵌入代码。
下载地址:Releases · alibaba/Sentinel · GitHub
Sentinel是一个spring boot jar包,可以直接cmd运行,默认端口号8080,建议修改
java -Dserver.port=9090 -jar sentinel-dashboard-1.8.6.jar
之后访问页面,输入用户名密码登录(用户名密码都是 sentinel )
1.导入依赖
<!--引入sentinel依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
2.配置yml
sentinel:
enabled: true
transport:
dashboard: localhost:9090 # sentinel端口号
port: 8719 #默认也是8719,数据传输接口
默认情况下sentiel为延迟加载,不会在启动之后立即创建服务监控,需要对服务进行调用时才会初始化,访问服务就能在sentinel上看到相关信息。
设置流控规则和熔断规则(也可以在簇点链路里设置)
流控规则
阈值类型:QPS(每秒请求数)和并发线程数
流控模式:直接、关联、链路
- 直接:流控规则直接作用自己
- 关联:流控规则作用关联资源,关联资源失败则自己就失败
- 链路:入口资源和其他资源都调用同一个服务,如果超出被调用服务的流控规则就对入口资源限制,不限制其他资源和被调用服务
流控效果:直接失败、warm up、排队等待
熔断规则
熔断策略:慢调用比例、异常比例、异常数