1.请说说你用过Spring Cloud哪些组件?这些组件分别有什么作用?
1、注册中心:Eureka、Nacos、Zookeeper、Consul;(服务注册)
2、负载均衡:Ribbon、LoadBalancer;(客户端的负载均衡)
3、服务调用:Feign、OpenFeign、Dubbo RPC;(优雅调用远程服务)
4、配置中心:Spring Cloud Config、Nacos;(统一管理服务配置)
5、熔断降级:Hystrix、Sentinel;(急骤请求,防止服务雪崩)
6、分布式事务:Seata (跨库跨服务的事务管理)
7、服务网关:Zuul 1.x、Zuul 2.x、Spring Cloud Gateway;(系统入口门面)
8、链路追踪:Skywalking、Zipkin;(监控服务状态、协助排查问题)
2.谈谈你对Spring Cloud的理解?
1、微服务开发需要解决各类问题,比如:负载均衡,服务的注册与发现,服务调用,服务路由,服务熔断等等一系列问题;
2、在没有Spring Cloud之前,我们需要自己寻找各种组件并进行集成来解决一系列微服务场景下的问题,有了Spring Cloud,它帮我们把微服务面临的各类技术问题全部打包好了,我们只需要开箱即用;
3、Spring Cloud最大的贡献是为开发人员提供了一整套集成好的微服务解决方案,不再需要开发人员自行集成各类组件解决不同问题,降低了微服务开发难度,Spring Cloud提供了统一标准,功不可没;
4、Spring Cloud在天下大乱,群雄并起中,实现了一统天下;
5、Spring Cloud的出现,也为Spring生态注入了更强大的生命力;
3.什么是服务熔断?什么是服务降级?有什么区别?
服务熔断,当服务A调用服务B时,如果此时服务B不可用,那么上游的服务A为了保证自己不受影响,就切断调用服务B,防止发生服务雪崩,直到B服务恢复;
提前做好一种兜底措施,比如返回假的数据,或者记录数据信息到数据库、redis、文件中,后续进行补救,直到B服务恢复;
服务降级,当系统负载过高时,对非核心的业务服务进行关闭,来保证核心业务的正常运行; 关闭某些不重要的服务,或者拒绝低优先级应用的服务请求,保证核心应用正常工作;
相同: 目的相同,都是为了保证服务的可用性,防止系统整体负载过大甚至崩溃; 表现相同,都是表现出服务暂时不可用的状态;
不同: 触发原因不同,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;
4.你之前的项目运行得好好的,为什么项目重构时要对系统进行拆分呢?
1、项目随着业务功能的增加,功能模块增多,业务复杂度增大,代码量也增加,在多人团队中,各开发人员为了实现自己的功能,有时候经常需要修改另一个开发人员的代码,经常会出现代码的冲突;
2、一个地方的功能修改经常导致另外一个地方的功能出现异常;
3、每次一个小小的修改,都需要测试团队对很多功能进行测试,效率非常低,测试团队也充满抱怨;
4、每次新增新的需求,开发效率都比较低下,由于所有功能都在一个项目中,导致业务代码逻辑变得非常复杂,经常陷入牵一发动全身的状态,团队成员也不敢轻易修改代码,响应新需求的速度低;
5、由于所有功能在一个项目中,代码量极大,代码的可读性可维护性可扩展性都变得很差,也导致团队成员不稳;
6、出现一些更好的新技术,也不敢轻易升级技术,升级非常困难,升级可能产生各种问题,调试和测试会消耗大量的时间和精力,团队生成力极低;
7、项目迭代上线效率低,每次上线,全体成员,技术团队、测试团队、运维团队都需要加班加点,而且常常都是胆战心惊的;
一个几百万行、几十万行代码的系统拆分成几百个、几十个服务,每个服务就只有1~2万行代码,每个服务由1~2人负责,每个人专注自己的服务维护;
1、不会出现代码冲突;
2、代码逻辑变简单了,代码变清晰了;
3、测试也变得容易了;
4、响应新需求的速度也提升了;
5、升级新技术也变容易了;
6、上线发布也变容易了;
5.Eureka和Nacos都可以做注册中心,它们有什么区别?
注册中心:Eureka、Nacos、Zookeeper、Apollo、Consul;
相同点:
1、都用于服务的注册和发现;
2、都支持服务的心跳健康检查;
3、都支持高可用;
不同点:
1、Nacos支持主动对微服务状态检测,Nacos临时实例采用心跳检测,永久实例采用主动检测;
2、Nacos临时实例心跳检测不正常会从注册中心删除,永久实例不会删除;
3、Nacos支持服务列表变更时的主动消息推送,服务列表更新会更及时;
4、Nacos集群支持两种模式,默认采用AP模式,当集群中存在非临时实例时,采用CP模式,而Eureka只能采用AP模式;
5、Nacos支持注册中心、配置中心,Eureka只支持注册中心;
6、Nacos具备服务优雅上下线和流量管理,而Eureka的后台页面仅供展示,需要使用api操作上下线且不具备流量管理功能;
7、Nacos社区活跃,Eureka已经闭源了;
6. ACID、BASE理论、CAP理论的关系?
1.ACID 是传统数据库中常用的设计理念;
1、Atomicity (原子性)
保证1-6所有步骤要么都执行,要么都不执行,一旦在执行某一步骤的过程中发生异常,就需要执行回滚操作。比如执行到第五步时,B账户突然不可用(比如被冻结或其他原因不可用),那么之前的所有操作都应该回滚到执行事务之前的状态;
2、Consistency (一致性)
在转账之前,A和B的账户中共有1000+1000=2000元钱,在转账之后,A和B的账户中共有900+1100=2000元。即数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态,并保证数据在业务意义上是正确的;
3、Isolation (隔离性)
隔离性是指当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行,也就是多个事务之间貌似是排队进行的。
4、Durability (持久性)
一旦转账成功(事务提交),两个账户中的金额就会发生真实变化(会把数据写入数据库持久化保存,也就是永久的保存),这就是持久性;
当然在实际应用场景中一个节点属于单点故障,所以需要增加多个副本(replica)一起来保证持久;如果做得更加完善,可以在不同地理位置的另一个数据中心做备份。
ACID它追求的是数据的强一致性模型。
2.BASE理论支持的是大型分布式系统;
1、基本可用 (Basically Available)
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性;
2、软状态 (Soft State)
软状态指允许系统中的数据存在中间状态,允许系统在不同节点的数据副本之间进行数据同步的过程存在延时;
3、最终一致性 (Eventually Consistent)
最终一致性强调的是所有的数据副本,在经过一段时间的同步之后,最终都能够达到一致的状态,而不需要实时保证系统数据的强一致;
BASE理论它是通过牺牲强一致性以获得高可用性。
3.CAP理论是支持分布式系统而提出的;
1、C 一致性(Consistency)
分布式系统中,所有节点的数据或状态在任何时刻都是一致的;
2、A 可用性(Availability)
分布式系统中,任何时刻都能够处理请求,都处于可用的状态;
3、P 分区容错性(Tolerance of network Partition)
分布式系统中,在遭遇网络故障时仍能继续正常工作;
分布式系统无法做到CAP,只能做到其中两项,要么CP,要么AP;
总结:
ACID它追求的是数据的强一致性;
CAP理论是分布式系统在一致性、可用性、分区容错性三个方面必须要做出的取舍,它针对的是互联互通并共享数据的分布式系统的读和写操作;
BASE理论是对CAP理论的延伸和补充,它是通过牺牲强一致性以获得高可用性,虽然存在中间状态,但数据最终一致;
ACID 和 CAP、BASE 代表了两种截然相反的设计哲学;
在分布式系统设计中,根据不同场景的实际情况,可以把 ACID、CAP(AP、CP)、BASE 结合起来使用;
7.注册中心应该选择CP还是AP?
CP:
如果选择CP(一致性),当我们向注册中心注册实例或删除实例时,都需要等待注册中心集群中的数据达到一致后才算注册或删除成功,在同步数据时,影响服务发现及服务调用;随着应用规模增大,应用实例频繁注册或删除,必将影响注册中心服务注册与发现的效率; AP:
如果选择AP(可用性),注册中心集群各节点不管数据是否同步一致了都可以提供服务,优先保证服务可用性,比如拉取到了一个已经下线了的服务节点,但是微服务框架一般都提供了服务容错和重试功能,也影响不大,对于注册中心而言不需要消耗时间和资源来实时地保证数据一致性,保证最终一致性即可,这样将减轻注册中心的压力,提升注册中心服务注册与发现的效率;
8.什么是接口幂等性?哪些场景需要幂等性?如何设计来保证接口幂等性?
幂等,英文idempotent [aɪ'dɛmpətənt]
幂等这个词源自数学,是数学中的一个概念,常见于抽象代数中,表达的是N次变换与1次变换的结果相同,在计算机的各个领域都借用了该概念;
幂等函数或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数;
简单来说就是如果方法调用一次和多次产生的效果是相同的,不会导致系统数据出错,那么它就具有幂等性;
幂等性衍生到我们系统中, 它的语义是指函数/接口可以使用相同的参数重复执行, 不应该影响系统状态, 也不会对系统造成改变;
也就是任意多次执行所产生的影响均与一次执行所产生的影响相同;
如果用户对同一操作发起的一次请求或多次请求所产生的影响是一样的,不会因为多次调用(点击)而产生了副作用,那么这就是幂等的;
第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用,这里的副作用是指不会对结果产生破坏或者产生不可预料的结果; 即 幂等性 = 多次执行无副作用;
1、因网络波动,可能会引起重复请求;
2、用户重复操作,用户可能会无意的触发多次下单多次交易,甚至没有响应而有意触发多笔交易;
3、应用使用了失败或超时重试机制(如RPC重试、业务层重试等)
4、第三方平台的接口(如:支付成功回调接口),因为异常导致多次回调;
5、中间件/应用服务根据自身的特性,也有可能进行重试;
6、用户双击提交按钮;
7、用户页面重复刷新;
8、使用浏览器后退按钮重复之前的操作,导致重复提交表单;
9、使用浏览器历史记录重复提交表单;
10、浏览器重复的HTTP请求;
11、定时任务重复执行;
1、使用唯一索引防止幂等性问题
此方案可以限制重复插入数据,当数据重复时,插入数据库会抛异常,保证不会出现脏数据,这也是一种简单粗暴的办法;
2、Token+Redis的幂等方案
这种方式分成两个阶段:申请token阶段和业务操作阶段; 以支付为例: 第一阶段,在进入到提交订单页面之前,需要订单系统根据用户信息向支付系统发起一次申请token的请求,支付系统将token保存到Redis缓存中,为第二阶段支付使用; 第二阶段,订单系统拿着申请到的token发起支付请求,支付系统会检查Redis中是否存在该token,如果存在,表示第一次发起支付请求,开始支付逻辑处理,处理完逻辑后删除redis中的token; 当重复请求时候,检查缓存中token不存在,表示非法请求;
3、防重表实现幂等性 需要增加一个表,这个表叫做防重表(防止数据重复的表) 使用唯一主键去做防重表的唯一索引,比如使用订单号orderNo做为防重表的唯一索引,每次请求都根据订单号向去重表中插入一条数据,第一次请求查询订单支付状态,当然订单没有支付,然后进行支付操作,支付前先向防重表中插入该支付的订单号,插入成功说明可以支付,然后进行支付操作,支付操作执行完后更新订单状态为成功或失败或其他状态,然后再删除防重表中的数据,所以在支付的过程中,另一个请求如果也请求支付则因为防重表中唯一索引而插入失败,则返回操作失败,直到第一次的请求操作完成(成功或失败),可以看出防重表作用是加锁的功能;(基于数据库的分布式锁)
9.你在项目中是否遇到分布式事务问题,分布式事务怎么解决?
常见的分布式解决方案:
1、2PC;
2、3PC;
3、TCC;
4、本地消息异步确认;
5、可靠消息最终一致性;
6、最大努力通知;
7、RocketMQ解决分布式事务;
8、阿里巴巴的Seata解决分布式事务;
10.分布式环境下如何进行服务的限流?
计数器法
它是限流算法中最简单粗暴,也最容易的一种算法,比如我们要求某一个接口1分钟内的请求不能超过60次,我们可以在开始时设置一个计数器,每次请求,该计数器+1;如果该计数器的值大于60并且与第一次请求的时间间隔在1分钟内,那么说明请求过多,如果该请求与第一次请求的时间间隔大于1分钟,并且该计数器的值还在限流范围内,那么重置该计数器;
漏桶算法
维基百科:https://en.wikipedia.org/wiki/Leaky_bucket 漏桶算法的思路,水(请求)先进入到漏桶里,漏桶以恒定的速度流出,当水流入速度过大会直接溢出,可以看出漏桶算法能强行限制数据的传输速率。
有一个固定容量的漏桶,按照常量固定速率流出水滴; 如果漏桶是空的,则不需流出水滴; 可以以任意速率流入水滴到漏桶; 如果流入水滴超出了桶的容量,则流入的水滴溢出了(也就是请求被丢弃),而漏桶容量是不变的。
令牌桶算法
维基百科:https://en.wikipedia.org/wiki/Token_bucket 令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。
Guava框架提供了令牌桶算法实现(Google),可直接拿来使用,使用 Guava框架的RateLimiter类即可创建一个令牌桶限流器,比如设置每秒放置令牌数为5个,那么RateLimiter对象就可以保证1秒内不会放入超过5个令牌,并且以固定速率进行放置令牌,达到平滑输出的效果。
1、Nginx 限流; Nginx中使用ngx_http_limit_req_module模块来限制的访问频率,在nginx.conf配置文件中可以使用limit_req_zone命令及limit_req命令限制请求速率; limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s; limit_req_zone $server_name zone=perserver:10m rate=2r/s;
2、OpenResty 限流;
3、Sentinel 限流;
4、Redis+Lua 限流;
5、Spring Cloud Gateway 限流;