# 微服务
# SpringCloud的五大常用组件
# 通常情况下,SpringCloud的五大常用组件是指以下五个组件:
- Eureka:服务注册与发现
- Ribbon:负载均衡
- Feign:声明式服务调用
- Hystrix:服务熔断与降级
- Zuul:API网关
# 随着SpringCloud的发展,我们项目中使用了一些阿里巴巴的组件,如:
- Nacos:服务注册与发现/配置中心
- Ribbon:负载均衡
- Feign:声明式服务调用
- sentinel:服务熔断与降级
- Gateway:API网关
# 服务注册与发现
# 服务注册与发现的核心组件是Eureka和Nacos
# Eureka:服务注册与发现
- 服务注册:服务提供者需要把自己的信息注册到Eureka Server上,以便服务消费者能够找到。
- 服务发现:服务消费者从Eureka Server上获取服务提供者的信息,以便能够调用服务。
- 服务监控:服务提供者会每隔30s定时向Eureka Server发送心跳,以保证服务的可用性。如果90s内没有收到心跳,则Eureka Server会将该服务实例从注册表中删除。
# Nacos:服务注册与发现/配置中心
- 服务注册:服务提供者需要把自己的信息注册到Nacos Server上,以便服务消费者能够找到。
- 服务发现:服务消费者从Nacos Server上获取服务提供者的信息,以便能够调用服务。
- 配置中心:Nacos Server还可以作为配置中心,用于统一管理配置文件。
# Eureka和Nacos的区别
- Eureka是Netflix公司开源的组件,Nacos是阿里巴巴公司开源的组件。
- Eureka只能用于服务注册与发现,Nacos既可以用于服务注册与发现,也可以用于配置中心。
- Nacos提供服务端主动检测提供者状态;临时实例采用心跳检测,非临时实例采用主动检测模式。
- 临时实例在心跳不正常时,会被删除;非临时实例不会被剔除。
- Nacos支持服务列表变更的消息推送模式,Eureka不支持。
- Nacos集群默认采用AP模式,当存在非临时实例,采用CP模式。Eureka集群默认采用AP模式。
# Ribbon负载均衡策有哪些
# Ribbon负载均衡策略有以下几种:
- 轮询策略:依次轮询选择服务实例。
- 随机策略:随机选择服务实例。
- 权重策略:根据服务实例的权重选择服务实例。
- 最小并发策略:选择并发量最小的服务实例。
- 重试策略:在一定次数内重试选择服务实例。
- 可用性敏感策略:先过滤非健康的服务实例,再选择连接数最少的服务实例。
- 区域感知策略:根据区域选择服务实例。
# 自定义负载均衡策略
- 自定义负载均衡策略需要实现IRule接口。(全局)
public class MyRule implements IRule {
@Override
public Server choose(Object key) {
// 自定义负载均衡策略
return null;
}
}
- 自定义负载均衡策略 @Bean注入。(局部)
@Bean
public IRule myRule() {
return new MyRule();
}
# 什么是服务雪崩
定义
服务雪崩是指当一个服务出现故障时,由于服务之间的调用关系,可能会导致多个服务出现故障,最终导致整个系统不可用。
# 如何解决服务雪崩
- 熔断降级 (解决)
- 限流 (预防)
# 服务降级
定义
服务降级是服务自我保护的一种方式,或者保护下游服务的一种方式,用于确保服务不会收到请求突增影响变得不可用,确保服务不会崩溃。
@FeignClient(value = "service-provider", fallback = MyFallback.class)
# 服务熔断
定义
服务熔断用于监控某个服务的调用情况,当调用10s失败次数达到50%时,会触发熔断器,之后每隔五秒会尝试调用一次,如果调用成功,则关闭熔断器,否则继续等待。
// 开启服务熔断
@EnableCircuitBreaker
// 服务熔断
@HystrixCommand(fallbackMethod = "fallbackMethod")
// 配置规则
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")
})
// 服务熔断
@HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000")
})
# 微服务监控
# skywalking
定义
SkyWalking是一个开源的分布式APM系统,用于监控微服务架构中的应用性能。提供了完善的链路追踪功能。
- skywalking主要可以监控接口、服务、物理实例的一些状态。特别是在压测的时候可以看到众多服务中哪些服务和接口比较慢,我们可以针对性的分析和优化。
- 还可以设置告警规则,项目上线以后,如果报错,我们分别设置了可以给相关负责人发短信和发邮件,第一时间了解项目的bug情况。
# 微服务限流
定义
限流是指对系统的访问流量进行限制,防止系统被过多的请求拖垮,导致系统不可用。
# 为什么要限流
- 并发的确大(突发流量)
- 防止用户恶意刷接口
# 实现方式
- Tomcat可以设置最大连接数
- Nginx 漏桶算法
- 网关 令牌桶算法
- 自定义拦截器
# Nginx限流
// 漏桶算法 限流 以固定速率处理请求
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
server {
location / {
limit_req_zone=mylimit burst=5 nodelay;
}
}
- 语法 limit_req_zone key zone rate;
- key:限流的key,可以是$binary_remote_addr、$server_name等。
- zone:定义共享内存区域,来存储访问信息,10m可以存储16w个ip的访问信息。
- rate:限流的速率,1r/s表示每秒1个请求。
- burst:桶的大小,5表示最大并发数为5。
- nodelay:快速处理请求,不会等待。
// 控制并发连接数
limit_conn_zone $binary_remote_addr zone=mylimit:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
location / {
limit_conn mylimit 5; // 限制并发连接数为5
limit_conn perserver 10; // 限制每个server的并发连接数为10
}
}
- limit_conn mylimit 5; 限制单个IP同时连接数为5
- limit_conn perserver 10; 限制每个虚拟主机的最大并发连接数为10
# 网关限流
// 令牌桶算法 限流 以固定速率处理请求
spring:
cloud:
gateway:
routes:
- id: rate_limit_route
uri: http://localhost:8081
predicates:
- Path=/rateLimit
filters:
- name: RequestRateLimiter
args:
key-resolver: "#{@userKeyResolver}"
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
- key-resolver 定义限流对象,使用SpEL表达式获取,需要代码实现
- redis-rate-limiter.replenishRate: 1 令牌桶每秒填充速率
- redis-rate-limiter.burstCapacity: 2 令牌桶最大容量
@Component
public class UserKeyResolver implements KeyResolver {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
- KeyResolver 限流对象接口
- resolve 限流对象的实现方法
- exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() 获取请求的IP地址
- Mono.just() 将IP地址包装成Mono对象
# 比较令牌桶和漏桶
- 漏桶:如果一下子来了很多请求,但是请求会被放在池子里面,然后以固定的速率去处理请求。
- 令牌桶:以固定的速率往桶内放入令牌,一下来很多请求,只要桶内的令牌足够多,请求就会立马被处理,这就是允许突发大量请求进来。
# CAP定理
定义
CAP定理是分布式系统中最基本的理论,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)三者不可兼得。
- 可用性:系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求都必须有响应。
- 一致性:系统中的数据一旦发生变化,所有的用户都能够立即看到。
- 分区容错性:系统在遇到网络分区故障时,仍然能够继续提供服务。
# BASE理论
定义
BASE理论是对CAP理论的延伸,是对大规模分布式系统的实践总结,核心思想是即使无法做到强一致性,但可以做到最终一致性。
- 基本可用(Basically Available):系统保证基本的可用性,允许损失部分可用性。
- 软状态(Soft state):允许系统中的数据存在中间状态,不同节点的数据副本可能不一致。
- 最终一致性(Eventually Consistent):系统保证在一段时间内,数据一致性最终能够达到。
# 分布式事务
定义
分布式事务是指事务的参与者、资源、执行者分布在不同的节点上,分布式事务需要满足ACID特性。
# Seata架构
- TC(Transaction Coordinator):事务协调器,负责全局事务的协调。
- TM(Transaction Manager):事务管理器,负责事务的开启、提交、回滚。
- RM(Resource Manager):资源管理器,负责分支事务的注册、状态汇报、回滚。
# Seata的XA模式
- CP,需要互相等待各个分支的事务提交,可以保证强一致性,但是性能较差。(银行业务)
# Seata的AT模式
- AP,底层使用数据库的undo log,可以保证最终一致性,性能较好。(电商业务)
# Seata的TCC模式
- AP,通过Try-Confirm-Cancel三个操作实现分布式事务,可以保证最终一致性,性能较好。(酒店预订)
# MQ实现分布式事务
- 在A服务写数据的时候,需要在同一事务中发送消息到另外一个事务,异步,性能最好
# 分布式服务的接口幂等性
定义
接口幂等性是指对于同一个接口的多次调用,对于系统的状态和数据都是一致的,不会因为多次调用而产生副作用。
- 用户重复点击(网络波动)
- MQ消息重复
- 应用使用失败或超时重复机制
# 接口幂等
- GET请求:幂等性是指对于同一个请求的多次调用,返回的结果是一致的。
- POST请求:不是幂等的,因为POST请求每次请求都会创建一个新的资源。
- PUT请求:不是幂等的,因为PUT请求每次请求都会更新一个资源。
- DELETE请求:幂等性是指对于同一个请求的多次调用,返回的结果是一致的。
# 实现幂等性
- 如果是新增操作,可以使用唯一索引,保证幂等性。
- 如果是新增或更改操作
- 分布式锁:使用Redis分布式锁,保证幂等性。
- 使用token+redis实现,性能比较好
- 第一次请求生成token,存入redis,返回给前端
- 前端请求携带token,后端校验token,删除token
# 分布式任务调度 XXL-JOB
# XXL-JOB的路由策略
- 第一种策略:轮询策略,每次调度都是按照顺序轮询调度。
- 第二种策略:故障转移策略,当某个执行器挂掉的时候,会自动切换到另外一个执行器。
- 第三种策略:分片广播策略,每个执行器都会执行一次任务。
# XXL-JOB的任务执行失败怎么解决
- 路由策略如果是故障转移策略,使用健康的实例执行任务
- 设置重试次数,如果任务执行失败,会自动重试
- 查看日志+邮件告警来通知相关负责人
# 如果有大数据量的任务同时都需要执行,怎么解决
- 让多个实例一块去执行,路由策略使用分片广播策略
- 在任务执行的代码中可以获取分片总数和当前分片,按照取模的方式分摊到各个实例去执行