java-微服务
基础知识
SpringCLoud5大组件有哪些?
- 注册中心/配置中心–Nacos
- 远程调用–Feign
- 负载均衡–Ribbon
- 服务保护–sentinel
- 网关–Gateway
注册中心
常见的注册中心–eureka, nacos
服务注册和发现是什么意思?Spring Cloud如何实现服务注册发现?
我们当时项目采用的nacos作为注册中心,也是Spring Cloud体系中的一个核心组件,我理解的注册中心有三大功能,分别是服务注册,服务发现和服务状态监控
服务注册是指服务提供者需要把自己的信息注册到nacos中,由nacos来保存这些信息,比如服务名称,ip,端口等
服务发现是消费者向nacos拉取服务列表信息,如果服务提供者有集群,则消费者会利用负载均衡算法,选择一个发起调用
服务监控是务的提供者每隔5秒向注册中心发送心跳,如果超过15秒注册中心没有收到心跳,就会将对应的服务实例的健康状态改为false,达到30秒没有收到心跳就会将其从注册中心剔除
nacos和eureka的区别?
我们当时xx项目就是采用的nacos作为注册中心,选择nacos还要一个重要原因就是它支持配置中心,不过nacos作为注册中心,也比eureka要方便好用一些,主要相同不同点在于几点:
- 共同点
- Nacos与eureka都支持服务注册和服务拉取,
- 都支持服务提供者心跳方式做健康检测
- Nacos与Eureka的区别
- Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
- Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
- Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
负载均衡
你们项目中负载均衡如何实现的?
在服务调度过程中的负载均衡我们使用的是Spring Cloud的Ribbon组件实现的,Feign底层已经自动集成了Ribbon,使用起来非常简单,当发起远程调用时,Ribbon先从注册中心拉取服务地址列表,然后按照路由策略原则一个发起远程调用,我们使用的调用策略是轮询
Ribbon的负载均衡策略有哪些?
- RoundRobinRule:简单轮询服务列表来选择服务器
- WeightedResponseTimeRule:按照权重来选择服务器,响应时间越长,权重越小
- RandomRule:随选择一个可用的服务器
- BestAvailableRule:忽略那些短路的服务器,并选择并发数较低的服务器
- RetryRule:重试机制的选择逻辑
- AvailabilityFilteringRule:可用性敏感策略,先过滤非健康的,再选择连接数较小的实例
- ZoneAvoidanceRule:以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询
如果想自定义负载均衡策略如何实现?
提供了两种方式:
- 创建类实现Rule接口,可以指定负载均衡策略,这个是全局的,对所有的远程调用都起作用
- 在客户端的配置文件中,可以配置某一个服务调用的负载均衡策略,只是对这个服务生效
熔断,降级
什么是服务雪崩,怎么解决这个问题?
服务雪崩是指一个服务失败,导致整条链路的服务都失败的情形,一般我们项目中有两种解决方案,第一种是服务降级,第二种是服务熔断,如果流量太大可以考虑限流.
服务降级就是服务自我保护的一种方式,也是保护下游服务的一种方式,用于确保服务不会受请求突增影响变得不可用,确保服务不会崩溃,一般实际开发中与feign接口整合,编写降级逻辑
服务熔断是默认关闭的,需要手动打开,如果检测到10秒内请求的失败率达到50%,就会触发熔断机制,之后每隔5秒尝试请求微服务,就是半开状态放行一条请求,如果微服务不响应,继续走熔断机制,如果微服务可以访问,就关闭熔断机制,恢复正常请求
服务降级是针对一个接口的,是部分服务受到限制,服务熔断是针对整个服务的
监控
为什么需要监控?
- 问题定位
- 性能分析
- 服务关系
- 服务告警
监控工具: - Springboot-admin
- prometheus+Grafana
- zipkin
- skywalking
补充概念 - 服务(service)–业务资源应用系统(微服务)
- 端点(endpoint)–应用系统对外暴露的功能接口(接口)
- 实例(instance)–物理机
你们的微服务是怎么监控的?
我们项目中采用的skywalking进行监控的
1,skywalking主要可以监控接口、服务、物理实例的一些状态。特别是在压测的时候可以看到众多服务中哪些服务和接口比较慢,我们可以针对性的分析和优化
2,我们还在skywalking设置了告警规则,特别是在项目上线以后,如果报错,我们分别设置了可以给相关负责人发短信和发邮件,第一时间知道项目的bug情况,第一时间修复
限流
为什么要限流?
- 并发的确大(突发流量)
- 防止用户恶意刷接口
限流的突发方式: - Tomcat–可以设置最大连接数
- Nginx,漏桶算法
- 网关,令牌桶算法
- 自定义拦截器
Nginx限流–漏桶算法方式一:
控制速率(突发流量)
方式二:
控制并发连接数
网关限流–令牌算法
你们项目中有没有做过限流?怎么做的?
1,先来介绍业务,什么情况下去做限流,需要说明QPS具体多少
- 我们当时有一个活动,到了假期就会抢购优惠券,QPS最高可以达到2000,平时10-50之间,为了应对突发流量,需要做限流
- 常规限流,为了防止恶意攻击,保护系统正常运行,我们当时系统能够承受最大的QPS是多少(压测结果)
2,nginx限流
- 控制速率(突发流量),使用的漏桶算法来实现过滤,让请求以固定的速率处理请求,可以应对突发流量
- 控制并发数,限制单个ip的链接数和并发链接的总数
3,网关限流
- 在spring cloud gateway中支持局部过滤器RequestRateLimiter来做限流,使用的是令牌桶算法
- 可以根据ip或路径进行限流,可以设置每秒填充平均速率,和令牌桶总容量
限流常见的算法有哪些呢?
比较常见的限流算法有漏桶算法和令牌桶算法
漏桶算法是把请求存入到桶中,以固定速率从桶中流出,可以让我们的服务做到绝对的平均,起到很好的限流效果
令牌桶算法在桶中存储的是令牌,按照一定的速率生成令牌,每个请求都要先申请令牌,申请到令牌以后才能正常请求,也可以起到很好的限流作用
它们的区别是,漏桶和令牌桶都可以处理突发流量,其中漏桶可以做到绝对的平滑,令牌桶有可能会产生突发大量请求的情况,一般nginx限流采用的漏桶,spring cloud gateway中可以支持令牌桶算法
分布式事务
什么是分布式事务
在微服务架构中,不同的服务通常分布在多个服务器上,它们之间需要相互协调完成一系列操作,这就涉及到了分布式事务问题。分布式事务指的是跨越多个服务的事务操作,它需要保证所有服务的操作要么全部执行成功,要么全部回滚,以确保数据的一致性和完整性
什么是CAP理论?
CAP主要是在分布式项目下的一个理论.CAP就是Consistency(一致性),Availability(可用性),Partition tolerance(分区容错性)首字母的缩写.
一致性是指更新操作成功并返回客户端完成后,所有节点在同一时间的数据完全一致(强一致性),不能存在中间状态
可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果
分区容错性是指分布式系统在遇到任何网络分区故障时,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障
为什么分布式系统中无法同时保证一致性和可用性?
分布式系统无法同时满足三个条件,原因在于:
首先一个前提,对于分布式系统而言,分区容错性是一个最基本的要求,因此基本上我们在设计分布式系统的时候只能从一致性(C)和可用性(A)之间进行取舍。如果保证了一致性(C):对于节点N1和N2,当往N1里写数据时,N2上的操作必须被暂停,只有当N1同步数据到N2时才能对N2进行读写请求,在N2被暂停操作期间客户端提交的请求会收到失败或超时。显然,这与可用性是相悖的。如果保证了可用性(A):那就不能暂停N2的读写操作,但同时N1在写数据的话,这就违背了一致性的要求。
什么是BASE理论?
BASE理论是对CAP的一种解决思路,核心思想是即使无法做到强一致性(StrongConsistency,CAP的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性(EventualConsitency)。它的思想包含三方面:
1、BasicallyAvailable(基本可用):基本可用是指分布式系统在出现不可预知的故障的时候,允许损失部分可用性,但不等于系统不可用
2、Softstate(软状态):即是指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时
3、Eventuallyconsistent(最终一致性):强调系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。其本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性
如何使用seata解决分布式事务
- 部署SeataTC端,TC端可以统一管理全局事务
- 微服务整合Seata
- 引入seata依赖,我们使用的版本是1.4.2
- 配置seataTC端地址配置事务模式Seata支持4种模式XA AT TCC SAGA
- 在需要管理全局事务的方法上加注解:@GlobalTransactional
seata的工作原理
Seata的AT模式采用的是两阶段提交(2pc)
@GlobalTransactional注解标记的方法被调用后,全局事务被触发,
整个事务采用2PC实现阶段一:执行每一个分支事务,每个分支事务执行时,seata会解析sql根据sql中的where条件和表生成select语句先查询出修改前的数据,称为前镜像数据然后执行业务sql执行完毕后,在select查询后置镜像将前后镜像的数据存入到undolog回滚日志表中,然后上报分支事务的执行状态。接着调用下一个分支事务
待所有分支事务执行完毕后,执行第二阶段
阶段二:
第二阶段有两种情况:
1.第一阶段的所有分支事务都执行成功,那么第二阶段只需要删除对应的undolog日志即可
2.第一阶段只要有一个环节失败,那么第二个阶段需要根据执行成功的分支事务ID找到对应的undolog日志内容,判断当前数据是否和后镜像存储的内容一致,如果一致将数据改为前镜像的内容
(细节:如果不一致直接改,容易产生脏数据
细节:seataAT模式要求必须依赖关系型数据库必须是java项目
细节:Seata存在脏读问题,可以通过在语句后加入forupdate解决
细节:Seata不存在脏写问题,通过seata中的全局锁解决不过全局锁会产生阻塞影响性能)
注意使用seaata时,sql有限制
不支持SQL嵌套
不支持多表复杂SQL(自1.6.0版本,MySQL支持UPDATEJOIN语句,详情请看)
不支持存储过程、触发器
部分数据库不支持批量更新,在使用MySQL、Mariadb、PostgreSQL9.6+作为数据库时支持批量,批量更新
不支持tinyint(1)字段
你们采用哪种分布式事务解决方案?
我们当时是xx项目,主要使用到的seata的at模式解决的分布式事务
seata的AT模型分为两个阶段:
1、阶段一RM的工作:①注册分支事务②记录undo-log(数据快照)③执行业务sql并提交④报告事务状态
2、阶段二提交时RM的工作:删除undo-log即可
3、阶段二回滚时RM的工作:根据undo-log恢复数据到更新前at模式牺牲了一致性,保证了可用性,不过,它保证的是最终一致性
seata事务管理中三个重要的角色TC(TransactionCoordinator)事务协调者:维护全局和分支事务的状态,协调全局事务提交或回滚
TM(TransactionManager)事务管理器:定义全局事务的范围、开始全局事务、提交或回滚全局事务
RM(ResourceManager)资源管理器:管理分支事务处理的资源,与TC交谈以注册分支事务和报告分支事务的状态,并驱动分支事务提交或回滚
seata的XA模式–CP/需要相互等待各个分支事务提交,可以保证强一致性,性能差/银行业务
seata的AT模式–AP/底层使用undo log实现,性能好,推荐使用/互联网业务
seata的TCC模式–性能较好,不过需要人工编码实现/银行业务
MQ模式–在A服务写数据的时候,需要在同一个事务内发送消息大另一个事务,异步,性能最好/互联网业务
分布式服务的接口幂等性如何设计?
幂等:多次调用方法或接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致
方案
- 数据库唯一索引–新增
- token+redis–新增, 修改
- 分布式锁–新增, 修改
嗯,我们当时有一个xx项目的下单操作,采用的token+redis实现的,流程是这样的:
第一次请求,也就是用户打开了商品详情页面,我们会发起一个请求,在后台生成一个唯一token存入redis,key就是用户的id,value就是这个token,同时把这个token返回前端
第二次请求,当用户点击了下单操作会后,会携带之前的token,后台先到redis进行验证,如果存在token,可以执行业务,同时删除token;如果不存在,则直接返回,不处理业务,就保证了同一个token只处理一次业务,就保证了幂等性
分布式任务调度
xxl-job解决的问题:
- 解决集群任务的重复执行问题
- cron表达式定义灵活
- 定时任务失败了,重试和统计
- 任务量大,分片执行
分布式调度在项目中的应用场景:
- 定时修改支付状态
- 定时匹配运输任务
- 定时重新发送失败的消息
为什么选择xxl-job
XXL-Job是一个分布式任务调度平台,可以用于定时任务和任务调度等场景。以下是XXL-Job框架的几个优点:
分布式:XXL-Job支持分布式部署,可以轻松应对高并发和大量任务的情况。
可视化管理:XXL-Job提供了Web界面,可以方便地查看任务状态、日志等信息,也可以通过图形化界面进行任务配置和管理。
执行器灵活:XXL-Job的执行器支持多种语言,如Java、Python、Shell等,可以满足不同项目的需求。
容错性强:当任务出现故障或者节点失效时,XXL-Job会自动重试、重新调度,确保任务的正常执行。
稳定性高:XXL-Job经过阿里云的生产环境严格测试和验证,稳定性和可靠性得到了很好的保证。
易于集成:XXL-Job提供了丰富的API接口和开源代码,可以简单快速地集成到项目中。
综上所述,XXL-Job是一个功能实用、易用、可靠、稳定、灵活且容错性强的分布式任务调度平台
xxl-job是如何通信的
xxljob服务端与客户端通信是通过nety搭建的通信服务器,基于的协议是http协议所以当我们的微服务配置的xxljob执行器需要单独设置端口号
xxl-job具体如何使用
- 执行器根据配置的调度中心的地址,自动注册到调度中心
- 达到任务触发条件,调度中心下发任务
- 执行器基于线程池执行任务,并把执行结果放入内存队列中,把执行日志写在日志文件中
- 执行器的回调线程消费内存队列中的执行结果,主动上报给调度中心5.当用户在调度中心查看任务日志,调度中心请求任务执行器,任务执行去读取任务日志并返回日志详情
xxl-job的工作原理
XXL-Job的工作原理主要分为两个部分:调度中心和执行器。
调度中心负责任务的管理、调度和监控,执行器负责任务的具体执行。
具体来说,XXL-Job的工作流程如下:
开发人员在XXL-Job的管理界面上创建任务,并设置定时规则和执行器信息等相关参数。
调度中心将任务信息保存在数据库中,并生成执行计划。当到达任务的执行时间时,调度中心会根据任务的执行计划选择一个合适的执行器进行任务的执行,同时记录任务的执行情况。
执行器在执行任务前会向调度中心获取任务信息,并执行具体的任务逻辑。任务执行完毕后,执行器会将执行结果上传到调度中心,并更新任务的状态。
如果任务执行失败,调度中心会记录失败信息,并根据任务的重试次数和重试间隔重新调度任务。
调度中心提供了丰富的Web界面和API接口,可以方便地查询和管理任务的执行情况。
总之,XXL-Job通过调度中心和执行器协作的方式,实现了对任务的灵活调度、管理和监控,保证了任务的准确性和可靠性
xxl-job版本号
2.3.0版本
xxl-job路由策略有哪些?
路由策略
- FIRST(第一个):固定选择第一个机器;
- LAST(最后一个):固定选择最后一个机器
- ROUND (轮询)
- RANDOM(随机):随机选择在线的机器
- CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上
- LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的机器优先被选举
- LEAST_RECENTLY_USED(最近最久未使用):最久未使用的机器优先被选举
- FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度
- BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度
- SHARDING_BROADCAST(分片广播):广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务;
xxl-job提供了很多路由策略,我们使用较多的就是–轮询,故障转移,分片广播
xxl-job任务执行失败怎么解决?
第一:路由策略选择故障转移,优先使用健康的实例来执行任务
第二,如果还有失败的,我们在创建任务时,可以设置重试次数
第三,如果还有失败的,就可以查看日志或者配置邮件告警来通知相关负责人解决
如果有大数据量的任务同时都需要执行,怎么解决?
我们会让部署多个实例,共同去执行这些批量的任务,其中任务的路由策略是分片广播
在任务执行的代码中可以获取分片总数和当前分片,按照取模的方式分摊到各个实例执行就可以了