分布式
分布式
1.什么是CAP理论?
CAP 定理(CAP theorem)指出对于一个分布式系统来说,当设计读写操作时,只能同时满足以下三点中的两个:
- 一致性(Consistency) : 所有节点访问同一份最新的数据副本。
- 可用性(Availability): 非故障的节点在合理的时间内返回合理的响应(不是错误或者超时的响应)。
- 分区容错性(Partition tolerance) : 分布式系统出现网络分区的时候,仍然能够对外提供服务。
2.什么是网络分区?
分布式系统中,多个节点之前的网络本来是连通的,但是因为某些故障(比如部分节点网络出了问题)某些节点之间不连通了,整个网络就分成了几块区域,这就叫网络分区。
3.不是所谓的“3 选 2”?
大部分人解释这一定律时,常常简单的表述为:“一致性、可用性、分区容忍性三者你只能同时达到其中两个,不可能同时达到”。
当发生网络分区的时候,如果我们要继续服务,那么强一致性和可用性只能 2 选 1。也就是说当网络分区之后 P 是前提,决定了 P 之后才有 C 和 A 的选择。也就是说分区容错性(Partition tolerance)我们是必须要实现的。
简而言之就是:CAP 理论中分区容错性 P 是一定要满足的,在此基础上,只能满足可用性 A 或者一致性 C。
因此,分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。 比如 ZooKeeper、HBase 就是 CP 架构,Cassandra、Eureka 就是 AP 架构,Nacos 不仅支持 CP 架构也支持 AP 架构。
为啥不可能选择 CA 架构呢? 举个例子:若系统出现“分区”,系统中的某个节点在进行写操作。为了保证 C, 必须要禁止其他节点的读写操作,这就和 A 发生冲突了。如果为了保证 A,其他节点的读写操作正常的话,那就和 C 发生冲突了。
选择 CP 还是 AP 的关键在于当前的业务场景,没有定论,比如对于需要确保强一致性的场景如银行一般会选择保证 CP 。
另外,需要补充说明的一点是: 如果网络分区正常的话(系统在绝大部分时候所处的状态),也就说不需要保证 P 的时候,C 和 A 能够同时保证。
4.BASE 理论?
BASE 是 Basically Available(基本可用) 、Soft-state(软状态) 和 Eventually Consistent(最终一致性) 三个短语的缩写。BASE 理论是对 CAP 中一致性 C 和可用性 A 权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的,它大大降低了我们对系统的要求。
即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。
BASE 理论本质上是对 CAP 的延伸和补充,更具体地说,是对 CAP 中 AP 方案的一个补充。
AP 方案只是在系统发生分区的时候放弃一致性,而不是永远放弃一致性。在分区故障恢复后,系统应该达到最终一致性。这一点其实就是 BASE 理论延伸的地方。
5.BASE 理论三要素?
1. 基本可用
基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。
什么叫允许损失部分可用性呢?
- 响应时间上的损失: 正常情况下,处理用户请求需要 0.5s 返回结果,但是由于系统出现故障,处理用户请求的时间变为 3 s。
- 系统功能上的损失:正常情况下,用户可以使用系统的全部功能,但是由于系统访问量突然剧增,系统的部分非核心功能无法使用。
2. 软状态
软状态指允许系统中的数据存在中间状态(CAP 理论中的数据不一致),并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
3.最终一致性
最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
分布式一致性的 3 种级别:
- 强一致性 :系统写入了什么,读出来的就是什么。
- 弱一致性 :不一定可以读取到最新写入的值,也不保证多少时间之后读取到的数据是最新的,只是会尽量保证某个时刻达到数据一致的状态。
- 最终一致性 :弱一致性的升级版,系统会保证在一定时间内达到数据一致的状态。
业界比较推崇是最终一致性级别,但是某些对数据一致要求十分严格的场景比如银行转账还是要保证强一致性。
ACID 是数据库事务完整性的理论,CAP 是分布式系统设计理论,BASE 是 CAP 理论中 AP 方案的延伸。
6.Paxos算法?
Paxos 不是一致性算法而是共识算法
Basic Paxos 算法
Basic Paxos 中存在 3 个重要的角色:
- 提议者(Proposer):也可以叫做协调者(coordinator),提议者负责接受客户端发起的提议,然后尝试让接受者接受该提议,同时保证即使多个提议者的提议之间产生了冲突,那么算法都能进行下去;
- 接受者(Acceptor):也可以叫做投票员(voter),负责对提议者的提议投票,同时需要记住自己的投票历史;
- 学习者(Learner):如果有超过半数接受者就某个提议达成了共识,那么学习者就需要接受这个提议,并就该提议作出运算,然后将运算结果返回给客户端。
Multi Paxos 思想
⚠️注意 : Multi-Paxos 只是一种思想,这种思想的核心就是通过多个 Basic Paxos 实例就一系列值达成共识。
二阶段提交是达成共识常用的方式,Basic Paxos 就是通过二阶段提交的方式来达成共识。Basic Paxos 还支持容错,少于一般的节点出现故障时,集群也能正常工作
6.分布式幂等性如何设计?
解决方案
1,查询和删除不在幂等讨论范围,查询肯定没有幂等的说,删除:第一次删除成功后,后面来删 除直接返回0,也是返回成功。
2,建唯一索引:唯一索引或唯一组合索引来防止新增数据存在脏数据 (当表存在唯一索引,并发 时新增异常时,再查询一次就可以了,数据应该已经存在了,返回结果即可)。
3,token机制:由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交。前端 在数据提交前要向后端服务的申请token,token放到 Redis 或 JVM 内存,token有效时间。提交后 后台校验token,同时删除token,生成新的token返回。redis要用删除操作来判断token,删除成 功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用。
4,悲观锁 select id ,name from table_# where id='##' for update;
悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,根据实际情况选用(另外还要考 虑id是否为主键,如果id不是主键或者不是 InnoDB 存储引擎,那么就会出现锁全表)。
5,乐观锁,给数据库表增加一个version字段,可以通过这个字段来判断是否已经被修改了
update table_xxx set name=#name#,version=version+1 where version=#version#
6,分布式锁,比如单号为key,然后给Key设置有效期(防止支付失败后,锁一直不释放),来一个请求使用订单号生成一把锁,业务代码执行完成后再释放锁。
7,保底方案,先查询是否存在此单,不存在进行支付,存在就直接返回支付结果。
7.简单一次完整的 HTTP 请求所经历的步骤?
1、 DNS 解析(通过访问的域名找出其 IP 地址,递归搜索)。
2、HTTP 请求,当输入一个请求时,建立一个 Socket 连接发起 TCP的 3 次握手。
3.1、客户端向服务器发送请求命令(一般是 GET 或 POST 请求)。
客户端的网络层不用关心应用层或者传输层的东西,主要做的是通过查找路由表确定如何 到达服务器,期间可能经过多个路由器,这些都是由路由器来完成的工作,就是通过查找路由表决定通过那个路径到达服务器。
客户端的链路层,包通过链路层发送到路由器,通过邻居协议查找给定 IP 地址的 MAC 地 址,然后发送 ARP 请求查找目的地址,如果得到回应后就可以使用 ARP 的请求应答交换 的 IP 数据包现在就可以传输了,然后发送 IP 数据包到达服务器的地址。
3.2、客户端发送请求头信息和数据。
4.1、服务器发送应答头信息。
4.2、服务器向客户端发送数据。
5、服务器关闭 TCP 连接(4次挥手)。
这里是否关闭 TCP 连接,也根据 HTTP Keep-Alive 机制有关。 同时,客户端也可以主动发起关闭 TCP 连接。
6、客户端根据返回的HTML、CSS、JS进行渲染。
8.你知道哪些分布式事务解决方案?
我目前知道的有五种:
两阶段提交(2PC)
三阶段提交(3PC)
补偿事务(TCC=Try-Confirm-Cancel)
本地消息队列表(MQ)
Sagas事务模型(最终一致性)
9.什么是二阶段提交?
两阶段提交2PC是分布式事务中最强大的事务类型之一,两段提交就是分两个阶段提交:
第一阶段询问各个事务数据源是否准备好。
第二阶段才真正将数据提交给事务数据源。
为了保证该事务可以满足ACID,就要引入一个协调者(Cooradinator)。其他的节点被称为参与者 (Participant)。协调者负责调度参与者的行为,并最终决定这些参与者是否要把事务进行提交。
处理流程如下:
阶段一
a) 协调者向所有参与者发送事务内容,询问是否可以提交事务,并等待答复。
b) 各参与者执行事务操作,将 undo 和 redo 信息记入事务日志中(但不提交事务)。
c) 如参与者执行成功,给协调者反馈 yes,否则反馈 no。
阶段二 如果协调者收到了参与者的失败消息或者超时,直接给每个参与者发送回滚(rollback)消息;否则, 发送提交(commit)消息。
两种情况处理如下:
情况1:当所有参与者均反馈 yes,提交事务
a) 协调者向所有参与者发出正式提交事务的请求(即 commit 请求)。
b) 参与者执行 commit 请求,并释放整个事务期间占用的资源。
c) 各参与者向协调者反馈 ack(应答)完成的消息。
d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务提交。
情况2:当有一个参与者反馈 no,回滚事务
a) 协调者向所有参与者发出回滚请求(即 rollback 请求)。
b) 参与者使用阶段 1 中的 undo 信息执行回滚操作,并释放整个事务期间占用的资源。
c) 各参与者向协调者反馈 ack 完成的消息。
d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务。
缺点:
- 性能问题:所有参与者在事务提交阶段处于同步阻塞状态,占用系统资源,容易导致性能瓶颈。
可靠性问题:如果协调者存在单点故障问题,或出现故障,提供者将一直处于锁定状态。
数据一致性问题:如果发⽣局部⽹络问题,⼀部分事务参与者收到了提交消 息,另⼀部分事务参与者没收到提交消息,那么就会导致节点间数据的不 ⼀致问题。
优点:尽量保证了数据的强一致,适合对数据强一致要求很高的关键领域。(其实也不能100%保证 强一致)。
10.什么是三阶段提交?
三阶段提交是在二阶段提交上的改进版本,3PC最关键要解决的就是协调者和参与者同时挂掉的问题,所以3PC把2PC的准备阶段再次一分为二,这样三阶段提交。 处理流程如下 :
阶段一
a) 协调者向所有参与者发出包含事务内容的canCommit 请求,询问是否可以提交事务,并等待所有参与者答复。
b) 参与者收到 canCommit 请求后,如果认为可以执行事务操作,则反馈 yes 并进入预备状态,否则反馈no。
阶段二 协调者根据参与者响应情况,有以下两种可能。
情况1:所有参与者均反馈 yes,协调者预执行事务。
a) 协调者向所有参与者发出 preCommit 请求,进入准备阶段。
b) 参与者收到 preCommit 请求后,执行事务操作,将 undo 和 redo 信息记入事务日志中(但不提交事务)。
c) 各参与者向协调者反馈 ack 响应或 no 响应,并等待最终指令。
情况2:只要有一个参与者反馈 no,或者等待超时后协调者尚无法收到所有提供者的反馈,即中断事务。
a) 协调者向所有参与者发出 abort 请求。
b) 无论收到协调者发出的 abort 请求,或者在等待协调者请求过程中出现超时,参与者均会中断事 务。
阶段三 该阶段进行真正的事务提交,也可以分为以下两种情况。
情况 1:所有参与者均反馈 ack 响应,执行真正的事务提交。
a) 如果协调者处于工作状态,则向所有参与者发出 do Commit 请求。
b) 参与者收到 do Commit 请求后,会正式执行事务提交,并释放整个事务期间占用的资源。
c) 各参与者向协调者反馈 ack 完成的消息。
d) 协调者收到所有参与者反馈的 ack 消息后,即完成事务提交。
情况2:只要有一个参与者反馈 no,或者等待超时后协调组尚无法收到所有提供者的反馈,即回滚 事务。
a) 如果协调者处于工作状态,向所有参与者发出 rollback 请求。
b) 参与者使用阶段 1 中的 undo 信息执行回滚操作,并释放整个事务期间占用的资源。
c) 各参与者向协调组反馈 ack 完成的消息。
d) 协调组收到所有参与者反馈的 ack 消息后,即完成事务回滚。
优点:相比二阶段提交,三阶段提交降低了阻塞范围,在等待超时后协调者或参与者会中断事务。 避免了协调者单点问题。阶段 3 中协调者出现问题时,参与者会继续提交事务。
缺点:数据不一致问题依然存在,当在参与者收到 preCommit 请求后等待 do commite 指令时, 此时如果协调者请求中断事务,而协调者无法与参与者正常通信,会导致参与者继续提交事务,造成数据不一致。
2PC和3PC的区别:
三阶段提交协议在协调者和参与者中都引⼊ 超时机制,并且把两阶段提交 协议的第⼀个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。 三阶段提交的三个阶段分别为:can_commit,pre_commit,do_commit。相对于2PC,3PC主要解决的单点故障问题,并减少阻塞, 因为⼀旦参与 者⽆法及时收到来⾃协调者的信息之后,他会默认执⾏commit。⽽不会⼀ 直持有事务资源并处于阻塞状态。
3PC相对于2PC⽽⾔到底优化了什么地⽅呢
相⽐较2PC⽽⾔,3PC对于协调者(Coordinator)和参与者(Partcipant) 都设置了超时时间,⽽2PC只有协调者才拥有超时机制。这解决了⼀个什 么问题呢?
这个优化点,主要是避免了参与者在⻓时间⽆法与协调者节点通讯(协调 者挂掉了)的情况下,⽆法释放资源的问题,因为参与者⾃身拥有超时机 制会在超时后,⾃动进⾏本地commit从⽽进⾏释放资源。⽽这种机制也侧 ⾯降低了整个事务的阻塞时间和范围。
另外,通过CanCommit、PreCommit、DoCommit三个阶段的设计,相较 于2PC⽽⾔,多设置了⼀个缓冲阶段保证了在最后提交阶段之前各参与节 点的状态是⼀致的。
11.什么是补偿事务?
TCC
(Try Confirm Cancel)是服务化的二阶段编程模型,采用的补偿机制:
TCC 其实就是采用的补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。
它分为三个步骤:
Try 阶段主要是对业务系统做检测及资源预留。
Confirm 阶段主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默 认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。
Cancel 阶段主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
优点:
性能提升:具体业务来实现控制资源锁的粒度变小,不会锁定整个资源。
数据最终一致性:基于 Confirm 和 Cancel 的幂等性,保证事务最终完成确认或者取消,保证数据 的一致性。
可靠性:解决了 XA 协议的协调者单点故障问题,由主业务方发起并控制整个业务活动,业务活动 管理器也变成多点,引入集群。
缺点:TCC 的 Try、Confirm 和 Cancel 操作功能要按具体业务来实现,业务耦合度较高,提高了开 发成本。
12.消息队列是怎么实现事务的?
本地消息表(异步确保)
基本思路就是:
消息生产方,需要额外建一个消息表,并记录消息发送状态。消息表和业务数据要在一个事务里提交,也就是说他们要在一个数据库里面。
然后消息会经过MQ发送到消息的消费方。如果消息发送失败,会进行重试发送。
消息消费方,需要处理这个消息,并完成自己的业务逻辑。此时如果本地事务处理成功,表明已经 处理成功了,如果处理失败,那么就会重试执行。如果是业务上面的失败,可以给生产方发送一个 业务补偿消息,通知生产方进行回滚等操作。
生产方和消费方定时扫描本地消息表,把还没处理完成的消息或者失败的消息再发送一遍。
这种方案遵循BASE理论,采用的是最终一致性,不会出现像2PC那样复杂的实现(当调用链很长的时候,2PC的可用性是非常低的),也不会像 TCC那样可能出现确认或者回滚不了的情况。
优点: 一种非常经典的实现,避免了分布式事务,实现了最终一致性。
缺点: 消息表会耦合到业务系统中,如果没有封装好的解决方案,会有很多杂活需要处理。
MQ 事务消息 有一些第三方的MQ是支持事务消息的,比如RocketMQ,他们支持事务消息的方式也是类似于采用 的二阶段提交,但是市面上一些主流的MQ都是不支持事务消息的,比如 RabbitMQ 和 Kafka 都不 支持。
以阿里的 RocketMQ 中间件为例,其思路大致为:
优点: 实现了最终一致性,不需要依赖本地数据库事务。
缺点: 实现难度大,主流MQ不支持 ,RocketMQ事务消息部分代码也未开源。
13.你知道哪些限流算法?
限流算法有四种常见算法:
计数器算法(固定窗口)
滑动窗口
漏桶算法
令牌桶算法
14.说说什么是计数器(固定窗口)算法?
计数器算法是使用计数器在周期内累加访问次数,当达到设定的限流值时,触发限流策略。下一个 周期开始时,进行清零,重新计数。
此算法在单机还是分布式环境下实现都非常简单,使用redis的incr原子自增性和线程安全即可轻松 实现。
这个算法通常用于QPS限流和统计总访问量,对于秒级以上的时间周期来说,会存在一个非常严重 的问题,那就是临界问题,如下图:
假设1min内服务器的负载能力为100,因此一个周期的访问量限制在100,然而在第一个周期的最 后5秒和下一个周期的开始5秒时间段内,分别涌入100的访问量,虽然没有超过每个周期的限制 量,但是整体上10秒内已达到200的访问量,已远远超过服务器的负载能力,由此可见,计数器算 法方式限流对于周期比较长的限流,存在很大的弊端。
15.说说什么是滑动窗口算法?
滑动窗口算法是将时间周期分为N个小周期,分别记录每个小周期内访问次数,并且根据时间滑动删除过期的小周期。
如下图,假设时间周期为1min,将1min再分为2个小周期,统计每个小周期的访问数量,则可以看 到,第一个时间周期内,访问数量为75,第二个时间周期内,访问数量为100,超过100的访问则 被限流掉了
由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。
此算法可以很好的解决固定窗口算法的临界问题。
16.说说什么是漏桶算法?
漏桶算法是访问请求到达时直接放入漏桶,如当前容量已达到上限(限流值),则进行丢弃(触发 限流策略)。漏桶以固定的速率进行释放访问请求(即请求通过),直到漏桶为空。
17.说说什么是令牌桶算法?
令牌桶算法是程序以r(r=时间周期/限流值)的速度向令牌桶中增加令牌,直到令牌桶满,请求到达时向令牌桶请求令牌,如获取到令牌则通过请求,否则触发限流策略
18.分布式id生成方案有哪些?
UUID,数据库主键自增,Redis自增ID,雪花算法。
描述 | 优点 | 缺点 | |
---|---|---|---|
UUID | UUID是通用唯一标识码的缩写,其目的是让分布式系统中的所有元素都有唯一的辨识信息,而不需要通过中央控制器来指定唯一标识。 | 1. 降低全局节点的压力,使得主键生成速度更快; 2. 生成的主键全局唯一; 3. 跨服务器合并数据方便。 | 1. UUID占用16个字符,空间占用较多; 2. 不是递增有序的数字,数据写入IO随机性很大,且索引效率下降 |
数据库主键自增 | MySQL数据库设置主键且主键自动增长 | 1. INT和BIGINT类型占用空间较小; 2. 主键自动增长,IO写入连续性好; 3. 数字类型查询速度优于字符串 | 1. 并发性能不高,受限于数据库性能; 2. 分库分表,需要改造,复杂; 3. 自增:数据和数据量泄露 |
Redis自增 | Redis计数器,原子性自增 | 使用内存,并发性能好 | 1. 数据丢失; 2. 自增:数据量泄露 |
雪花算法(snowflake) | 大名鼎鼎的雪花算法,分布式ID的经典解决方案 | 1. 不依赖外部组件; 2. 性能好 | 时钟回拨 |
19.雪花算法生成的ID由哪些部分组成?
- 符号位,占用1位。
- 时间戳,占用41位,可以支持69年的时间跨度。
- 机器ID,占用10位。
- 序列号,占用12位。一毫秒可以生成4095个ID。
20.分布锁有哪些解决方案?
Reids的分布式锁,很多大公司会基于Reidis做扩展开发。setnx key value ex 10s,Redisson。
watch dog.
基于Zookeeper。临时节点,顺序节点。
基于数据库,比如Mysql。主键或唯一索引的唯一性。
21.Redis做分布式锁用什么命令?
SETNX 格式:setnx key value 将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作,操作失败。
SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
加锁:set key value nx ex 10s
释放锁:delete key
22.Redis做分布式锁死锁有哪些情况,如何解决?
情况1:加锁,没有释放锁。需要加释放锁的操作。比如delete key。
情况2:加锁后,程序还没有执行释放锁,程序挂了。需要用的key的过期机制。
23.你设计微服务时遵循什么原则?
单一职责原则:让每个服务能独立,有界限的工作,每个服务只关注自己的业务。做到高内聚。
服务自治原则:每个服务要能做到独立开发、独立测试、独立构建、独立部署,独立运行。与其他服务进行解耦。
轻量级通信原则:让每个服务之间的调用是轻量级,并且能够跨平台、跨语言。比如采用RESTful风格,利用消息队列进行通信等。
粒度进化原则:对每个服务的粒度把控,其实没有统一的标准,这个得结合我们解决的具体业务问题。不要过度设计。服务的粒度随着业务和用户的发展而发展。
总结一句话,软件是为业务服务的,好的系统不是设计出来的,而是进化出来的。
24.Cookie 和 Session 有什么区别?如何使用Session进行身份验证?
Session 的主要作用就是通过服务端记录用户的状态。 典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。
Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密。
那么,如何使用Session进行身份验证?
很多时候我们都是通过 SessionID 来实现特定的用户,SessionID 一般会选择存放在 Redis 中。举个例子:用户成功登陆系统,然后返回给客户端具有 SessionID 的 Cookie,当用户向后端发起请求的时候会把 SessionID 带上,这样后端就知道你的身份状态了。关于这种认证方式更详细的过程如下:
用户向服务器发送用户名和密码用于登陆系统。 服务器验证通过后,服务器为用户创建一个 Session,并将 Session信息存储 起来。 服务器向用户返回一个 SessionID,写入用户的 Cookie。 当用户保持登录状态时,Cookie 将与每个后续请求一起被发送出去。 服务器可以将存储在 Cookie 上的 Session ID 与存储在内存中或者数据库中的 Session 信息进行比较,以验证用户的身份,返回给用户客户端响应信息的时候会附带用户当前的状态。 使用 Session 的时候需要注意下面几个点:
依赖Session的关键业务一定要确保客户端开启了Cookie。 注意Session的过期时间
25.为什么Cookie 无法防止CSRF攻击,而token可以?
**CSRF(Cross Site Request Forgery)**一般被翻译为 跨站请求伪造 。那么什么是 跨站请求伪造 呢?说简单用你的身份去发送一些对你不友好的请求。举个简单的例子:
小壮登录了某网上银行,他来到了网上银行的帖子区,看到一个帖子下面有一个链接写着“科学理财,年盈利率过万”,小壮好奇的点开了这个链接,结果发现自己的账户少了10000元。这是这么回事呢?原来黑客在链接中藏了一个请求,这个请求直接利用小壮的身份给银行发送了一个转账请求,也就是通过你的 Cookie 向银行发出请求。
<a src=http://www.mybank.com/Transfer?bankId=11&money=10000>科学理财,年盈利率过万</> 进行Session 认证的时候,我们一般使用 Cookie 来存储 SessionId,当我们登陆后后端生成一个SessionId放在Cookie中返回给客户端,服务端通过Redis或者其他存储工具记录保存着这个Sessionid,客户端登录以后每次请求都会带上这个SessionId,服务端通过这个SessionId来标示你这个人。如果别人通过 cookie拿到了 SessionId 后就可以代替你的身份访问系统了。
Session 认证中 Cookie 中的 SessionId是由浏览器发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。
但是,我们使用 token 的话就不会存在这个问题,在我们登录成功获得 token 之后,一般会选择存放在 local storage 中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个 token,这样就不会出现 CSRF 漏洞的问题。因为,即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带 token 的,所以这个请求将是非法的。
26.什么是 Token?什么是 JWT?如何基于Token进行身份验证?
我们知道 Session 信息需要保存一份在服务器端。这种方式会带来一些麻烦,比如需要我们保证保存 Session 信息服务器的可用性、不适合移动端(依赖Cookie)等等。
有没有一种不需要自己存放 Session 信息就能实现身份验证的方式呢?使用 Token 即可!JWT (JSON Web Token) 就是这种方式的实现,通过这种方式服务器端就不需要保存 Session 数据了,只用在客户端保存服务端返回给客户的 Token 就可以了,扩展性得到提升。
JWT 本质上就一段签名的 JSON 格式的数据。由于它是带有签名的,因此接收者便可以验证它的真实性。
下面是 RFC 7519 对 JWT 做的较为正式的定义。
JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted. ——JSON Web Token (JWT)
JWT 由 3 部分构成:
Header :描述 JWT 的元数据。定义了生成签名的算法以及 Token 的类型。 Payload(负载):用来存放实际需要传递的数据 Signature(签名):服务器通过Payload、Header和一个密钥(secret)使用 Header 里面指定的签名算法(默认是 HMAC SHA256)生成。 在基于 Token 进行身份验证的的应用程序中,服务器通过Payload、Header和一个密钥(secret)创建令牌(Token)并将 Token 发送给客户端,客户端将 Token 保存在 Cookie 或者 localStorage 里面,以后客户端发出的所有请求都会携带这个令牌。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP Header 的 Authorization字段中:Authorization: Bearer Token。
用户向服务器发送用户名和密码用于登陆系统。 身份验证服务响应并返回了签名的 JWT,上面包含了用户是谁的内容。 用户以后每次向后端发请求都在Header中带上 JWT。 服务端检查 JWT 并从中获取用户相关信息。
27.springcloud核心组件有哪些?
服务注册与发现——Netflix Eureka、Nacos、Zookeeper
客户端负载均衡——Netflix Ribbon、SpringCloud LoadBalancer
服务熔断器——Netflix Hystrix、Alibaba Sentinel、Resilience4J
服务网关——Netflix Zuul、SpringCloud Gateway
服务接口调用——Netflix Feign、 Resttemplate、Openfeign
链路追踪——Netflix Sleuth、Skywalking、Pinpoint
聚合Hystrix监控数据——Netflix Turbine
监控中心---- SpringBoot Admin
配置中心——Spring Cloud Config 、Apollo、nacos
28.分布式锁的使⽤场景是什么?有哪些实现⽅案?
在单体架构中,多个线程都是属于同⼀个进程的,所以在线程并发执⾏时,遇到资源竞争时,可以利⽤ ReentrantLock、synchronized等技术来作为锁,来控制共享资源的使⽤。
⽽在分布式架构中,多个线程是可能处于不同进程中的,⽽这些线程并发执⾏遇到资源竞争时,利⽤ ReentrantLock、synchronized等技术是没办法来控制多个进程中的线程的,所以需要分布式锁,意思 就是,需要⼀个分布式锁⽣成器,分布式系统中的应⽤程序都可以来使⽤这个⽣成器所提供的锁,从⽽ 达到多个进程中的线程使⽤同⼀把锁。
⽬前主流的分布式锁的实现⽅案有两种:
- zookeeper:利⽤的是zookeeper的临时节点、顺序节点、watch机制来实现的,zookeeper分布式 锁的特点是⾼⼀致性,因为zookeeper保证的是CP,所以由它实现的分布式锁更可靠,不会出现混乱
- redis:利⽤redis的setnx、lua脚本、消费订阅等机制来实现的,redis分布式锁的特点是⾼可⽤, 因为redis保证的是AP,所以由它实现的分布式锁可能不可
29.如果没有Cookie,Session还能进⾏身份验证吗?
当服务器tomcat第⼀次接收到客户端的请求时,会开辟⼀块独⽴的session空间,建⽴⼀个session对 象,同时会⽣成⼀个session id,通过响应头的⽅式保存到客户端浏览器的cookie当中。以后客户端的 每次请求,都会在请求头部带上这个session id,这样就可以对应上服务端的⼀些会话的相关信息,⽐ 如⽤户的登录状态。
如果没有客户端的Cookie,Session是⽆法进⾏身份验证的。
当服务端从单体应⽤升级为分布式之后,cookie+session这种机制要怎么扩展?
- session黏贴: 在负载均衡中,通过⼀个机制保证同⼀个客户端的所有请求都会转发到同⼀个 tomcat实例当中。问题: 当这个tomcat实例出现问题之后,请求就会被转发到其他实例,这时候⽤户的session信息就丢了。
- session复制: 当⼀个tomcat实例上保存了session信息后,主动将session 复制到集群中的其他实例。问题: 复制是需要时间的,在复制过程中,容易产⽣session信息丢失。
- session共享: 就是将服务端的session信息保存到⼀个第三⽅中,⽐如Redis。
30.什么是OAuth2.0协议?有哪⼏种认证⽅式?
OAuth2.0是⼀个开放标准,允许⽤户授权第三⽅应⽤程序访问他们存储在另外的服务提供者上的信息, ⽽不需要将⽤户名和密码提供给第三⽅应⽤或分享他们数据的所有内容。 OAuth2.0协议的认证流程,简单理解,就是允许我们将之前的授权和认证过程交给⼀个独⽴的第三⽅进 ⾏担保。 OAuth2.0协议有四种认证⽅式:
授权码模式
简化模式
密码模式
客户端模式
31.什么是SSO?与OAuth2.0有什么关系?
OAuth2.0的使⽤场景通常称为联合登录, ⼀处注册,多处使⽤
SSO Single Sign On 单点登录。 ⼀处登录,多处同时登录
SSO的实现关键是将Session信息集中存储
32.epoll和poll的区别
- select模型,使⽤的是数组来存储Socket连接⽂件描述符,容量是固定的,需要通过轮询来判断是否发⽣了IO事件
- poll模型,使⽤的是链表来存储Socket连接⽂件描述符,容量是不固定的,同样需要通过轮询来判断是否发⽣了IO事件
- epoll模型,epoll和poll是完全不同的,epoll是⼀种事件通知模型,当发⽣了IO事件时,应⽤程序才 进⾏IO操作,不需要像poll模型那样主动去轮询
33.谈谈你对seata的理解
在微服务架构下,由于数据库和应用服务的拆分,导致原本一个事务单元中的多 个 DML 操作,变成了跨进程或者跨数据库的多个事务单元的多个 DML 操作,而传统的数据库事务无法解决这类的问题,所以就引出了分布式事务的概念。
分布式事务本质上要解决的就是跨网络节点的多个事务的数据一致性问题,业内 常见的解决方法有两种
强一致性,就是所有的事务参与者要么全部成功,要么全部失败,全局事务协调 者需要知道每个事务参与者的执行状态,再根据状态来决定数据的提交或者回滚!
最终一致性,也叫弱一致性,也就是多个网络节点的数据允许出现不一致的情况, 但是在最终的某个时间点会达成数据一致。
基于 CAP 定理我们可以知道,强一致性方案对于应用的性能和可用性会有影响, 所以对于数据一致性要求不高的场景,就会采用最终一致性算法。
在分布式事务的实现上,对于强一致性,我们可以通过基于 XA 协议下的二阶段 提交来实现,对于弱一致性,可以基于 TCC 事务模型、可靠性消息模型等方案 来实现。
市面上有很多针对这些理论模型实现的分布式事务框架,我们可以在应用中集成 这些框架来实现分布式事务。
而 Seata 就是其中一种,它是阿里开源的分布式事务解决方案,提供了高性能 且简单易用的分布式事务服务。
Seata 中封装了四种分布式事务模式,分别是:
AT 模式,是一种基于本地事务+二阶段协议来实现的最终数据一致性方案,也是 Seata 默认的解决方案
TCC 模式, TCC 事务是 Try、Confirm、Cancel 三个词语的缩写,简单理解就 是把一个完整的业务逻辑拆分成三个阶段,然后通过事务管理器在业务逻辑层面 根据每个分支事务的执行情况分别调用该业务的 Confirm 或者 Cacel 方法。
Saga 模式,Saga 模式是 SEATA 提供的长事务解决方案,在 Saga 模式中,业 务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经 成功的参与者。
XA 模式,XA 可以认为是一种强一致性的事务解决方法,它利用事务资源(数 据库、消息服务等)对 XA 协议的支持,以 XA 协议的机制来管理分支事务的一 种事务模式。
从这四种模型中不难看出,在不同的业务场景中,我们可以使用 Seata 的不同 事务模型来解决不同业务场景中的分布式事务问题,因此我们可以认为 Seata 是一个一站式的分布式事务解决方案。
34.什么是数据⼀致性?
数据⼀致性分为强⼀致性、弱⼀致性、最终⼀致性。
如果时刻保证客户端看到的数据都是⼀致的, 那么称之为强⼀致性。
如果允许存在中间状态,只要求经过⼀段时间后,数据最终是⼀致的, 则称之为最终⼀致性。
如果允许存在部分数据不⼀致,那么就称之为弱⼀致性。