分布式与微服务
1.zookeeper是什么
zookeeper是一个开源的分布式协调服务,主要目标是提供一个可靠的、高性能的分布式协调服务,以帮助应用
程序处理分布式环境中的一些常见问题,如:
(1)注册中心 : zookeeper可用于注册和发现分布式系统中的服务,使得应用程序能够通过名称找到所需的
服务
(2)配置中心 : zookeeper可用于集中管理配置信息,应用程序可以在需要时动态获取配置变更通知
(3)分布式锁 : zookeeper提供了基于分布式锁的原语,使得多个进程或线程可以协调访问共享资源,以
避免竞争条件
(4)分布式选举 : zookeeper提供了选举算法,用于在分布式系统中选举出一个主节点以协调整个系统的
操作
(5)分布式同步 : zookeeper可用于实现分布式应用程序中的同步需求,例如控制顺序和时间相关的操作
2.zookeeper保证数据一致性
强一致性 : 确保系统的每个操作都会对所有节点产生相同的结果,保证了数据的强一致性
弱一致性 : 系统中的节点可能在不同的时间看到不同的数据,系统不会保证操作立即传播到所有节点,可以
提高系统的性能和可用性,需要开发者设计自己的逻辑处理数据不一致的情况
最终一致性 : 介于强一致性和弱一致性之间,它允许在一段时间内存在数据不一致,但最终在没有新的更新
的情况下,系统最终会达到一致状态
3.zookeeper的快速领导者选举是怎么实现的
当集群中的 leader 节点出现故障或者需要重新选举时,就会触发快速领导者选举过程
1.当集群中的 leader 节点发生故障、崩溃无法通信时,其余节点会触发领导者选举,每个节点都可以成为
候选者
2.当一个节点决定参与选举时,它首先会将自己的信息(选举编号等)广播给其他节点,并将自己的状态设置
为候选者
3.集群中的每个节点收到候选者的选举请求后,会比较候选者的选举编号(通常是一个递增的序列号)和自己的
选举编号。如果候选者的编号较大,那么该节点就会将自己的选票投给候选者,并将自己的状态设置为投票
给候选者
4.在快速领导者选举中,需要满足"大多数投票原则"。意味着候选者需要获得集群中超过一半节点的选票才能
成为新的 leader
5.如果候选者获得了超过一半节点的选票,那么它将成为新的 leader,并会广播自己的信息以通知其它节点。
其它节点在收到新的 leader 的通知后,会更新自己的状态以反映当前的 leader
6.如果没有候选者获得做够多的选票,那么选举失败。这时候通常会出发新一轮的选举尝试,直到某个节点
获得足够多的选票为止
4.CAP理论
C(一致性):即更新操作成功并返回客户端,所有节点在同一时间的数据完全一致。
对于客户端来说,一致性指的是并发访问时更新过的数据如何获取的问题
从服务端来看,则是更新如何复制分布到整个系统,以保证数据最终一致
A(可用性):即服务一直可用,而且是正常响应时间。
系统能够很好的为用户服务,不出现用户操作失败或者访问超时等用户体验不好的情况
P(分区容错性):即分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供一致性和可用性的服务。
分区容错性要求能够使应用虽然是一个分布式系统,而看上去却好像是在一个可以运转的正常
整体。
比如现在的分布式系统中有一个或者几个机器宕机了,其它剩下的机器还能够正常运转满足
系统需求,对于用户而言并没有什么体验上的影响
CP和AP:分区容错是必须保证的,当发生网络分布区的时候,如果要继续服务,那么强一致性和可用性只能
二选一
5.BASE理论
BASE是 Basically Avaliable(基本可用)、Soft state(软状态)、Eventually consistent(最终
一致性)
BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于
CAP定理逐步演化而来的。
BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使
系统达到最终一致性
基本可用:
响应时间上的损失:正常情况下,处理用户请求需要0.5s返回结果,但是由于系统出现故障,处理
用户请求的时间变长
系统功能上的损失:正常情况下,用户可以使用系统的全部功能,但是由于系统访问量突然剧增,系
统的部分非核心功能无法使用
软状态:数据同步允许一定的延迟
最终一致性:系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态,不要求实时
6.分布式id生成方案
(1)UUID
利用:
当前日期和时间 时间戳
时钟序列 计数器
全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其它方式获得
来生成UUID
优点:a.代码简单
b.性能好(本地生成,没有网络消耗)
c.保证唯一(相对而言,重复概率极低可以忽略)
缺点:a.每次生成的ID都是无序的,而且不是全数字,且无法保证趋势递增
b.UUID生成的是字符串,字符串存储性能差,查询效率慢,写的时候由于不能产生顺序的append操作,
需要进行insert操作,导致频繁的页分裂,这种操作在记录占用空间比较大的情况下,性能下降比较
大,还会增加读取磁盘的次数
c.UUID长度过长,不适用于存储,耗费数据库性能
d.ID无一定业务含义,可读性差
e.有信息安全问题,有可能泄露mac地址
(2)数据库自增序列
单机模式:
优点:实现简单,依靠数据库即可,成本小
ID数字化,单调递增,满足数据库存储和查询性能
具有一定的业务可读性(结合业务code)
缺点:强依赖数据库,存在单点问题,如果数据库宕机,则业务不可用
数据库生成ID性能有限,单点数据库压力大,无法抗高并发场景
信息安全问题,比如暴露订单量,url查询改一下id就可以查到别人的订单
数据库高可用:多主模式做负载,基于序列的起始值和步长:设置不同的初始值和相同的步长,步长大于节点数
优点:解决了ID生成的单点问题,同时平衡了负载
缺点:系统扩容困难:系统定义好步长之后,增加机器之后调整步长困难
数据库压力大:每次获取一个ID都必须独写一次数据库
主从同步的时候:因为数据同步延迟导致查询不到刚插入的数据。可以在数据要求比较严谨的时候直接
查主库
(3)Leaf-segment
采用每次获取一个ID区间段的方式来解决,区间段用完之后再去数据库获取新的字段,这样的话可以大大减轻
数据库的压力
核心字段:biz_tag,max_id,step
biz_tag:用来区分业务
max_id:表示该biz_tag目前所被分配的ID号段的最大值
step:表示每次分配的号段长度,原来每次获取ID都要访问数据库,现在只需要把step设置的足够合理,就
只需要在当前号段ID都用完之后再去访问数据库
优点:扩张灵活,性能强能撑起大部分业务场景
ID号码是趋势递增的,满足数据库存储和性能要求
可用性高,即使ID生成服务器不可用,也能够使得业务在短时间内可用
缺点:可能存在多个节点同时请求ID区间的情况,依赖数据库
双buffer:将获取一个号段的方式优化成获取两个字段,在一个号段用完之后不用立马去更新字段,还有一个
缓存号段备用,这样能够有效解决这种冲突问题,而且采用双buffer的方式,在当前号段消耗了
10%的时候就去检查下一个号段有没有准备好,如果没有准备好就去更新下一个号段,当当前号段
用完了就切换到下一个已经缓存好的号段去使用,同时在下一个号段消耗到10%的时候,又去检测
下一个号段有没有准备好,如此往复
优点:基于JVM存储双buffer的号段,减少了数据库查询,减少了网络依赖,效率更高
缺点:segment号段长度是固定的,业务量大时可能会频繁更新号段,因为原本分配的号段会一下用完
如果号段长度设置过长,但凡缓存中有号段没有消耗完,其它节点重新获取的号段会与之前相比可能
跨度会很大 需要动态调整step
(4)雪花算法
生成一个64bit的整型数字
第一位固定为0,41位时间戳,10位workId,12位序列号
位数可以有不同实现
优点:每个毫秒值包含的ID值很多,不够可以变动位数来增加,性能佳
时间戳值在高位,中间是固定的机器码,自增的序列在低位,整个ID是趋势递增的
能够根据业务场景数据库节点布置灵活bit位划分,灵活度高
缺点:强依赖于机器时钟,如果时钟回拨,会导致重复的ID生成,所以一般基于此的算法发现时钟回拨,都会
抛出异常处理,阻止ID生成,这可能导致服务不可用
7.分布式缓存寻址算法
1.hash算法:根据key进行hash函数运算、结果对分片数取模,确定分片
优点:适合固定分片数的场景
缺点:扩展分片或者减少分片时,所有数据都需要重新计算分片、存储
2.一致性hash:将整个hash值的区间组织成一个闭合的圆环,计算每台服务器的hash值、映射到圆环中。
使用相同的hash算法计算数据的hash值,映射到圆环,顺时针寻找,找到的第一个服务器就是
数据存储的服务器
优点:新增及减少节点时,只会影响节点到他逆时针最近的一个服务器之间的值
缺点:存在hash环倾斜的问题,即服务器分布不均匀,可以通过虚拟节点解决
3.hash slot:将数据与服务器隔离开,数据与slot映射,slot与服务器映射,数据进行hash决定存放的
slot。新增及删除节点时,将slot进行迁移即可
8.分布式架构下的session共享方案
1.采用无状态的服务,比如 token
2.服务器之间进行 session 同步,这样可以保证每个服务器上都有全部的 session 信息,不过当服务器
数量比较多的时候,同步是会有延迟甚至同步失败
3.IP绑定策略,使用 Nginx(或其它负载均衡软件) 中的IP绑定策略,同一个IP只能在指定的同一个机器
访问,但是这样做就失去了负载均衡的意义,当挂掉一台服务器时,会影响一批用户,风险很大
4.使用 redis 存储
把 session 放到 redis 中存储,虽然架构上变得复杂,并且需要多访问一次 redis,但是这种方案
带来的好处也很大
实现了 session 共享
可以水平扩展
服务器重启 session 不丢失
不仅可以跨服务器 session 共享,甚至可以跨平台
9.分布式事务解决方案
XA规范:分布式事务规范,定义了分布式事务模型
四个角色:事务管理器(协调者TM)、资源管理器(参与者RM)、应用程序AP、通信资源管理器CRM
全局事务:一个横跨多个数据库的事务,要么全部提交、要么全部回滚
JTA事务是java对XA规范的实现,对应JDBC的单库事务
(1)两阶段协议
第一阶段:
发送prepare消息(基本完成sql语句操作),但未提交事务
每个参与者执行本地事务但不提交,进入ready状态,并通知协调者已经准备就绪
第二阶段:
如果阶段一所有prepare操作成功/失败,则通知所有库提交事务/回滚事务
当协调者确认每个参与者都ready后,通知参与者进行commit操作;如果有参与者fail,则发送回滚命令,
各参与者做回滚
问题:
单点故障:一旦事务管理器出现故障,整个系统不可用(参与者都会阻塞住)
数据不一致:在阶段二,如果事务管理器只发送了部分commit消息,此时网络发生异常,那么只有部分参与者
收到commit消息,只有部分参与者提交了事务,使得系统数据不一致
响应时间较长:参与者和协调者资源都被锁住,提交或者回滚之后才能释放
不确定性:当事务管理器发送commit之后,并且此时只有一个参与者收到了commit,那么当该参与者与事务
管理器同时宕机之后,重新选举的事务管理器无法确定该条消息是否提交成功
(2)三阶段协议
主要针对两阶段的优化,解决了两阶段单点故障问题,但是性能问题和不一致问题仍然没有根本解决
引入了超时机制,解决参与者阻塞的问题,超时后本地提交,两阶段只有协调者有超时机制
第一阶段:
协调者询问事务参与者,是否有能力完成此事务
如果能够完成,则进入第二阶段
如果有一个及以上的十五参与者不能完成或者响应超时,则中断事务,并向所有参与者发送abort请求
第二阶段:
协调者向所有的参与者发送PreCommit请求,参与者收到后开始执行事务操作
参与者执行完事务操作后(此时属于未提交事务的状态),就会向协调者反馈ACK表示已经做好准备提交了
第三阶段:
如果阶段二所有的参与者都返回了ACK,那么协调者就会从预提交状态转为提交状态
然后向所有的参与者节点发送doCommit请求,参与者节点在收到提交请求后就会各自执行事务提交操作,
并向协调者反馈ACK,协调者收到所有参与者的ACK消息后完成事务。
如果有节点未完成PreCommit的反馈或者反馈超时,那么协调者就会向所有的参与者节点发送abort请求,
从而中断事务
(3)TCC补偿事务
TCC: try confirm cancel
针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作
try:做业务检查及资源预留
confirm:做业务确认操作
cancel:实现一个与try相反的操作(回滚操作)
TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的
cancel操作,若try操作全部成功,TM将会发起所有分支事务confirm操作,其中confirm/cancel操作
若执行失败,TM会进行重试
TCC模型对业务的侵入性较强,改造的难度较大,每个操作都需要有try confirm cancel 三个接口实现,
confirm和cancel接口还必须实现幂等性
(4)消息队列的事务消息
发送prepare消息到消息中间件
发送成功后,执行本地事务
如果事务执行成功,则commit,消息中间件将消息发至消费端(commit前消息不会被消费)
如果事务执行失败,则回滚,消息中间件将这条prepare消息删除
消费端接收到消息进行消费,如果消费失败,则不断重试
10.分布式锁解决方案
需要这个锁独立于每一个服务,而不是在服务里边,使用第三方锁来解决
(1)数据库
利用数据库的主键冲突控制一次只有一个线程能获取锁
非阻塞、不可重入、单点、失效时间
优点:
可以使用已有的数据库系统,不需要额外引入新的组件
可以利用数据库的事务支持来保证数据一致性
缺点:
性能开销大,数据库操作通常比较慢,可能成为瓶颈
容易引发数据库死锁问题,需要仔细设计事务隔离级别和锁策略
高并发情况下可能导致数据库连接池资源耗尽
解决的问题:
防止多个节点同时修改同一资源,保证数据的一致性
(2)zookeeper分布式锁
zookeeper通过临时节点,解决了死锁的问题,一旦客户端获取到锁之后突然挂掉(session连接断开),
那么这个临时节点就会自动删除掉,其他客户端自动获取锁
临时顺序节点解决惊群效应
(3)redis分布式锁
setNX,单线程处理网络请求,不需要考虑并发安全性
所有服务节点设置相同的key,返回为0则获取锁失败
setNX:
早期版本没有超时参数,需要到哪都设置,存在死锁问题(中途宕机)
后期版本提供加锁与设置时间原子操作,但是存在任务超时,锁自动释放,导致并发问题,加锁与释放
锁不是同一个线程的问题
删除锁:判断线程唯一标志,再删除
可重入性与锁续期没有实现,通过redisson解决(类似AQS的实现,看门狗监听机制)
优点:
原子性操作能够在高并发下保证锁的正确性
性能相对较高,缓存通常比数据库操作快速
缺点:
可能出现死锁问题,需要考虑锁的超时机制和错误处理
缓存故障可能导致锁失效或者数据不一致
解决的问题:
在分布式环境中实现资源的互斥访问,防止竞争条件
11.负载均衡策略
负载均衡是一种在计算机网络和分布式系统中应用的策略,用于将工作负载(如请求、流量)平均分配到多个服
务器或资源上,以实现高可用性、提高性能和避免单一节点的过载。
负载均衡旨在优化资源利用,确保系统能够有效地处理大量的请求,并在节点出现故障时继续提供服务
(1)轮询法
将请求按顺序轮流的分配到服务器上,它均衡的对待后端的每一台服务器,而不关心服务器实际的连接
数和当前的系统负载
(2)加权轮询法
不同的服务器可能机器的配置和当前系统的负载并不相同,因此它们的抗压能力也不相同。
给配置高、负载低的机器配置更高的权重,让其处理更多的请求。
给配置低、负载高的机器分配较低的权重,降低其系统负载
(3)随机法
通过系统的随机算法,根据服务器的列表大小值来随机选取其中的一台服务器进行访问。
随着客户端调用服务端的次数增多,其实际越来越接近与平均分配请求到每一台服务器
(4)加权随机法
与加权轮询法一样,根据服务器的配置与系统的负载分配不同的权重。
不同的是,它是按照权重随机请求服务器,而不是顺序请求
(5)源地址哈希法
根据获取客户端的IP地址,通过哈希函数计算得到一个hashcode,用该hashcode对服务器列表的大小进行
取模运算,得到的结果便是客户端要访问的服务器的序号。
采用源地址哈希法进行负载均衡,同一IP地址的客户端,当服务器列表不变时,它每次都会映射到同一台
服务器进行访问
(6)最小连接数法
最小连接数算法比较灵活和智能,由于服务器的配置不尽相同,对于请求的处理有快有慢,它是根据服务器
当前的连接情况,动态地选取其中当前积压连接数最少的一台服务器来处理当前的请求,尽可能的提高服务器
的利用效率,将请求合理地分流到每一台服务器
12.集群、分布式、SOA、微服务的概念及区别
集群:
不同服务器部署同一套应用服务对外提供访问,实现服务的负载均衡,指同一种组件的多个实例,形成的
逻辑上的整体。单个节点可以提供完整服务。
分布式:
是指将单体架构的各个部分拆分,然后部署到不同的机器或者进程中
SOA:
是一种面向服务的架构,系统所有的服务都注册在总线上,当调用服务时,从总线上查找服务信息,然后
调用
微服务:
一种更彻底的面向服务的架构,将系统中各个功能个体抽成一个个小的应用程序,基本保持一个应用
对应一个服务的架构
13.spring cloud 和 dubbo有哪些区别
spring cloud:提供了构建微服务系统所需要的一组通用开发模式以及一系列快速实现这些开发模式的工具
是一个微服务框架,提供了微服务领域中的很多功能组件,是一个大而全的框架
dubbo:一开始是一个RPC调用框架,核心是解决服务调用间的问题,更侧重于服务调用,服务调用性能比
spring cloud高
14.spring cloud有哪些常用组件
Eureka:注册中心,用来进行服务的自动注册和发现
Nacos:注册中心、配置中心
Consul:注册中心、配置中心
spring cloud config:配置中心
feign/openfeign:RPC调用
dubbo:RPC调用
kong:服务网关
zuul:服务网关,可以进行服务路由、服务降级、负载均衡
spring cloud gateway:服务网关
ribbon:负载均衡,用来在消费者调用服务时进行负载均衡
spring cloud sleuth:链路追踪
zipkin:链路追踪
seata:分布式事务
sentinel:服务熔断
hystrix:服务熔断,负责服务容错
15.高并发场景下如何实现系统限流
限流一般需要结合容量规划和压测来进行。
当外部请求接近或者达到系统的最大阈值时,触发限流,采取其他的手段进行降级,保护系统不被压垮
常见的降级策略包括延迟处理、拒绝服务、随机拒绝
(1)计数器法
将时间划分为固定的窗口大小
在窗口时间段内,每来一个请求,对计数器+1
当计数器达到设定限制后,该窗口时间内的之后的请求都被丢弃处理
该窗口时间结束后,计数器清零,从新开始计数
(2)滑动窗口计数法
将时间划分为细粒度的区间,每个区间维持一个计数器,每进入一个请求则将计数器+1
多个区间组成一个时间窗口,每六十一个区间时间后,则抛弃最老的一个区间,纳入新区间
若当前窗口的区间计数器总和超过设定的限制数量,则本窗口内的后续请求都被丢弃
(3)漏桶算法
如果外部请求超出当前阈值,则会在一直加入,直到溢出,系统并不关心溢出的流量。
从出口处限制请求速率,并不存在计数器法的临界问题,请求曲线始终是平滑的。
无法应对突发流量,相当于一个空桶+固定处理线程
(4)令牌桶算法
假设一个大小恒定的桶,这个桶的容量和设定的阈值有关,桶里放着很多令牌,通过一个固定的速率往里边
放入令牌,如果桶满了,则把令牌丢掉,最后桶中可以保存的最大令牌数永远不会超过桶的大小。
当有请求进入时,就尝试从桶里取走一个令牌,如果桶是空的,那么这个请求就会被拒绝
16.什么是hystrix
分布式容错框架:
阻止故障的连锁反应,实现熔断
快速失败,实现优雅降级
提供实时的监控和告警
资源隔离:
线程隔离:hystrix会给每一个Command分配一个单独的线程池,这样在进行单个服务调用的时候,
就可以在独立的线程池里面进行,而不会对其它线程池造成影响
信号量隔离:客户端向依赖服务发起请求时,首先要获取一个信号量才能真正发起调用,由于信号量
的数量有限,当并发请求超过信号量个数时,后续的请求都会直接拒绝,进入
fallback流程。信号量隔离主要是通过控制并发请求量,防止请求线程的大面积阻塞
,从而达到限流和防止雪崩的目的
熔断和降级:调用服务失败后快速失败
熔断:为了防止异常扩散,保证系统的稳定性
降级:编写好调用失败的补救逻辑,然后对服务直接停止运行,这样这些接口就无法正常调用,但又不至于
直接保存,只是服务水平下降
17.什么是服务降级
降级是解决系统资源不足和海量业务请求之间的矛盾
在暴增的流量请求下,对一些非核心业务流程、非关键业务,进行有策略的放弃,以此来释放系统资源,保证
核心业务的正常运行,尽量避免这种系统资源分配的不平衡,打破二八策略,让更多的机器资源,承载主要的
业务请求。
服务降级不是一个常态策略,而是应对非正常情况下的应急策略。服务降级的结果,通常是对一些业务请求,
返回一个统一的结果,可以理解为一种FailOver快速失败的策略。
一般通过配置中心配置开关实现开启降级
是为了降低系统负载
18.什么是服务熔断
熔断模式保护的是业务系统不被外部大流量或者下游系统的异常而拖垮
如果开启了熔断,订单服务可以在下游调用出现部分异常时,调节流量请求,比如在出现10%的失败后,减少
50%的流量请求,如果继续出现50%的异常,则减少80%的流量请求。
相应的,在检测到下游服务正常后,首先恢复30%的流量,然后是50%的流量,接下来是全部流量
是下游服务故障触发
19.什么是服务雪崩
当服务A调用服务B,服务B调用服务C,此时大量请求突然请求服务A,加入服务A本身能抗住这些请求,但是
如果服务C扛不住,导致服务C请求堆积,从而服务B请求堆积,从而服务A不可用
20.什么是服务限流
指高并发请求下,为了保护系统,可以对访问服务的请求进行数量上的限制,从而防止系统不被大量请求压垮,
在秒杀中,限流非常重要
21.什么是微服务
微服务:通过将大型的单体应用划分为比较小的服务单元,从而降低整个系统的复杂度
优点:
服务部署更灵活:每个应用都可以是一个独立的项目,可以独立部署,不依赖于其他服务,耦合度降低
技术更新灵活:在大型单体应用中,技术要进行更新,往往是非常困难的。而微服务可以根据业务特点
,灵活选择技术栈
应用的性能提高:大型单体应用中,往往启动就会成为一个很大的难关。而采用微服务,整个系统的性能
是能得到提高的
代码复用:很多底层服务可以以 REST API 的方式对外提供统一的服务,所有基础服务可以在整个
微服务系统中通用
缺点:
服务调用的复杂性提高了:网络问题、容错问题、负载问题、高并发问题
分布式事务
测试的难度提升了、运维难度提升了