消息队列⭐
消息队列基础
什么是消息队列?
消息队列是一种存放消息的容器, 生产者可以在队尾添加消息, 消费者可以在队头消费消息.
消息中间件的组成有哪些?
- Broker, 消息服务器, 作为server提供消息核心服务.
- Exchange: 消费交换机, 它决定消息进入哪个队列.
- Queue: 消息队列, 特定的生产者向特定的队列发送消息, 消费者订阅特定的队列完成消息的接收.
- Topic: 主题, 发布订阅模式下的消息统一回基地, 不同生产者向topic发送消息, 消息服务器将消息发布给不同的消费者, 实现消息的广播.
- Message: 消息体, 根据不同通信协议规定的固定格式封装业务数据.
- Producer: 消息生产者.
- Consumer: 消息的消费者.
消息队列的应用场景是什么?⭐
消息队列的应用场景是:异步处理, 应用解耦, 流量削峰, 日志处理, 消息通讯
- 异步处理, 减少响应时间, 比如注册写入数据库, 发送验证码, 发送邮件, 后两者可以用消息队列.
- 应用解耦, 分布式系统之间不必强依赖, 比如电商的下单和扣减库存功能.
- 流量削峰, 避免因流量过大系统挂掉, 比如秒杀活动中前端请求写入消息队列, 如果消息队列长度超过最大数量, 则抛弃新的请求, 后台也业务处理对接消息队列而不是用户的请求.
- 日志处理, 日志采集系统将日志信息写入消息队列, 而日志处理应用程序订阅消息队列.
- 消息通讯, 可以实现点对点聊天和聊天室聊天的功能.
使用消息队列会带来什么新的问题?/缺点?
- 可用性降低, 消息队列本身可能挂掉
- 复杂度提高, 需要保证消息被正确消费, 处理消息丢失, 保证消息传递的正确性.
- 一致性问题, 如果消费者没有正确消费消息, 但是生产者以为已经完成了, 这样就出现数据不一致问题.
常见的消息队列有哪些? 各自有什么特点?
kafka
RocketMQ
RabbitMQ
ActiveMQ
如何选择消息队列?
对比的方向有: 吞吐量, 可用性, 时效性, 消息丢失方面:
- 吞吐量: kafka和RocketMQ都是十万百万级别的, 而ActiveMQ和RabbitMQ都是万级别的,
- 可用性: kafka和RocketMQ都是分布式架构, 而ActiveMQ和RabbitMQ都是主从架构.
- 时效性: RabbitMQ基于Erlang开发, 并发能力很强, 性能非常好, 延时很低, 微秒级别, 其他都是毫秒级别.
- 消息丢失: kafka和RocketMQ理论上都能做到0丢失, 而ActiveMQ和RabbitMQ有可能,但是可能性极低.
JMS是什么?
JMS全称java message service, 是java的消息服务, JMS的客户端可以通过JMS服务进行异步消息传输, JMS API定义了消息服务的规范, ActiveMQ基于JMS规范实现.
JMS定义了五种不同的消息正文格式以及调用的消息类型:
- StreamMessage: java原始值的数据流消息
- MapMessage: 一套键值对消息
- TextMessage: 一个字符串对象
- ObjectMessage: 一个序列化的java对象
- BytesMessage: 一个字节的数据流
JMS的两种消息模型?
点对点模型和发布订阅模型.
点对点模型是生产者将消息放入Queue中, 所有的消费者都可以消费但只能一个消费者实际消费, 可以做成负载均衡.
而发布订阅模型是生产者将消息放入Topic, 生产者生产的消息可以通过消息队列广播给消费者, 一条消息广播以后才订阅的用户是收不到该消息的.
AMQP是什么?
AMQP(Advanced Message Queuing Protocal), 高级消息队列协议, 是应用层的一个协议, 兼容JMS, 该协议不限制平台和语言, RabbitMQ基于AMQPS实现.
AMQP仅支持序列化的二进制消息
AMQP支持的消息模型
提供了五种消息模型:①direct exchange;②fanout exchange;③topic change;④headers exchange;⑤system exchange。本质来讲,后四种和 JMS 的 pub/sub 模型没有太大差别,仅是在路由机制上做了更详细的划分;
消息积压如何避免和解决?
消息丢失如何避免和解决?
延时消息可以用来做什么?
kafka
kafka的关键功能和主要应用场景是什么?
kafka是一个分布式流处理平台, 它有3个关键功能:
- 消息队列, 发布和订阅消息流
- 容错的持久化方式存储记录数据流, kafka会把消息持久化到磁盘.
- 流式处理平台, 提供了流数据处理程序来转换和处理数据流.
kafka的两大应用场景:
- 消息队列
- 数据处理
kafka的优势在哪里?为什么这么快?
kafka的优势有2点:
- kafka的性能非常好, 基于Scala语言和Java语言开发, 设计中使用了大量的批处理和异步的思想, 最高每秒处理千万级别的消息.
- 生态系统兼容性无可匹敌, kafka的兼容性非常好.
kafka的消息模型知道吗?⭐
==kafka的消息模型是发布-订阅模式==, kafka的消息模型中有以下概念:
- Cluster, Cluster由多个broker组成.
- Broker, Borker有多个topic.
- Topic, Topic由多个Partion组成
- Partition, Partition 属于 Topic 的一部分。一个 Topic 可以有多个 Partition ,并且同一 Topic 下的 Partition 可以分布在不同的 Broker 上,这也就表明一个 Topic 可以横跨多个 Broker 。这正如我上面所画的图一样。
- producer, 生产者, 负责创建消息并且投递到kafka集群中, 投递室需要指定Topic并确定发往哪个Partition
- consumer, 消费者, 根所订阅的Topic以及所属的消费组, 决定从哪些Partition中拉取消息, 并且可以设置消息位移offset来控制获取哪些消息.
- Zookeeper, 负责集群的管理, 比如集群中有哪些broker以及topic, 以及patition.
- consumer groups, 一群消费者的集合.
Pruducer将信息发布给Topic, 而Consumer可以订阅Topic, 这样一个消息就会广播给订阅了这个Topic的所有Consumer.
kafka的多副本机制了解吗?⭐
kafka的多副本机制是Partition有多个副本, 而所有的副本之间有一个副本是Leader, 其他副本是follower, Producer发布的消息会被发送到Leader副本, 然后follower副本会从leader副本上面拉取消息进行同步, follower存在的意义是保证数据的安全性, Producer只和Leader进行交互, 当Leader挂掉的时候会从所有的follower中选举出一个leader, 如果follower的同步程度没有达到要求则不会参加竞选.
kafka为什么要设计分区?
为了高可用性和负载均衡.
kafka一个消费者可以消费多个partition吗?
Kafka中的一个消费者可以消费多个分区(partitions)的消息。消费者在订阅(subscribe)特定主题(topic)时,可以同时订阅一个或多个分区。
在Kafka中,每个主题可以被分为多个分区,每个分区都包含一部分消息数据。消费者可以选择订阅一个主题的所有分区,或者只订阅其中的一部分分区。
通过订阅多个分区,消费者可以实现并行处理,从多个分区同时消费消息,从而提高消息处理的吞吐量。
kafka生产者如何选择分区?消息的分配策略是怎样的?⭐
生产者发送消息的时候可以指定topic, partition, key和data, ==必须指定topic==
- 顺序分配, 如果设置key=null就会使用顺序分配topic里面的分区, 以最大限度的平均将消息分配到各个分区上.
- 指定分区, 指定key, 则会分配到key经过hash后的分区上.
- 随机策略
- 自定义策略, 可以实现
org.apache.kafka.clients.producer.Partioner
接口的partion
方法自定义.
zookeeper在kafka中的作用是什么?
进行broker和topic的注册,每个broker在启动时都会在zookeeper中进行注册, 并且topic的partition也是由
并且进行负载均衡.
kafka如何保证消息的消费顺序?⭐
因为kafka的逻辑数据存储单位是partition, 所以partition里面的消息都是有序的, 所以要保证消费的消费顺序, 就要让消息在partition中有序, 所以就可以先提出两种简单的方法:
- 1个topic只对应1个partition(不推荐)
- 发送消息的时候指定key或者partition(kafka发送消息时可以指定topic, partion, key, data)四个参数, 同一个key会保证只发送到同一个partition.
kafka如何保证消息不丢失?⭐
生产者消息丢失的情况是, 发送了但是因为网络波动没发送成功, 防止消息丢失一般会给send方法增加一个回调函数, 回调函数中使用get方法获取调用的结果. 并且使用producer的retries
设置一个重试次数, 一般为3, 另外重试间隔不能设置的太小, 否则网络波动一次3次重试一下子用完了.
消费者消息丢失的情况是, 当从消息队列中拉取消息消费后会自动固定频率提交offset 但是准备消费时消费者挂掉了, 这样消息就丢失了, 解决的方法就是手动提交offset, 当消息真正处理后再手动提交offset, 这样就又有一个重复消费
的问题, 也就是已经消费但在提交offset之前消费者挂掉了, 消息会被重复消费.
kafka消息丢失的情况是, 如果leader所在的broker挂掉的话, 此时会选举一个follower重新成为leader, 但是如果所有的follower都没有同步到leader挂掉之前的一些数据, 就会造成消息丢失, 可以这样解决:
- 设置acks=all, 默认acks=1表示只要数据当leader接收成功即为发送成功, 而设置为all则表明当所有副本都全部收到消息时才算发送成功, 当然如果副本数太多了则延迟很高.
- 设置replication.factor>=3, 设置每个分区的副本数量.
- 设置min.insync.replicas > 1, 设置最小被几个副本接收才算发送成功, 一般推荐一般推荐设置成 replication.factor = min.insync.replicas + 1, 不能相等, 因为相等的话要是有一个副本挂掉, 那必然不能发送成功, 则整个分区不可用.
- 设置unclean.leader.election.enable = false, 当副本发生故障时不会从同步没达到要求的follow中选举leader.
kafka如何保证消息不重复消费?
- 消费者组(Consumer Group):Kafka中的消费者可以组成消费者组,每个消费者组内的消费者共同消费一个或多个分区。Kafka确保每个分区只能被同一个消费者组内的一个消费者消费,这样可以避免同一个消息被多个消费者消费,从而避免消息的重复消费。
- 手动提交偏移量:除了自动提交偏移量,消费者还可以选择手动提交偏移量的方式。在手动提交偏移量的情况下,消费者可以在消费完消息后,显式地调用提交偏移量的API将偏移量提交到Kafka中,以确保已经消费的消息得到正确记录。
- 做幂等性校验: 如果消费者在消费消息时发生错误并重新启动,可能会导致消息被重复消费。在这种情况下,可以通过在消费者端使用幂等性操作或在消息中添加唯一标识符等方式来解决重复消费的问题。
kafka consumer自动提交是怎样的?
Kafka Consumer Offset 自动提交时间是指 Kafka Consumer 自动将消费过的消息的 offset 提交给 Kafka Broker 的时间间隔。Kafka Consumer 在消费消息时会记录消费的 offset,以便在下次消费时从正确的位置开始读取消息。而 Consumer Offset 的提交是由 Consumer 控制的,可以选择手动提交或者自动提交。
在 Kafka 中,有两种自动提交 Consumer Offset 的方式,分别是
- 时间间隔提交
时间间隔提交是指 Consumer 定期自动提交一段时间内消费过的所有消息的 offset,这个时间间隔可以通过配置参数auto.commit.interval.ms
来设置,默认值是 5000 毫秒(5 秒)。 - 消费数量提交。
需要注意的是,开启自动提交 Consumer Offset 的功能可能会导致一些消息重复消费或者消费顺序错乱的情况,因此在实际应用中需要根据具体场景来决定是否开启自动提交 Consumer Offset 的功能,以及选择合适的提交方式。如果要保证消息不会被重复消费或消费顺序不会错乱,可以考虑使用手动提交 Consumer Offset 的方式来控制 offset 的提交。
RabbitMQ⏲
RocketMQ
RocketMQ有哪些组件
RocketMQ主要有四大核心组成部分:NameServer、Broker、Producer以及Consumer四部分。
- NameServer:Name Server是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。NameServer 是整个 RocketMQ 的 “中央大脑 “ ,它是 RocketMQ 的服务注册中心,所以 RocketMQ 需要先启动 NameServer 再启动 Rocket 中的 Broker。
- Broker: 消息服务器,作为Server提供消息核心服务, 它接收并存储Producer生产的消息,也提供消息给Consumer消费。Broker一般会分主从,Master 可读可写,Slave 只读。
- Producer: 消息生产者,消息的发送方,负责生产消息传输给broker。RocketMQ提供了发送:同步、异步和单向(one-way)的多种模式。
- Consumer: 消息消费者,消息的处理方,负责从broker获取消息并进行业务逻辑处理。
另外其他如 Topic、 Message,也是重要的组成部分:
- Topic:主题,发布/订阅模式下的消息统一汇集地,不同生产者向topic发送消息,由MQ服务器分发到不同的订阅者,实现消息的广播
- Message:消息体,根据不同通信协议定义的固定格式进行编码的数据包,来封装业务数据,实现消息的传输。
分布式概览
分布式概念
分布式基础
什么是分布式?
为什么要分布式?
分布式的缺点是怎样的?
1. 和集中式相比,功能之间的调用使用的是接口调用,而不是直接调用。需要编写稳定有效的API。
2. 分布式系统之间的通信无法直接通知,需要使用消息机制(MQ)进行通知。
3. 分布式开发涉及到多个开发团队,开发过程中需要频繁的进行沟通
4. 分布式开发中测试更加复杂,有效的测试用例可以帮助我们更好的剥离项目逻辑与协调组件系统。而小的集中系统开发甚至可以不使用测试用例。
5. 集中式系统开发可以使用debug从头到尾进行调试,而分布式层次太深,组件调用太多,使用debug很难整体调试。需要有效使用日志组件,更好的帮助我们找到问题。
什么是强一致性, 弱一致性, 最终一致性?
强一致性
任何一次读都能读到某个数据的最近一次写的数据。系统中的所有进程,看到的操作顺序,都和全局时钟下的顺序一致。简言之,在任意时刻,所有节点中的数据是一样的。
弱一致性
数据更新后,如果能容忍后续的访问只能访问到部分或者全部访问不到,则是弱一致性。
最终一致性
不保证在任意时刻任意节点上的同一份数据都是相同的,但是随着时间的迁移,不同节点上的同一份数据总是在向趋同的方向变化。简单说,就是在一段时间后,节点间的数据会最终达到一致状态。
由于分布式事务方案,无法做到完全的ACID的保证,没有一种完美的方案,能够解决掉所有业务问题。因此在实际应用中,会根据业务的不同特性,选择最适合的分布式事务方案。
什么是幂等性?⭐
幂等性指的是重复操作的结果是相同的.
幂等性常在以下问题中出现:
- 前端重复提交: 用户在填写某些
form表单
时,保存按钮不小心快速点了两次,表中竟然产生了两条重复的数据,只是id不一样。 - 接口超市重试: 开发人员在项目中为了解决
接口超时
问题,通常会引入了重试机制
。第一次请求接口超时了,请求方没能及时获取返回结果(此时有可能已经成功了),于是会对该请求重试几次,这样也会产生重复的数据。 - 消费重复消息: mq消费者在读取消息时,有时候会读取到
重复消息
,也会产生重复的数据。
如何保证幂等性?⭐
保证幂等性的方法有前端控制, 唯一标识符检查, 唯一索引, 悲观锁, 乐观锁, 分布式锁.
- 前端控制: 点击后置灰或者跳转到另一个界面
- 唯一标识符: 进入表单页面时会请求一个唯一token, 服务端返回唯一token并存入redis, 客户端提交业务请求时携带token, 服务端先删除token, 可以删除则表明第一次处理进行业务操作, 否则提示重复操作.
- 唯一索引: 唯一索引插入重复数据时会抛出异常, 可以用于插入, 更新, 删除业务操作
- 悲观锁: 在获取数据时加锁, 当有重复请求则其他请求无法操作.
- 乐观锁: 基于版本号, 当更新时先查询获得版本号, 更新时对比当前的版本号和查询时的版本号是否一致.
- 分布式锁
微服务架构的服务粒度如何确定? 服务怎么通信?
确定微服务架构中的服务粒度是一个关键的设计决策,它直接影响到系统的灵活性、可维护性和性能。以下是一些常见的指导原则来确定服务粒度:
- 单一责任原则(Single Responsibility Principle):每个服务应该具有清晰的职责和功能,只负责解决一个特定的业务问题。将服务拆分成较小的粒度可以提高可维护性和可测试性,降低变更的影响范围。
- 高内聚低耦合(High Cohesion Low Coupling):服务内部的组件和模块应该具有高内聚,即相互关联的功能应该放在同一个服务内部。同时,服务之间的耦合应该尽量降低,通过明确定义的接口进行通信。
- 业务边界(Business Boundaries):根据业务领域的不同,将相关的功能打包成一个服务。这样可以实现业务的自治性和独立性,提高团队的效率。
- 可扩展性和性能考虑:考虑系统的可扩展性和性能需求,合理划分服务粒度。过大的服务可能导致性能瓶颈和扩展困难,而过小的服务可能会增加通信开销和管理复杂性。
关于服务之间的通信,常见的方式有以下几种:
- HTTP/REST:使用基于HTTP协议的RESTful接口进行通信。这是一种常见的轻量级通信方式,易于理解和实现。
- RPC(Remote Procedure Call):使用RPC框架进行服务之间的远程调用。RPC框架可以隐藏底层通信细节,提供类似本地方法调用的方式,如Dubbo、gRPC等。
- 消息队列(Message Queue):使用消息队列作为服务之间的通信媒介,通过发布订阅模式或点对点模式进行消息传递。常见的消息队列包括Kafka、RabbitMQ、ActiveMQ等。
- 事件驱动(Event-driven):使用事件驱动架构进行服务之间的通信,通过发布事件和订阅者模式实现解耦。常见的事件驱动框架有Spring Cloud Stream、Apache Kafka Streams等
分布式理论⭐
知道CAP原则吗?为什么CAP不可兼得?⭐
CAP分别指Consistency(一致性), Availability(可用性), Partition tolerance(分区容错性), 一致性指的是写操作后读操作必须返回该值, 可用性是指只要收到用户的请求服务器必须给出回应, 而分区容错性指的是区间的通信可能失败, 一般来说P一定是成立的, CAP理论就是说P成立的情况下A和P无法同时做到.
在写A服务器时, 如果要保证B的一致性, 所以在A写的时候B的写和读都被锁定, 只有数据同步后才能开发读写, 所以这时候没有B没有可用性.
如果要保证B的可用性, 一定不能锁定B的读写,那这时候一致性就没有了.
CAP各模型常见的应用有哪些?
CP, 保证一致性不保证可用性:
相当于每个请求都需要在Server之间强一致,而P(分区)会导致同步时间无限延长,如此CP也是可以保证的。很多传统的数据库分布式事务都属于这种模式。
CP模型的常见应用:
- 分布式数据库
- 分布式锁
AP 保证可用性不保证一致性
要高可用并允许分区,则需放弃一致性。一旦分区发生,节点之间可能会失去联系,为了高可用,每个节点只能用本地数据提供服务,而这样会导致全局数据的不一致性。现在众多的NoSQL都属于此类。
AP模型常见应用:
- Web缓存
- DNS
举个大家更熟悉的例子,像我们熟悉的注册中心ZooKeeper
、Eureka
、Nacos
中:
- ==ZooKeeper 保证的是 CP==
- ==Eureka 保证的则是 AP==
- ==Nacos 不仅支持 CP 也支持 AP==
BASE理论了解吗?⭐
BASE理论是对分布式系统中可用性和一致性之间的权衡进行的一种观点。BASE是”Basically Available, Soft State, Eventually Consistent”的缩写,分别代表以下三个概念:
Basically Available(基本可用):系统保证在面对部分故障或者分区失败的情况下,仍然能够提供基本的可用性和响应性能。这意味着系统应该始终保持对外提供服务,尽管在某些时候可能会出现性能下降或数据不一致的情况。
Soft State(软状态):多个节点数据副本都是一致的, 这是一种”硬状态”。这意味着系统中的数据在不同节点之间可能存在一段时间的不一致,但最终会趋于一致。
Eventually Consistent(最终一致性):系统中的数据最终会在不同节点之间达到一致状态,但这个一致性的过程可能需要一定的时间。系统不会强制要求实时的一致性,而是通过异步的方式,通过后续的数据同步和修复来实现一致性。
BASE理论强调了在分布式系统设计中的可用性和性能,相对于传统的ACID(Atomicity、Consistency、Isolation、Durability)模型,它提供了更高的可伸缩性和容错性,适用于大规模分布式系统和云计算环境。然而,BASE也带来了数据一致性的挑战,需要在应用程序设计中考虑如何处理数据的最终一致性和冲突解决。
分布式通信协议
Gossip协议是什么
Gossip 协议是一种用于分布式系统中节点之间通信和信息传播的协议。它是一种去中心化的协议,通过节点之间的相互交流和信息交换来维护全局一致的状态。
Gossip 协议的核心思想是节点之间相互交换信息并随机选择其他节点进行通信。当一个节点收到新的信息时,它会将这些信息广播给一些其他随机选择的节点,这些节点会进一步将信息广播给其他节点。通过这种信息的传播方式,整个系统中的节点逐渐收敛到一致的状态。
在 Gossip 协议中,每个节点都维护一个本地的状态和信息列表。节点周期性地选择一些其他节点进行通信,并将本地的状态和信息发送给这些节点。接收到信息的节点会将其合并到自己的状态中,同时继续进行信息的传播。
Gossip 协议具有以下特点:
去中心化:每个节点都是平等的,没有中心节点或协调者。节点通过相互通信来达成共识和一致性。
随机选择:节点随机选择其他节点进行通信,避免了集中式的节点选择策略,增加了系统的鲁棒性和扩展性。
信息传播:通过节点之间的信息传播和交流,整个系统逐步达到一致状态,保证了分布式系统的一致性和可靠性。
Gossip 协议在许多分布式系统中得到广泛应用,如分布式数据库、分布式存储系统和对等网络等。它通过去中心化和随机化的方式,提供了一种高效且容错的通信机制,使得分布式系统能够有效地处理节点故障和数据一致性的问题。
分布式锁⭐
常见的分布式锁的实现方案都有哪些?:star:
常见的分布式锁实现方案有三种:MySQL分布式锁
、ZooKepper分布式锁
、Redis分布式锁
。
Mysql分布式锁
MySQL实现分布式锁的原理是主键的冲突和字段的检查, 方式是
- 基于表的锁: 创建一个锁表, 然后分布式系统申请一个锁就增加一条记录, 释放锁就删除一条记录, 当插入时主键冲突的时候表明锁正在占用
- 基于行的锁: 在现有的业务中增加一个用于锁的字段, 申请锁后则置为1, 释放锁则置0, 当为1时锁正在被占用
一般不用mysql做分布式锁, 因为IO操作效率不高且开销大.
Zookeeper分布式锁
Zookeeper实现分布式锁的原理利用临时顺序节点的特性和节点监听机制, 方式是
- 创建一个锁目录
- 尝试获取锁: 需要获取锁的进程在锁目录下创建临时节点, 创建时会分配一个唯一的序列号
- 检查锁状态: 获取锁的进程检查节点序列号是否是最小节点, 如果是则获取到了锁, 如果不是一般注册Watcher来监听前一个节点的删除来继续获取锁
- 释放锁: 删除临时节点, 释放锁资源, 并且会通知给其他等待的线程.
需要注意的是,ZooKeeper提供的分布式锁机制并不是绝对可靠的,它可能存在”羊群效应”(Herd Effect)和”惊群效应”(Thundering Herd Effect)等问题。因此,在使用ZooKeeper实现分布式锁时,需要仔细考虑锁的获取和释放的策略,以及处理异常情况和竞争条件的处理方式。
Redis分布式锁
Redis分布式锁的原理是利用Redis单线程的特性, 方式是
使用setNx key value
, 如果不存在则设置值, 如果设置成功则获取锁成功, 释放锁是删除掉这个key
一般生产中使用Redission, 封装了分布式锁的Api.
分布式事务⭐
分布式事务解决方案都有哪些?⭐
常见的分布式事务的解决方案有7种,2PC, 3PC, TCC, 本地消息表, 消息事务, 最大努力, sagas.
2PC(两阶段提交):
两阶段是指准备阶段和提交阶段, 尽量保证了数据的强一致, 实现成本较低, 但是有单点故障问题和阻塞的风险.
单点故障: 事务管理器非常重要, 要是在第二阶段正准备提交时故障, 则资源管理器会一直阻塞.
同步阻塞: 在准备就绪之后,资源管理器中的资源一直处于阻塞,直到提交完成,释放资源。
3PC(三阶段提交):
相比2PC加了预提交阶段和超时特性, 超时作用于预提交阶段, 如果预提交阶段事务管理器宕机或者没有收到确认, 则回到准备阶段之前, 如果提交阶段是超时, 则参与者提交事务.
TCC
TCC(Try Confirm Cancel) ,是两阶段提交的一个变种,针对每个操作,都需要有一个其对应的确认和取消操作,当操作成功时调用确认操作,当操作失败时调用取消操作,类似于二阶段提交,只不过是这里的提交和回滚是针对业务上的,所以基于TCC实现的分布式事务也可以看做是对业务的一种补偿机制。
TCC 是业务层面的分布式事务,保证最终一致性,不会一直持有资源的锁。
- 优点: 把数据库层的二阶段提交交给应用层来实现,规避了数据库的 2PC 性能低下问题
- 缺点:TCC 的 Try、Confirm 和 Cancel 操作功能需业务提供,开发成本高。TCC 对业务的侵入较大和业务紧耦合,需要根据特定的场景和业务逻辑来设计相应的操作
本地消息表
本地消息表的核心思想是将分布式事务拆分成本地事务进行处理。
例如,可以在订单库新增一个消息表,将新增订单和新增消息放到一个事务里完成,然后通过轮询的方式去查询消息表是否完成,将没完成的消息推送到MQ,库存服务去消费MQ。而另一个服务接收MQ消息自执行修改库存事务, 如果修改成功则调用rpc接口修改消息表的状态或者直接删除这条消息, 如果修改失败再做重试.
需要注重两个问题:
- 消息一直重复发送的问题, 所以需要记录发送次数达到一定量时报警人工处理
- 库存服务要保证幂等性, 避免多次消费造成不一致
本地消息表这种方案实现了最终一致性,需要在业务系统里增加消息表,业务逻辑中多一次插入的DB操作,所以性能会有损耗,==而且最终一致性的间隔主要有定时任务的间隔时间决定==
MQ消息事务
消息事务的原理是将两个事务「通过消息中间件进行异步解耦」,和上述的本地消息表有点类似,但是是通过消息中间件的机制去做的,其本质就是’将本地消息表封装到了消息中间件中’。
执行流程:
- 发送prepare消息到消息中间件
- 发送成功后,执行本地事务
- 如果事务执行成功,则commit,消息中间件将消息下发至消费端
- 如果事务执行失败,则回滚,消息中间件将这条prepare消息删除
- 消费端接收到消息进行消费,如果消费失败,则不断重试
这种方案也是实现了「最终一致性」,对比本地消息表实现方案,不需要再建消息表,「不再依赖本地数据库事务」了,所以这种方案更适用于高并发的场景。目前市面上实现该方案的「只有阿里的 RocketMQ」。
最大努力通知
最大努力通知相比实现会简单一些,适用于一些对最终一致性实时性要求没那么高的业务,比如支付通知,短信通知。
以支付通知为例,业务系统调用支付平台进行支付,支付平台进行支付,进行操作支付之后支付平台会去同步通知业务系统支付操作是否成功,如果不成功,会一直异步重试,但是会有一个最大通知次数,如果超过这个次数后还是通知失败,就不再通知,业务系统自行调用支付平台提供一个查询接口,供业务系统进行查询支付操作是否成功。
saga模式
Saga事务模型又叫做长时间运行的事务
其核心思想是「将长事务拆分为多个本地短事务」,由Saga事务协调器协调,如果正常结束那就正常完成,如果「某个步骤失败,则根据相反顺序一次调用补偿操作」。
能介绍一下Seata分布式事务框架吗?
Seata的核心设计思想是将分布式事务分为全局事务和分支事务。全局事务是一个包含多个分支事务的上下文,它负责协调和管理分支事务的提交或回滚。分支事务是实际的业务操作,可以是数据库操作、消息发送等。
Seata 中存在这么几种重要角色:
- TC(Transaction Coordinator):事务协调者。管理全局的分支事务的状态,用于全局性事务的提交和回滚。
- TM(Transaction Manager):事务管理者。用于开启、提交或回滚事务。
- RM(Resource Manager):资源管理器。用于分支事务上的资源管理,向 TC 注册分支事务,上报分支事务的状态,接收 TC 的命令来提交或者回滚分支事务。
Seata整体执行流程:
- 服务A中的 TM 向 TC 申请开启一个全局事务,TC 就会创建一个全局事务并返回一个唯一的 XID
- 服务A中的 RM 向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
- 服务A开始执行分支事务
- 服务A开始远程调用B服务,此时 XID 会根据调用链传播
- 服务B中的 RM 也向 TC 注册分支事务,然后将这个分支事务纳入 XID 对应的全局事务管辖中
- 服务B开始执行分支事务
- 全局事务调用处理结束后,TM 会根据有误异常情况,向 TC 发起全局事务的提交或回滚
- TC 协调其管辖之下的所有分支事务,决定是提交还是回滚
Seata支持的四大事务模式是什么?-GPT⭐
- AT(自动化事务)模型:AT模型是Seata的默认事务模型。它通过在每个参与者上自动化地将业务操作转化为本地事务,使用数据库的ACID特性来保证事务的一致性和隔离性。在AT模型下,Seata框架会拦截和管理数据库操作,并在全局事务提交或回滚时协调各个参与者的本地事务。
- TCC(Try-Confirm-Cancel)模型:TCC模型是一种补偿性事务模型,用于处理分布式事务。在TCC模型中,每个参与者需要实现Try、Confirm和Cancel三个操作。Try操作用于尝试执行业务逻辑和预留资源,Confirm操作用于确认提交事务,Cancel操作用于回滚事务。Seata框架在全局事务提交或回滚时会调用相应的参与者方法来执行对应的操作。
- SAGA模型:Seata框架支持SAGA模式的分布式事务。在SAGA模型中,事务被拆分为一系列的局部事务步骤,每个步骤代表一个原子性操作。每个步骤都有一个正常执行操作和一个补偿操作,用于保证系统的一致性。Seata框架通过协调和执行每个步骤的操作,实现整体事务的提交或回滚。
- XA模型:XA模型是一种经典的分布式事务协议。Seata框架通过与支持XA协议的数据库进行交互,实现分布式事务的管理和协调。在XA模型中,Seata框架作为全局事务的协调器,与各个事务参与者进行通信,并控制全局事务的提交或回滚。
分布式一致性算法
一致性模型
分布式系统中的一致性模型
读写不再是一个瞬时的过程,而是一个类似光传播->反射面->反向传播的过程。**
线性一致性: 以到达的点的前后顺序为一致性
顺序一致性: 只要求相对的先后顺序, 而并非绝对的到达时间
因果一致性: 对结果产生影响的原因一定在结果的前面发生
串行一致性: 数据库的隔离级别
分布式一致性模型介绍-呆呆
严格一致性
顺序一致性
因果一致性
最终一致性
线性一致性
常见的分布式一致性算法有哪些?-GPT
- Paxos算法:Paxos是一种基于消息传递的一致性算法,用于解决分布式系统中的一致性问题。它通过选举过程和多个阶段的消息交换来达成一致性,保证系统在存在故障和消息丢失的情况下仍能达成共识。
- Raft算法:Raft算法也是一种基于消息传递的一致性算法,旨在提供更好的可理解性和可维护性。它将一致性问题划分为领导者选举、日志复制和安全性等阶段,通过多数投票的方式来达成共识。
- ZAB协议:ZAB(ZooKeeper Atomic Broadcast)协议是ZooKeeper分布式系统中用于实现一致性的协议。它采用了类似于Paxos的两阶段提交机制,通过主从复制和原子广播来保证一致性。
- Gossip协议:Gossip协议是一种基于随机化的分布式协议,用于在节点之间传播信息。它通过节点之间的随机通信来实现信息的传播和一致性,具有较好的可扩展性和容错性。
- Byzantine Fault Tolerance(拜占庭容错)算法:拜占庭容错算法用于处理分布式系统中存在恶意节点(拜占庭故障)的情况。它通过加密、签名和多数投票等机制来检测和排除恶意节点,从而保证系统的一致性和安全性。
分布式限流
分布式限流算法都有哪些?
- 计数器算法(Counting Algorithm):计数器算法简单地对请求进行计数,当请求数量达到一定阈值时,拒绝后续的请求。这种算法比较直接,但容易受到突发流量的影响,需要合理设置阈值。
- 固定窗口算法(Fixed Window Algorithm):固定窗口算法将时间分割成固定的窗口,比如每秒一个窗口。在每个窗口内,限定请求的数量不能超过一个预设的阈值。这种算法容易导致突发流量超出限制,因为它不考虑请求的分布情况。
- 滑动窗口算法(Sliding Window Algorithm):滑动窗口算法在固定窗口算法的基础上进行了改进。它使用一个指定长度的时间窗口,将时间划分为多个小窗口,并计算每个小窗口内的请求数量。通过滑动窗口的方式,限制每个窗口内的请求数量不超过阈值。这种算法相对于固定窗口算法更加平滑,可以更好地应对突发流量。
- 令牌桶算法(Token Bucket Algorithm):令牌桶算法维护一个固定容量的令牌桶,每个令牌代表一个请求。令牌以固定的速率被放入桶中,当请求到来时,需要从桶中获取一个令牌才能被处理。如果桶中没有足够的令牌,则请求需要被延迟处理或丢弃。该算法可以控制请求的速率,并允许一定程度的突发流量。
- 漏桶算法(Leaky Bucket Algorithm):漏桶算法将请求看作水滴,通过固定的速率将请求放入一个容量为固定大小的漏桶中。如果漏桶已满,新的请求将被丢弃。漏桶以固定的速率漏水,即处理请求的速率。该算法可以平滑流量,并控制请求的处理速度。
令牌桶算法和漏铜算法的区别是什么?-GPT
两者的区别:
- 令牌桶算法以固定的速率放入令牌,并根据令牌的可用情况决定请求是否被处理。
- 漏桶算法以固定的速率处理请求,并根据桶的容量决定是否接受新的请求。
- ==令牌桶算法允许一定程度的突发流量,可以在短时间内消耗桶中的令牌,处理更多的请求==。
- ==漏桶算法平滑流量,控制请求的处理速率,即使请求以高于固定速率的速度到达,仍然以固定速率处理请求。==
微服务框架
微服务框架对比
SpringCloud包含的组件很多,有很多功能是重复的。其中最常用组件包括:
- 网关组件:Zuul、Gateway
- 注册中心组件:Eureka、Nacos等
- 负载均衡组件:Ribbon
- 远程调用组件:OpenFeign
- 服务保护组件:Hystrix、Sentinel
- 服务配置管理组件:SpringCloudConfig、Nacos
Dubbo | SpringCloud | SpringCloudAlibaba | |
---|---|---|---|
注册中心 | zookeeper、Redis | Eureka、Consul | Nacos、Eureka |
服务远程调用(RPC) | Dubbo协议 | Feign (http协议) | Dubbo、 Feign |
配置中心 | 无 | SpringCloudConfig | SpringCloudConfig、 Nacos |
服务网关 | 无 | SpringCloudGateway、 Zuul | SpringCloudGateway、Zuul |
服务监控和保护 | dubbo-admin, 功能弱 | Hystrix | Sentinel |
SpringCloud及其组件你了解哪些?⭐
SpringCloud是Spring官方推出的微服务治理框架, 常用则组件有:
- 网关: SpringCloud GateWay 和 Zuul
- 注册中心: Eureka, 提供服务注册发现功能.
- 负载均衡: Ribbon, 进行客户端的负载均衡
- 远程调用: Feign
- 链路追踪: Sleuth
- 服务保护: Hystrix
- 配置中心: Config
微服务之间如何独立通讯的?⭐
同步通信:dobbo通过 RPC 远程过程调用、springcloud通过 REST 接口json调用等。
异步:消息队列,如:RabbitMq
、ActiveM
、Kafka
等消息队列。
Dubbo
Dubbo是什么?
Apache Dubbo 是一款易用、高性能的 WEB 和 RPC 框架,同时为构建企业级微服 务提供服务发现、流量治理、可观测、认证鉴权等能力、工具与最佳实践。
Dubbo的核心特点是什么?
1.快速易用
2.超高性能
3.服务治理
4.生产环境检验
为什么要用Dubbo?
用户量越来越多, 分布式服务架构可以将不同的服务拆分来提供响应速度和用户体验, 而服务越来越多, 服务调用关系越来越负载, 就需要用软件来管理
Dubbo解决了以下问题:
负载均衡: 同一个服务部署在不同的机器时调用哪一台机器的服务.
服务调用链路生成: 服务依赖关系比较复杂后, Dubbo可以解决服务之间互相是如何调用的.
服务访问压力以及市场统计, 资源调度和治理: 基于访问压力实时管理集群容量, 提高集群利用率.
另外,Dubbo 除了能够应用在分布式系统中,也可以应用在现在比较火的微服务系统中。不过,由于 Spring Cloud 在微服务中应用更加广泛,所以,我觉得一般我们提 Dubbo 的话,大部分是分布式系统的情况.
Dubbo架构中有哪些组成部分?⭐
- 服务提供者(Provider): 服务提供者是Dubbo架构中提供实际服务的应用程序。它将自己提供的服务注册到注册中心,并接收来自服务消费者的远程调用请求,执行相应的服务逻辑并返回结果。
- 服务消费者(Consumer): 服务消费者是Dubbo架构中需要使用某项服务的应用程序。它从注册中心获取服务提供者的地址信息,并通过远程调用方式调用服务提供者的方法,获取返回结果。
- 注册中心(Registry): 注册中心是Dubbo架构中用于服务注册与发现的组件。它维护了服务提供者和服务消费者的注册信息,并提供查询接口供服务消费者查找可用的服务提供者地址。
- 监控中心(Monitor): 监控中心是Dubbo架构中用于监控和统计服务调用情况的组件。它收集各个服务提供者和服务消费者的运行状态、调用次数、响应时间等数据,并提供可视化的监控界面和报表分析功能。
- 远程调用(Remote Invocation): 远程调用是Dubbo架构中服务提供者和服务消费者之间进行通信的方式。Dubbo支持多种通信协议(如Dubbo协议、RMI协议、Hessian协议、HTTP协议等)和序列化协议(如Java原生序列化、Hessian、JSON、FastJson等),通过代理和序列化技术实现远程调用。
- 配置中心(Config Center): 配置中心是Dubbo架构中用于统一管理服务配置信息的组件。它可以将服务的配置信息集中存储,并提供动态刷新配置的能力,从而实现灵活的配置管理和运行时配置的变更。
这些组成部分共同协作,构成了Dubbo架构,实现了服务的注册与发现、远程调用、负载均衡、容错等关键功能,帮助简化分布式系统的开发和管理。
Dubbo的工作原理讲一讲?⭐
==Dubbo的工作原理可以简化为服务提供者注册服务到注册中心,服务消费者从注册中心获取可用的服务提供者地址列表,选择合适的服务提供者进行远程调用,然后处理调用结果。==
- 服务暴露: 首先,服务提供者(Provider)需要将自己提供的服务注册到注册中心。服务提供者会将服务的接口、实现类、地址等信息注册到注册中心,使得服务消费者能够发现并调用该服务。
- 服务发现: 服务消费者(Consumer)在需要调用某个服务时,会向注册中心发送服务查询请求,获取可用的服务提供者地址列表。注册中心返回可用的服务提供者地址给服务消费者。
- 负载均衡: 服务消费者在获得服务提供者地址列表后,根据负载均衡策略选择一个合适的服务提供者进行远程调用。Dubbo支持多种负载均衡策略,如随机(Random)、轮询(RoundRobin)、最少活跃调用数(LeastActive)等。
- 远程调用: 服务消费者通过远程调用方式将请求发送给选择的服务提供者。Dubbo支持多种通信协议(如Dubbo协议、RMI协议、Hessian协议、HTTP协议等)和序列化协议(如Java原生序列化、Hessian、JSON、FastJson等),通过代理和序列化技术实现服务的远程调用。
- 容错处理: 在服务调用过程中,Dubbo提供了多种容错机制来处理服务提供者的故障或不可用情况。例如,Dubbo支持失败重试(Failover)机制,在服务调用失败时自动重试其他可用的服务提供者,以增加系统的可靠性。
- 响应返回: 服务提供者在收到请求后,执行相应的服务逻辑并返回结果给服务消费者。服务消费者接收到结果后进行处理。
Dubbo的Invoker概念了解吗?⭐
在Dubbo中,Invoker是Dubbo框架用于表示可调用的远程服务的接口。它是Dubbo中服务调用的核心对象。Invoker接口定义了对远程服务的调用操作,并提供了调用所需的参数、方法、目标地址等信息。
Dubbo中的Invoker接口有两个主要实现类:
- ProviderInvoker: ProviderInvoker是服务提供者(Provider)端的Invoker实现。它封装了服务提供者的实现类、方法、参数等信息,并提供了对服务的本地执行操作。
- ClusterInvoker: ClusterInvoker是服务消费者(Consumer)端的Invoker实现。它封装了服务消费者的请求信息、负载均衡策略、容错机制等,并通过Dubbo的集群容错策略来选择合适的服务提供者进行调用。
==Dubbo的Invoker通过代理模式实现服务的远程调用。在服务消费者端,Dubbo会根据配置生成动态代理对象,拦截接口方法的调用,并通过Invoker将请求发送到服务提供者端。在服务提供者端,Dubbo会根据Invoker中的信息,调用实际的服务提供者实现类,并将结果返回给服务消费者==。
Dubbo的SPI机制了解么?如何扩展Dubbo中的默认实现?⭐
Dubbo的SPI机制是一种用于扩展框架功能的机制。通过SPI机制,Dubbo提供了一种标准的扩展点加载机制,使得用户可以在不修改框架源码的情况下,通过配置文件或注解的方式,动态加载和替换Dubbo框架中的默认实现。
Dubbo SPI机制的关键要点和使用方式:
- 扩展点接口定义: Dubbo的扩展点接口是指框架定义的允许用户扩展的接口。这些接口通常有多个实现,用户可以根据需求选择合适的实现。
- 扩展点接口的实现: Dubbo的扩展点接口的实现类需要通过在类上添加
@SPI
注解进行标记,指定该类为扩展点的默认实现。同时,实现类需要在类路径下的META-INF/dubbo
目录下创建以扩展点接口全限定名为名称的文件,文件中列出该接口的所有实现类。 - 扩展点的加载和获取: Dubbo使用自定义的类加载器加载扩展点,并将加载后的实现类封装成ExtensionLoader对象。通过ExtensionLoader对象可以获取到扩展点接口的实例。
- 扩展点的配置: 用户可以通过在配置文件中指定扩展点的实现类,或者在代码中使用
@SPI
注解指定扩展点的实现类。Dubbo会根据配置文件或注解的信息来加载指定的扩展点实现。
Dubbo的微内核架构了解吗
Dubbo采用了微内核架构,这是一种软件架构设计模式,通过将核心功能和可扩展功能分离,使得系统更加灵活、可扩展和易于维护。Dubbo的微内核架构将核心功能抽象为一个轻量级的内核(Microkernel),而将扩展功能作为插件(Extension)进行实现。
在Dubbo的微内核架构中,内核负责处理核心的通用逻辑,包括服务调用、负载均衡、容错处理、线程池管理等。它提供了一组标准的接口和实现,包括Protocol、Exchange、Cluster、Registry等。这些核心接口和实现是Dubbo框架的基础。
而对于各种扩展功能,Dubbo提供了可插拔的扩展点机制。用户可以根据自己的需求,通过实现Dubbo提供的扩展点接口,并将实现类注册到内核中,从而扩展Dubbo的功能。例如,负载均衡、容错处理、序列化等都是通过扩展点的形式提供的,用户可以根据需要选择合适的扩展实现。
Dubbo提供的负载均衡策略有哪些?⭐
以下是Dubbo提供的一些常用负载均衡策略:
- Random(随机): 随机选择一个可用的服务提供者进行调用。
- RoundRobin(轮询): 按照轮询的方式依次选择可用的服务提供者。每个服务提供者会被平均选中,逐个进行调用。
- LeastActive(最少活跃调用数): 根据服务提供者的活跃调用数,选择活跃调用数最少的服务提供者进行调用。活跃调用数指的是当前正在处理请求的线程数。
- ConsistentHash(一致性哈希): 将请求的参数或其他标识进行哈希计算,然后根据哈希值选择一个服务提供者。相同的参数会被路由到同一个服务提供者上,适用于需要保持会话的场景。
- WeightedRandom(加权随机): 按照服务提供者的权重随机选择一个可用的服务提供者。权重越高的服务提供者被选中的概率越大。
- WeightedRoundRobin(加权轮询): 按照服务提供者的权重进行轮询选择。每个服务提供者被选中的次数与其权重成正比。
Dubbo支持哪些序列化方式?⭐
Dubbo支持多种序列化协议,包括Java原生序列化、Hessian、JSON、FastJson等。开发人员可以根据实际需求选择合适的序列化协议。
Dubbo的集群容错机制有哪些?⭐
以下是Dubbo常用的集群容错机制:
- Failover(失败自动切换): Failover是Dubbo的默认集群容错机制。当调用失败时,Failover会自动切换到另一个可用的服务提供者进行重试,直到调用成功或达到最大重试次数。
- Failfast(快速失败): Failfast是一种快速失败的集群容错机制。在调用过程中,只尝试一次调用,若调用失败,则立即报错。适用于对响应时间要求较高的场景。
- Failsafe(失败安全): Failsafe是一种失败安全的集群容错机制。在调用失败时,Failsafe会忽略错误,仅记录日志,不会抛出异常。适用于日志记录、监控等不重要的操作。
- Failback(失败自动恢复): Failback是一种失败自动恢复的集群容错机制。当调用失败时,Failback会在后台记录失败的请求,并定期重发,直到调用成功。
- Forking(并行调用): Forking是一种并行调用的集群容错机制。当调用失败时,Forking会同时发起多个请求,并等待第一个成功返回的结果,忽略其他的请求。
- Broadcast(广播调用): Broadcast是一种广播调用的集群容错机制。调用会发给所有的服务提供者,并将结果合并后返回。适用于广播通知等场景。
dubbo的客户端服务端的数据处理过程?⭐
在Dubbo中,客户端和服务端之间的数据处理过程包括以下步骤:
- 客户端调用:客户端通过本地代理对象发起远程调用,调用对应的服务接口方法。
- 序列化:客户端将方法调用参数进行序列化,将方法名、参数等数据转换为字节流,以便在网络中传输。
- 网络传输:客户端将序列化后的数据通过网络传输到服务端。Dubbo支持多种网络通信协议,如TCP、HTTP等。
- 反序列化:服务端接收到客户端发送的数据后,进行反序列化操作,将字节流转换为方法调用的参数。
- 调用服务:服务端根据接收到的方法调用信息,执行对应的服务实现逻辑,并获取结果。
- 序列化:服务端将方法调用结果进行序列化,将结果转换为字节流。
- 网络传输:服务端将序列化后的结果通过网络传输回客户端。
- 反序列化:客户端接收到服务端发送的结果数据后,进行反序列化操作,将字节流转换为方法调用的结果。
- 返回结果:客户端将反序列化后的结果返回给调用方,完成远程调用过程。
网关
Gateway
什么是Spring Gateway?
- Spring Gateway是基于Spring Framework和Spring Boot的反应式API网关,用于构建微服务架构中的边缘服务。
Spring Gateway的主要特性有哪些?⭐
- 路由和负载均衡:通过定义路由规则将请求转发到后端服务,并支持负载均衡策略。
- 过滤器:可以对请求和响应进行预处理和后处理,如鉴权、日志记录等。
- 断路器:提供断路器模式,用于故障熔断和服务降级。
- 限流:支持基于请求速率的限流,防止流量过载。
- 重试:在请求失败时支持自动重试机制。
- 动态路由:支持动态添加、修改和删除路由规则,无需重启网关服务器。
Spring Gateway与Zuul相比有什么优势?
- 性能:Spring Gateway使用了Reactor和WebFlux的异步非阻塞处理模型,具有更高的性能和吞吐量。
- 编程模型:Spring Gateway使用了函数式编程模型,使得路由和过滤器的定义更加简洁和灵活。
- 响应式支持:Spring Gateway完全支持响应式编程,适用于构建反应式微服务架构。
- 扩展性:Spring Gateway的设计更加模块化,可以方便地扩展和定制。
Spring Gateway如何实现动态路由?
- Spring Gateway通过与服务注册中心(如Consul、Eureka)的集成,可以实现动态路由。它可以自动从服务注册中心获取服务的实例信息,并根据路由规则将请求转发到合适的服务实例。
Spring Gateway如何实现请求过滤和处理?
- Spring Gateway使用过滤器来实现请求过滤和处理。它提供了预定义的过滤器,如鉴权、日志记录等,同时也支持自定义过滤器来满足特定需求。
Spring Gateway如何处理故障和异常?
- Spring Gateway提供了断路器模式,用于故障熔断和服务降级。通过配置断路器规则,当后端服务出现故障或异常时,可以快速失败或返回预定义的默认响应。
Spring Gateway如何实现请求限流和重试机制?
- Spring Gateway提供了请求限流的功能,可以基于请求速率对流量进行限制,防止过载。同时,它也支持自动重试机制,当请求失败时可以进行自动重试。
断路器是什么?
在Spring Gateway中,断路器(Circuit Breaker)是一种用于处理故障熔断和服务降级的机制。它的作用是在后端服务发生故障或异常时,阻止请求继续访问该服务,并提供一种替代的响应,以保护系统的稳定性和可靠性。
断路器的原理是根据一定的条件监控后端服务的状态,并在达到预设的阈值时打开断路器。一旦断路器打开,所有的请求将不再直接发送到后端服务,而是立即返回一个预先定义的默认响应(通常是一个错误信息或者是服务降级的响应)。这样可以避免不稳定的后端服务对整个系统的影响。
断路器还有一个重要的功能,即当后端服务出现故障后一段时间后,断路器会进入半开状态,允许部分请求通过以检查服务是否恢复正常。如果这些请求成功,则断路器将关闭,恢复正常的请求转发。否则,断路器将再次打开,阻止后续请求。
Spring Gateway内置了断路器模式的支持,通过使用断路器模式可以保护网关和后端服务之间的通信。开发人员可以根据需要配置断路器的相关参数,如故障阈值、时间窗口、响应超时时间等,以适应不同的应用场景,并通过定义降级响应来提供良好的用户体验。
注册中心
Zookeeper, Nacos, Eureka
什么是注册中心?
微服务中, 一个服务要调用其他服务, 就需要知道其他服务的信息, 所以需要一个东西来管理这些微服务的地址和信息通知给其他服务, 这就是注册中心, 注册中心的主要功能就是服务注册和服务发现, 服务注册指的是服务提供者在注册中心进行注册, 并且通过心跳进行续约, 而服务的消费者进行服务发现, 来调用服务提供者提供的服务.
Nacos和Eureka的区别?⭐
Nacos与eureka的共同点
- 都支持服务注册和服务拉取
- 都支持服务提供者心跳方式做健康检测
Nacos与Eureka的区别
- Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
- 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
- Nacos支持服务列表主动变更的消息推送模式,服务列表更新更及时
- Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式
Eureka
什么是Eureka
- Eureka作为SpringCloud的服务注册功能服务器,他是服务注册中心,系统中的其他服务使用Eureka的客户端将其连接到Eureka Service中,并且保持心跳,这样工作人员可以通过Eureka Service来监控各个微服务是否运行正常。
Eureka怎么实现高可用
- 集群吧,注册多台Eureka,然后把SpringCloud服务互相注册,客户端从Eureka获取信息时,按照Eureka的顺序来访问。
什么是Eureka的自我保护模式
- 默认情况下,如果Eureka Service在一定时间内没有接收到某个微服务的心跳,Eureka Service会进入自我保护模式,在该模式下Eureka Service会保护服务注册表中的信息,不在删除注册表中的数据,当网络故障恢复后,Eureka Servic 节点会自动退出自我保护模式
DiscoveryClient的作用
- 可以从注册中心中根据服务别名获取注册的服务器信息。
Eureka和ZooKeeper都可以提供服务注册与发现的功能,请说说两个的区别⭐
ZooKeeper中的节点服务挂了就要选举 在选举期间注册服务瘫痪,虽然服务最终会恢复,但是选举期间不可用的, 选举就是改微服务做了集群,必须有一台主其他的都是从
Eureka各个节点是平等关系,服务器挂了没关系,只要有一台Eureka就可以保证服务可用,数据都是最新的。 如果查询到的数据并不是最新的,就是因为Eureka的自我保护模式导致的
Eureka本质上是一个工程,而ZooKeeper只是一个进程
Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像ZooKeeper 一样使得整个注册系统瘫痪
ZooKeeper保证的是CP,Eureka保证的是AP
CAP: C:一致性>Consistency; 取舍:(强一致性、单调一致性、会话一致性、最终一致性、弱一致性) A:可用性>Availability; P:分区容错性>Partition tolerance;
Nacos
Nacos的核心功能有哪些?⭐
Nacos的核心功能包括:
- 服务注册和发现:通过Nacos实现服务的注册和发现,方便服务之间的通信和调用。
- 配置管理:Nacos可以集中管理配置信息,支持动态刷新和变更通知。
- 服务健康监测:Nacos可以定期检查服务的健康状态,并提供实时的健康检查结果。
- 动态路由和负载均衡:Nacos可以实现服务的动态路由和负载均衡,根据服务的实际情况进行请求转发。
- 服务降级和故障熔断:Nacos提供了服务的降级和故障熔断机制,保证系统在故障情况下的稳定性。
- 配置共享和权限管理:Nacos支持配置的共享和权限管理,确保配置的安全性和可控性。
Nacos是如何实现服务注册和发现的?
Nacos通过服务提供者在启动时向Nacos注册自己的服务信息,包括服务名、IP地址、端口等。服务消费者通过向Nacos发起服务发现请求,Nacos返回可用的服务实例列表,消费者可以从中选择合适的实例进行服务调用。
Nacos支持哪些服务发现的协议?⭐
Nacos支持三种服务发现的协议:基于HTTP/REST的服务发现、基于DNS的服务发现和基于RPC的服务发现。借助这些协议,开发人员可以根据实际需求选择合适的方式来进行服务发现。
Nacos的配置管理功能是如何实现的?
Nacos提供了一个统一的配置管理界面,开发人员可以通过该界面进行配置的创建、修改和删除。配置信息存储在Nacos的持久化存储中,可以根据需要进行动态刷新。同时,Nacos支持配置的监听和通知机制,当配置发生变化时,Nacos会通知订阅了该配置的客户端进行相应的更新。
Nacos支持哪些配置管理的数据源类型?
Nacos支持多种数据源类型的配置管理,包括文件类型(如properties、yaml)、JSON类型和XML类型。开发人员可以根据自己的需求选择适合的
Nacos支持动态配置刷新吗?如何实现配置的动态刷新?
是的,Nacos支持动态配置刷新。当配置发生变化时,Nacos会自动通知订阅了该配置的客户端进行刷新。客户端可以通过监听配置的变化事件,在收到通知后重新加载最新的配置。
Nacos的持久化存储是如何实现的?
Nacos的持久化存储是通过使用关系型数据库(如MySQL)或者本地文件系统来实现的。Nacos将注册的服务信息、配置数据和元数据等存储在持久化存储中,以确保数据的持久性和可靠性。
Nacos的高可用性如何保证?
Nacos可以通过部署多个节点来实现高可用性。节点之间通过选举产生一个Leader节点,负责处理写操作,其他节点作为Follower节点来处理读操作。当Leader节点发生故障时,Follower节点会重新选举出一个新的Leader节点,确保服务的连续可用性。
Nacos如何实现服务的流量管理和动态路由?
Nacos通过集成流量管理组件(如OpenAPI、Spring Cloud Gateway)来实现服务的流量管理和动态路由。开发人员可以在Nacos中配置路由规则和流量策略,包括路径匹配、权重分配、灰度发布等,以实现动态的请求路由和流量控制。
Nacos如何支持服务的降级和故障熔断?
Nacos通过与服务调用框架(如Dubbo、Spring Cloud)的集成来支持服务的降级和故障熔断。开发人员可以在Nacos中配置降级规则和熔断策略,当服务发生故障或超时时,Nacos可以根据配置的规则自动触发降级或熔断操作,保障系统的稳定性和可靠性。
如何在Spring Cloud项目中使用Nacos作为服务注册和配置中心?⭐
在Spring Cloud项目中使用Nacos,可以通过引入相应的依赖,配置Nacos的服务地址和配置信息,以及使用相应的注解和配置类来实现服务的注册和配置管理。具体的步骤包括引入spring-cloud-starter-alibaba-nacos-discovery
和spring-cloud-starter-alibaba-nacos-config
依赖,配置bootstrap.properties
或bootstrap.yml
文件,使用@EnableDiscoveryClient
注解启用服务注册和发现,以及使用@Value
注解获取配置信息等。
Nacos与其他服务注册与配置中心(如ZooKeeper、Consul)相比有什么优势?⭐
- Nacos提供了更丰富的功能,包括服务注册和发现、配置管理、流量管理、动态路由等,而ZooKeeper和Consul主要专注于服务注册与发现。
- Nacos支持多种配置数据源类型,而ZooKeeper和Consul主要支持键值对类型的配置。
- Nacos提供了更灵活的动态配置刷新和更新通知机制。
- Nacos有更好的可伸缩性和高可用性,支持分布式部署和集群模式。
- Nacos对云原生生态系统(如Spring Cloud、Kubernetes)的支持更加紧密和友好。
Zookeeper
什么是 ZooKeeper?它的作用是什么?
- ZooKeeper 是一个开源的分布式协调服务,用于解决分布式系统中的一致性问题和协调问题。
- ZooKeeper 提供了一个简单而强大的分布式环境,使开发人员能够构建可靠的分布式应用。
ZooKeeper 的主要特点是什么?
- 高性能:ZooKeeper 使用内存数据模型,可以实现高性能的数据访问和更新。
- 可靠性:ZooKeeper 采用了多机复制机制,保证数据的可靠性和高可用性。
- 顺序一致性:ZooKeeper 提供了强一致性的数据更新机制,保证所有客户端看到的数据是一致的。
- 简单易用:ZooKeeper 提供了简单而清晰的接口,易于使用和集成到应用中。
ZooKeeper 的数据模型是什么样的?
- 层次性:ZooKeeper的数据模型是一个层次结构,类似于目录树。每个节点可以作为其他节点的父节点或子节点,形成了一个层次化的结构。
- 唯一路径:每个节点在整个ZooKeeper集群中都有唯一的路径来标识,称为ZNode路径。ZNode路径类似于文件系统中的绝对路径,由斜杠(/)分隔的一系列名称组成,例如:/root/child。
- 数据存储:每个ZNode可以存储一个小的数据块(最大限制为1MB)。这些数据可以是任意形式的字节流,可以是文本、序列化对象等。
- 版本号:每个ZNode都有一个版本号,包括数据版本号和ACL(访问控制列表)版本号。版本号用于实现乐观锁机制,以便在更新节点数据时进行冲突检测。
- 监听器(Watcher):ZooKeeper支持Watcher机制,可以在节点上设置Watcher,用于监听节点数据的变化。当节点的数据发生变化时,会触发相应的Watcher通知。
ZooKeeper 是如何实现数据的一致性和可靠性的?⭐
- ZAB(ZooKeeper Atomic Broadcast)协议:ZooKeeper使用ZAB协议来实现数据的一致性。ZAB协议是一种原子广播协议,通过将事务请求广播给ZooKeeper集群中的所有节点,并通过多数派投票机制来保证数据的一致性。当大多数节点都确认接收并处理了请求后,才认为该请求已提交,从而实现数据的一致性。
- 数据复制和选举:ZooKeeper使用多机复制机制来复制数据并保持数据的可靠性。当一个节点接收到事务请求后,它将该请求复制到其他节点,并等待大多数节点的确认。如果节点失败或失去连接,集群中的其他节点会通过选举机制选择新的领导者来继续处理请求,并保持数据的可靠性。
- 临时顺序节点:ZooKeeper提供了临时顺序节点的特性,这种节点在客户端会话结束后会被自动删除。通过使用临时节点,可以实现对临时性数据的管理,确保数据在不需要时可以自动清理,从而保持数据的可靠性和一致性。
- 事务日志和快照:ZooKeeper使用事务日志和快照来保证数据的一致性和可靠性。所有的数据更新操作都会被记录在事务日志中,该日志是顺序写入的,可以保证数据的顺序一致性。同时,ZooKeeper还会定期创建快照,将内存中的数据持久化到磁盘上,以便在节点重启时快速恢复数据。
什么是 ZAB 协议?它在 ZooKeeper 中的作用是什么?⭐
ZAB(ZooKeeper Atomic Broadcast)协议是 ZooKeeper 中的一种原子广播协议,用于实现数据的一致性和可靠性。
ZAB 协议在 ZooKeeper 中的作用主要有两个方面:
数据一致性:ZAB 协议通过保证多数派投票机制来实现数据的一致性。当一个客户端向 ZooKeeper 发起事务请求时,该请求会被广播到 ZooKeeper 集群中的所有节点,并通过多数派投票来决定是否接受该事务请求。只有当大多数节点都接受并执行了该事务请求后,ZooKeeper 才会认为该事务已经提交,从而保证了数据的一致性。
Leader 选举:ZAB 协议还负责 ZooKeeper 集群中的 Leader 选举。在 ZooKeeper 集群中,一个节点被选举为 Leader 节点,负责处理客户端的读写请求和协调其他节点。当集群中的 Leader 节点失效时,剩余的节点会通过 ZAB 协议进行新的 Leader 选举,以确保集群的正常运行。
ZAB 协议通过使用事务日志和快照机制,以及多数派投票和选举机制,实现了数据的一致性和可靠性。它是 ZooKeeper 实现高可用、高性能分布式协调服务的核心协议之一。
ZooKeeper 的节点类型有哪些?它们的特点是什么?
- 持久节点(Persistent Node):
- 持久节点在创建后会一直存在,直到主动删除。
- 它们的路径在ZooKeeper中是持久的,不受客户端会话的影响。
- 持久节点可以存储数据,用于表示持久化状态或配置信息。
- 临时节点(Ephemeral Node):
- 临时节点在创建它们的客户端会话有效期内存在,一旦会话结束或客户端断开连接,临时节点将被自动删除。
- 它们的路径是临时的,与客户端会话相关联。
- 临时节点通常用于表示临时性状态,例如临时工作节点或临时锁。
- 顺序节点(Sequential Node):
- 顺序节点是在节点路径后附加一个单调递增的数字编号,以确保节点的创建顺序。
- 顺序节点可以与持久节点或临时节点一起使用,使节点具有顺序性。
- 顺序节点的编号是全局唯一的,它可以用于实现有序性操作,如队列等。
- 临时顺序节点(Ephemeral Sequential Node):
- 临时顺序节点是临时节点和顺序节点的结合。
- 它们在创建后会在路径中附加一个单调递增的数字编号,并在客户端会话结束时自动删除。
- 临时顺序节点通常用于创建有序的临时工作节点或有序的临时锁。
什么是 Watcher?它在 ZooKeeper 中的作用是什么?
Watcher在ZooKeeper中的作用如下:
- 实时通知:Watcher使得客户端能够实时感知到节点的变化。客户端可以在创建节点时设置Watcher,并在节点发生变化时得到通知,而不需要轮询或频繁地查询节点状态。
- 分布式协调:Watcher机制可以用于实现分布式协调。客户端可以设置Watcher来监听特定节点的变化,并在节点状态发生变化时采取相应的行动,例如重新分配任务、更新配置等。
- 数据一致性:Watcher能够保证客户端与ZooKeeper之间的数据一致性。当客户端读取一个节点的数据时,可以同时设置Watcher,以便在数据发生变化时接收到通知并重新获取最新的数据。
- 高效性能:Watcher是一种轻量级的机制,不会占用太多的资源。客户端可以通过设置Watcher来减少不必要的网络请求,只在节点变化时才主动获取数据,提高系统的性能效率。
ZooKeeper 如何实现分布式锁?
- ZooKeeper 的临时节点和顺序节点可以用于实现分布式锁。
- 客户端可以通过创建一个临时顺序节点,然后判断自己是否是最小节点,如果是则获得锁;否则,监听前一个节点的删除事件,一旦前一个节点被删除,就获得锁。
- 当客户端释放锁时,只需要删除对应的临时节点即可。
如何处理在 ZooKeeper 中的故障恢复?
自动选举机制
ZooKeeper 的集群部署和配置有哪些注意事项?
- 奇数个节点:为了确保ZooKeeper集群的正常运行和高可用性,应该部署奇数个节点,通常建议使用3、5、7等。奇数节点可以确保在发生故障或网络分区时,仍然有大多数节点可用进行选举和维持集群的一致性。
- 配置文件:在每个ZooKeeper节点上,需要配置适当的ZooKeeper配置文件。配置文件中的一些重要参数包括:
dataDir
:指定ZooKeeper数据目录,用于存储事务日志和快照数据。clientPort
:指定ZooKeeper客户端连接的端口号。tickTime
:指定ZooKeeper节点之间的心跳时间,用于检测节点存活和维持集群的一致性。initLimit
和syncLimit
:用于配置初始连接和同步的时间限制。server.X
:指定每个节点的唯一ID、IP地址和数据通信端口号。
- 配置同步:在部署新节点或更改配置时,确保新节点的配置文件和数据与现有集群保持同步。可以使用配置管理工具或手动方法来确保配置文件的一致性,并确保节点之间的数据同步。
ZooKeeper 的性能调优有哪些方法?
- 增加服务器数量:通过增加ZooKeeper服务器的数量,可以提高集群的吞吐量和容错能力。更多的服务器可以分担负载和处理更多的请求。
- 配置合适的硬件:使用高性能的硬件设备,如快速的磁盘、高带宽的网络和足够的内存,可以提升ZooKeeper的性能。
- 调整数据存储:可以调整ZooKeeper的数据存储方式和配置,例如使用SSD来替代传统的磁盘存储,使用合适的文件系统,调整数据存储路径等,以提高数据读写的性能。
- 合理配置参数:ZooKeeper有一些关键的参数可以进行调整,如tickTime、syncLimit、initLimit等。根据实际场景和需求,合理设置这些参数可以优化ZooKeeper的性能。
- 分布式部署:将ZooKeeper服务器分布在多个物理机或虚拟机上,可以提高并行处理能力,避免单点故障,并减轻网络传输负担。
- 合理设置Watcher:Watcher是ZooKeeper中的事件通知机制,过多的Watcher可能对性能产生负面影响。因此,需要合理设置Watcher的数量,并及时清理不再使用的Watcher。
- 避免频繁的连接与断开:频繁的连接和断开会导致额外的开销,建议在应用程序中保持一个长时间的会话连接,而不是每次操作都建立新的连接。
- 合理使用缓存:在适当的情况下,可以使用缓存来减少对ZooKeeper的读取请求,提高读取性能。但要注意及时更新缓存,以保证数据的一致性。
- 监控和调优:使用监控工具来监视ZooKeeper的性能指标,如请求延迟、吞吐量等。根据监控结果进行调优,及时发现并解决潜在的性能问题。
ZooKeeper 的典型应用场景有哪些?
- 分布式锁:ZooKeeper可以用于实现分布式锁,多个客户端可以竞争获取锁资源并协调访问共享资源,确保在分布式环境下的数据一致性和协作。
- 配置管理:ZooKeeper可以用作配置中心,用于存储和管理应用程序的配置信息。应用程序可以通过监听ZooKeeper节点的变化来动态获取最新的配置,并实现配置的实时更新和动态调整。
- 分布式协调:ZooKeeper提供了一致性和可靠性的协调服务,可以用于实现分布式系统中的协调任务,如分布式锁、领导者选举、分布式队列、分布式协议等。
- 服务注册与发现:ZooKeeper可以作为服务注册中心,用于服务的注册与发现。服务提供者将自己的地址信息注册到ZooKeeper的节点上,服务消费者可以从ZooKeeper中获取服务提供者的地址信息,实现服务的动态发现和调用。
- 分布式队列:ZooKeeper可以用于实现分布式队列,多个客户端可以往队列中写入数据或从队列中消费数据,实现任务的异步处理和消息的分发。
- 高可用性的协调节点:ZooKeeper可以作为分布式系统中的协调节点,提供高可用性的服务。多个ZooKeeper服务器构成一个ZooKeeper集群,通过选举机制选出一个Leader节点,保证集群的可用性和数据一致性。
- 数据发布与订阅:ZooKeeper可以用于实现数据发布与订阅的机制,多个订阅者可以监听ZooKeeper节点的变化,并获取最新的数据。
Euraka, Nacos, Zookeeper的比较?
- 设计理念和架构:
- Eureka:Eureka是Netflix开源的服务发现组件,旨在实现服务注册和发现。它采用了客户端-服务器架构,通过心跳机制实现服务实例的注册和维护。
- Nacos:Nacos是一个面向服务的发现、配置和管理平台,提供了服务注册与发现、配置管理、动态路由等功能。它采用集群化的架构,无单点故障。
- ZooKeeper:ZooKeeper是一个基于ZAB(ZooKeeper Atomic Broadcast)协议的一致性协调服务,用于提供高可用性的协调服务。它采用主从架构,通过选举机制选出一个Leader节点来处理客户端请求。
- 功能特性:
- Eureka:Eureka主要关注服务注册与发现,提供了服务注册、心跳机制、自我保护机制等功能。它较为简单,适用于中小型分布式系统。
- Nacos:Nacos是一个功能较为全面的分布式协调平台,包括服务注册与发现、配置管理、动态路由等功能。它注重服务的动态管理和配置的实时更新。
- ZooKeeper:ZooKeeper提供了一致性和可靠性的协调服务,包括分布式锁、配置管理、领导者选举、分布式队列等功能。它的重点是保证数据的一致性和可靠性。
负载均衡器
Ribbon
Spring之Ribbon与Nginx区别?
Nginx 是客户端所有请求统一交给 nginx,由 nginx 进行实现负载均衡请求转发,属于服务器端负载均衡。它是一种集中式的负载均衡器。即请求由 nginx 服务器端进行转发。
Ribbon 是从 eureka 注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略。即在客户端实现负载均衡。
应用场景的区别
1)Nginx 适合于服务器端实现负载均衡 比如 Tomcat
2)Ribbon 适合与在微服务中 RPC 远程调用实现本地服务负载均衡,比如 Dubbo、SpringCloud 中都是采用本地负载均衡。
Ribbon是什么?
- Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法
- Ribbon客户端组件提供一系列完善的配置项,如连接超时,重试等。简单的说,就是在配置文件中列出后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随即连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法。(有点类似Nginx)
Ribbon的负载均衡策略有哪些?⭐
- 随机(Random):
- 随机选择一个可用的服务实例进行请求转发。
- 轮询(Round Robin):
- 循环轮询选择下一个可用的服务实例进行请求转发。
- 权重(Weighted):
- 根据服务实例的权重进行选择,权重高的实例获得更多的请求。
- 最少并发(Least Connection):
- 选择当前并发连接数最少的服务实例进行请求转发。
- Hash(哈希):
- 根据请求的某个属性(如请求IP或请求参数)计算哈希值,然后根据哈希值选择服务实例。
- 一致性哈希(Consistent Hashing):
- 根据请求的某个属性(如请求URL或请求参数)计算哈希值,并通过一致性哈希算法将请求映射到一个固定的节点。
- IP地址相关(IP Address相关):
- 根据请求方的IP地址范围来选择服务实例。
- 响应时间加权(Response Time Weighted):
- 根据服务实例的平均响应时间和权重计算得分,选择得分较高的实例进行请求转发。
Ribbon底层实现原理⭐
Ribbon是一个基于客户端的负载均衡器,它主要通过以下几个步骤实现负载均衡:
服务发现:Ribbon与服务注册中心(如Eureka、Consul等)集成,通过注册中心获取可用的服务实例列表。
负载均衡策略选择:Ribbon根据配置的负载均衡策略(如随机、轮询等)从可用的服务实例列表中选择一个实例。
服务调用:Ribbon将请求发送到选择的服务实例,完成服务调用。
Ribbon的底层实现原理可以简单概括如下:
Ribbon使用了Apache HttpClient或者Netty等HTTP客户端进行底层的HTTP通信。
Ribbon通过与服务注册中心的集成,可以动态地获取可用的服务实例列表。
Ribbon根据配置的负载均衡策略,在可用的服务实例列表中选择一个实例。
Ribbon通过维护每个服务实例的状态(如连接数、响应时间等),来评估实例的健康程度。
当选择的服务实例无法响应或超时时,Ribbon会自动切换到其他可用的实例。
Ribbon还支持超时设置、重试机制等功能,以增强服务调用的可靠性和稳定性。
总的来说,Ribbon通过与服务注册中心集成,动态地获取可用的服务实例列表,并根据负载均衡策略选择合适的实例进行服务调用。它提供了一种简单而可靠的方式来实现客户端的负载均衡,并提供了一些额外的功能来处理故障转移、重试等场景。
@LoadBalanced注解的作用
开启客户端负载均衡。
远程调用
RPC
什么是RPC?
RPC(Remote Procedure Call), 远程过程调用, 因为两个服务器上服务提供的方法不在同一个内存空间, 所以无法直接调用, 而RPC可以帮助我们调用远程计算机上的某个服务的方法, 隐藏了底层的传输方式(比如TCP或者UDP), 序列化方式(XML或者JSON或者二进制)和通信细节.
RPC的原理是什么?
RPC的核心功能可以看做以下部分:
- 客户端: 也叫做服务消费端, 调用远程方法的一端.
- 客户端桩: client stub, 把调用方法, 类, 方法参数等信息传递给服务端.
- 网络传输
- 服务端桩: server stub, 接收到客户端执行方法的请求, 执行对应的方法返回结果给客户端的类.
- 服务端: 提供远程方法的一端.
RPC调用的过程是什么?
- 客户端以本地调用的方式调用远程服务.
- 客户端桩接收到调用请求后负责将方法, 参数进行序列化成消息体以便网络传输.
- 客户端桩找到远程服务的地址, 然后将消息发送给服务器提供端.
- 服务端桩将消息反序列化成Java对象RpcRquest.
- 服务端桩根据
RpcRequest
中的类, 方法, 方法参数等信息调用本地的方法. - 服务端桩将执行的序列化结果
RpcResponse
发送给客户端. - 客户端桩接收消息并将消息反序列化成Java对象
RpcResponse
.
有哪些常见的RPC框架?
Dubbo
Apache Dubbo 是一款微服务框架,为大规模微服务实践提供高性能 RPC 通信、流量治理、可观测性等解决方案, 涵盖 Java、Golang 等多种语言 SDK 实现。
Dubbo 提供了从服务定义、服务发现、服务通信到流量管控等几乎所有的服务治理能力,支持 Triple 协议(基于 HTTP/2 之上定义的下一代 RPC 通信协议)、应用级服务发现、Dubbo Mesh (Dubbo3 赋予了很多云原生友好的新特性)等特性。
gRPC
RPC 是 Google 开源的一个高性能、通用的开源 RPC 框架。其由主要面向移动应用开发并基于 HTTP/2 协议标准而设计(支持双向流、消息头压缩等功能,更加节省带宽),基于 ProtoBuf 序列化协议开发,并且支持众多开发语言。
ProtoBuf是一种更加灵活、高效的数据格式,可用于通讯协议、数据存储等领域,基本支持所有主流编程语言且与平台无关。不过,通过 ProtoBuf 定义接口和数据类型还挺繁琐的,这是一个小问题。
Thrift
Apache Thrift 是 Facebook 开源的跨语言的 RPC 通信框架,目前已经捐献给 Apache 基金会管理,由于其跨语言特性和出色的性能,在很多互联网公司得到应用,有能力的公司甚至会基于 thrift 研发一套分布式服务框架,增加诸如服务注册、服务发现等功能。
Thrift
支持多种不同的编程语言,包括C++
、Java
、Python
、PHP
、Ruby
等(相比于 gRPC 支持的语言更多 )。
HTTP和RPC分别有什么区别?
- 传输协议:
- RPC: 可以基于TCP协议, 也可以基于HTTP协议
- HTTP: 基于HTTP协议
- 传输效率
- RPC: 使用自定义TCP协议可以使得请求报文体积更小, 或者使用HTTP2.0协议, 也可以很好的减少报文体积, 提高传输效率
- HTTP: 基于HTTP1.1, 效率不搞, HTTP2.0封装一下可以作为RPC使用.
- 性能消耗:
- RPC: 可以基于thrift实现高效的二进制传输.
- HTTP: 大部分是通过json实现, 字节大小和序列化耗时逗比thrift要更消耗性能
- 负载均衡
- RPC: 自带负载均衡
- HTTP: 需要结合Nginx等实现
- 服务治理(下游服务新增重启下线是如何不影响上游调用者)
- RPC: 能自动通知不影响上游
- HTTP: 需要实现通知, 修改Nginx配置
RPC和HTTP的应用场景分别是什么?
- RPC主要用于公司内部服务调用, 性能消耗低, 传输效率高, 服务治理方便, 但是要求服务提供方和服务消费方都必须使用统一的RPC框架
- HTTP主要用于对外的异构环境, 浏览器调用, APP接口调用, 第三方接口调用等.
RPC架构分析
一款分布式有3个基本要素:
- 注册中心(Registry), 主要用来服务注册和服务发现
- 服务提供者(Service Provider), 对外提供服务接口, 需要在应用启动时连接注册「注册中心」, 将服务名和其服务元数据发往注册中心.
- 服务消费者(Service Consumer), 借由注册中心发现服务, 需要在应用启动时扫描依赖的RPC服务, 并为其生成外力调用对象, 同时从注册中心拉取服务元数据存入本地缓存, 然后监听各服务的变动做到及时更新缓存.
围绕上面的三个基本要素可以进一步扩展序列化协议, 通信协议, 服务路由, 负载均衡, 服务熔断降级机制等等.
RPC的技术选型有哪些?
- 注册中心: Zookeeper,Nacos,Consul,Eureka
- 序列化协议: Protobuf, JavaSerializer, Hessian
- IO通信框架: Netty, MINA
- 通信协议: TCP, 将消息分为消息头和消息体,消息头中包含表示消息总长度(或者消息体长度)的字段。
参考架构:
为什么RPC要用到序列化?
因为程序使用的是对象, 而远程调用之间要通过网络传输, 所以需要将对象转换成字符串进行传输, 传输后再转换回对象, 这个过程就是序列化和反序列化.
Feign
什么是Feign?
- Feign 是一个声明web服务客户端,这使得编写web服务客户端更容易
- 他将我们需要调用的服务方法定义成抽象方法保存在本地就可以了,不需要自己构建Http请求了,直接调用接口就行了,不过要注意,调用方法要和本地抽象方法的签名完全一致。
SpringCloud有几种调用接口方式
- Feign
- RestTemplate
Feign与RestTemplate的区别是什么?⭐
- Feign是一个声明式的HTTP客户端,通过定义接口来声明服务的调用,相对来说更简洁和易用。
- RestTemplate是一个传统的HTTP客户端,需要手动构建HTTP请求,使用起来相对繁琐。
Feign如何处理请求超时?
- 可以通过配置Feign的超时时间来处理请求超时,如果超时则会触发熔断机制。
Feign的异常处理机制是什么?
- Feign会将HTTP状态码转换为相应的异常抛出,开发人员可以通过自定义异常处理器来处理这些异常。
服务保护
Hystrix
什么是断路器
- 当一个服务调用另一个服务由于网络原因或自身原因出现问题,调用者就会等待被调用者的响应 当更多的服务请求到这些资源导致更多的请求等待,发生连锁效应(雪崩效应)
- 断路器有三种状态
- 打开状态:一段时间内 达到一定的次数无法调用 并且多次监测没有恢复的迹象 断路器完全打开 那么下次请求就不会请求到该服务
- 半开状态:短时间内 有恢复迹象 断路器会将部分请求发给该服务,正常调用时 断路器关闭
- 关闭状态:当服务一直处于正常状态 能正常调用
什么是 Hystrix?
- 在分布式系统,我们一定会依赖各种服务,那么这些个服务一定会出现失败的情况,就会导致雪崩,Hystrix就是这样的一个工具,防雪崩利器,它具有服务降级,服务熔断,服务隔离,监控等一些防止雪崩的技术。
- Hystrix有四种防雪崩方式:
- 服务降级:接口调用失败就调用本地的方法返回一个空
- 服务熔断:接口调用失败就会进入调用接口提前定义好的一个熔断的方法,返回错误信息
- 服务隔离:隔离服务之间相互影响
- 服务监控:在服务发生调用时,会将每秒请求数、成功请求数等运行指标记录下来。
谈谈服务雪崩效应
- 雪崩效应是在大型互联网项目中,当某个服务发生宕机时,调用这个服务的其他服务也会发生宕机,大型项目的微服务之间的调用是互通的,这样就会将服务的不可用逐步扩大到各个其他服务中,从而使整个项目的服务宕机崩溃.发生雪崩效应的原因有以下几点
- 单个服务的代码存在bug. 2请求访问量激增导致服务发生崩溃(如大型商城的枪红包,秒杀功能). 3.服务器的硬件故障也会导致部分服务不可用.
在微服务中,如何保护服务?
- 一般使用使用Hystrix框架,实现服务隔离来避免出现服务的雪崩效应,从而达到保护服务的效果。当微服务中,高并发的数据库访问量导致服务线程阻塞,使单个服务宕机,服务的不可用会蔓延到其他服务,引起整体服务灾难性后果,使用服务降级能有效为不同的服务分配资源,一旦服务不可用则返回友好提示,不占用其他服务资源,从而避免单个服务崩溃引发整体服务的不可用.
服务雪崩效应产生的原因
- 因为Tomcat默认情况下只有一个线程池来维护客户端发送的所有的请求,这时候某一接口在某一时刻被大量访问就会占据tomcat线程池中的所有线程,其他请求处于等待状态,无法连接到服务接口。
谈谈服务降级、熔断、服务隔离
- 服务降级:当客户端请求服务器端的时候,防止客户端一直等待,不会处理业务逻辑代码,直接返回一个友好的提示给客户端。
- 服务熔断是在服务降级的基础上更直接的一种保护方式,当在一个统计时间范围内的请求失败数量达到设定值(requestVolumeThreshold)或当前的请求错误率达到设定的错误率阈值(errorThresholdPercentage)时开启断路,之后的请求直接走fallback方法,在设定时间(sleepWindowInMilliseconds)后尝试恢复。
- 服务隔离就是Hystrix为隔离的服务开启一个独立的线程池,这样在高并发的情况下不会影响其他服务。服务隔离有线程池和信号量两种实现方式,一般使用线程池方式。
服务降级底层是如何实现的?
- Hystrix实现服务降级的功能是通过重写HystrixCommand中的getFallback()方法,当Hystrix的run方法或construct执行发生错误时转而执行getFallback()方法
Sentinel
什么是Sentinel?
- Sentinel是阿里巴巴开源的一款轻量级的流量控制和熔断降级组件,用于保护分布式系统的稳定性。
Sentinel的主要特性是什么?
- 流量控制:通过设置规则对流量进行控制,包括流量限流、熔断降级等。
- 实时监控:提供实时的监控指标,包括请求QPS、响应时间、异常比例等。
- 系统保护:提供系统级别的保护机制,包括系统自适应保护和慢调用比例保护等。
- 规则配置:支持通过代码和配置文件两种方式进行规则的配置。
Sentinel的流量控制模式有哪些?⭐
- 直接:直接拒绝请求,不进行等待。
- 关联:当关联的资源达到阈值时,限制其他资源的请求。
- 链路:当其他链路的资源达到阈值时,限制当前链路的请求。
Sentinel的熔断降级机制是怎样的?⭐
- Sentinel通过设置熔断规则,当资源的异常比例或异常数超过阈值时,会触发熔断,暂时停止请求资源,避免故障进一步扩大。
Sentinel的熔断规则有什么?⭐
- RT(平均响应时间)熔断:
- 当资源的平均响应时间超过设定的阈值时,触发熔断策略。
- 异常比例熔断:
- 当资源的异常比例(异常请求占总请求的比例)超过设定的阈值时,触发熔断策略。
- 异常数熔断:
- 当资源的异常数超过设定的阈值时,触发熔断策略。
- 慢调用比例熔断:
- 当资源的慢调用比例(响应时间超过设定阈值的请求占总请求数的比例)超过设定的阈值时,触发熔断策略。
- 异常预热熔断:
- 在熔断之前,先让请求按照一定比例通过,以达到预热的效果。
Sentinel如何实现实时监控?
- Sentinel通过提供Dashboard面板和Metrics API,可以实时查看应用的运行状态和指标数据。
Sentinel的流控规则和熔断规则有什么区别?⭐
- 流控规则用于限制对资源的访问流量,控制并发数或QPS。
- 熔断规则用于当资源出现异常时,暂时停止对资源的访问,以保护系统稳定性。
Sentinel与Spring Cloud的集成如何实现?
- 可以通过在Spring Cloud项目中引入Sentinel的依赖,并使用Sentinel的注解或AOP方式来保护和控制资源的访问。
配置中心
SpringCloud Config
了解Spring Cloud Config 吗?
在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在Spring Cloud中,有分布式配置中心组件Spring Cloud Config
,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程Git仓库中。
在Spring Cloud Config
组件中,分两个角色,一是config server,二是config client。
使用方式:
- 添加pom依赖
- 配置文件添加相关配置
- 启动类添加注解@EnableConfigServer
什么是Spring Cloud Config?
- Spring Cloud Config为分布式系统中的外部配置提供服务器和客户端支持,可以方便的对微服务各个环境下的配置进行集中式管理。Spring Cloud Config分为Config Server和Config Client两部分。Config Server负责读取配置文件,并且暴露Http API接口,Config Client通过调用Config Server的接口来读取配置文件。
分布式配置中心有那些框架?
- Apollo、zookeeper、springcloud config。
分布式配置中心的作用?
- 动态变更项目配置信息而不必重新部署项目。
SpringCloud Config 可以实现实时刷新吗?
- springcloud config实时刷新采用SpringCloud Bus消息总线。
链路追踪
服务器
Tomcat
Nginx⭐
Nginx是什么?
Nginx是一个web服务器, 主要功能是反向代理, 负载均衡, 用于HTTP, HTTPS, SMTP, POP3和IMAP协议.
Nginx的应用场景是什么? 有什么优点?
当用户量很大的时候, 用户访问量并发就很多, 此时Nginx可以处理高并发连接, 利用反向代理功能, 将请求分发给不同的后端处理, 但用户角度该操作是透明的.
Nginx的优点是跨平台, 非阻塞高并发连接, 内存消耗小, 可以处理2-3万并发连接数, 开启10个nginx内存消耗才占150M左右.
为什么Nginx的性能这么高?⭐
因为他的事件处理机制:异步非阻塞事件处理机制:运用了epoll模型,提供了一个队列,排队解决
原文作者:阿尔巴
原文链接:https://www.nginx.org.cn/article/detail/451/
转载来源:NGINX开源社区
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Nginx怎么处理请求的?
nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的location,location就是实际地址
server { # 第一个Server区块开始,表示一个独立的虚拟主机站点
listen 80; # 提供服务的端口,默认80
server_name localhost; # 提供服务的域名主机名
location / { # 第一个location区块开始
root html; # 站点的根目录,相当于Nginx的安装目录
index index.html index.htm; # 默认的首页文件,多个用空格分开
} # 第一个location区块结果
}
什么是正向代理和反向代理?
正向代理是客户端发给代理服务器请求并指定原始服务器, 由代理服务器转发请求并交应答的响应返回给客户端, 常见的应用有VPN, 代理服务器和客户端处于同一个局域网内.
反向代理是代理服务器接接收网络上的连接请求, 将请求转发给内部网络上的服务器, 并将服务器上得到的结果返回给客户端, 服务器可以是不同服务器, 但是对客户端表现为同一个服务器, 代理服务器和服务器处于
Nginx是如何实现高并发的?⭐
Nginx是多进程, 多路复用模型epoll异步非阻塞的方式来处理请求所以可以实现高并发.
多进程指的是Nginx有一个master
进程和多个相互独立的worker
进程, master
进程接收外接信号并且向所有的worker
发送信号, 而每个worker
进程都有机会来处理这个连接.
多路复用模型epoll: 一般的io模型比如select
是通过轮询的方式查询”文件”是否准备好, 而epoll
是通过事件通知的方式来处理IO的, 这样当一个请求因为IO阻塞时, worker可以处理其他的请求.
Nginx的Master和Worker进程分别是什么, 干什么的? 参考2⭐
master进程:
- 负责收集请求并分发请求
- 监控
worker
进程状态在work
进程因为异常情况退出时重启新的worker
进程
worker进程:
worker
进程是由master
进程fork
过来的, 在master进程里面,先建立好需要listen的socket(listenfd)之后,然后再fork出多个worker进程, 所有worker
进程的listenfd会在新连接到来时变的可读, 为了得到这个请求, 需要先在listenfd
读时间之前争抢accept_mutex
这个互斥锁, 抢到互斥锁的那个进程注册listenfd
读事件,在读事件里调用accept
接受该连接。- 当一个 worker 进程在
accept()
这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,一个完整的请求。
Nginx常见的优化配置有哪些?
- 调整
worker_processes
, 也就是worker
进程的数量, 最佳实践是有几个cpu就启动几个worker进程, 因为不用进行上下文切换 - 最大化
worker_connections
, 最大客户端(连接数) = 工作进程 * 工作者连接数(worker_connections), 最佳实践是应设置为CPU一次可以允许的最大进程数1024. - 弃用Gzip压缩, 压缩文件大小, 减少客户端http的传输带宽
- 为静态文件弃用缓存.
- Timeouts设置, 设置连接的保持时间
- 禁用access_logs, 访问日志记录记录每个nginx请求, 因此消耗了大量的CPU资源, 降低了性能.
Nginx的所使用的的IO模型是什么?[^17][^18]⭐
Nginx支持多种并发模型, 并发模型的具体实现根据系统平台而有所不同, Nginx会自动选择最高效的IO模型, 也可以通过use
指令来在配置文件中指定.
- select
- poll
- kqueue
- epoll
- /dev/poll
- eventpoll
Nginx常用命令有哪些?^12
启动
nginx
。停止
nginx -s stop
或nginx -s quit
。重启
nginx -s reload
或service nginx reload
。重载指定配置文件
.nginx -c /usr/local/nginx/conf/nginx.conf
。查看 nginx 版本
nginx -v
Nginx的目录结构有哪些?
[root@localhost ~]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp
├── conf # Nginx所有配置文件的目录
│ ├── fastcgi.conf # fastcgi相关参数的配置文件
│ ├── fastcgi.conf.default # fastcgi.conf的原始备份文件
│ ├── fastcgi_params # fastcgi的参数文件
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types # 媒体类型
│ ├── mime.types.default
│ ├── nginx.conf # Nginx主配置文件
│ ├── nginx.conf.default
│ ├── scgi_params # scgi相关参数文件
│ ├── scgi_params.default
│ ├── uwsgi_params # uwsgi相关参数文件
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp # fastcgi临时数据目录
├── html # Nginx默认站点目录
│ ├── 50x.html # 错误页面优雅替代显示文件,例如当出现502错误时会调用此页面
│ └── index.html # 默认的首页文件
├── logs # Nginx日志目录
│ ├── access.log # 访问日志文件
│ ├── error.log # 错误日志文件
│ └── nginx.pid # pid文件,Nginx进程启动后,会把所有进程的ID号写到此文件
├── proxy_temp # 临时目录
├── sbin # Nginx命令目录
│ └── nginx # Nginx的启动命令
├── scgi_temp # 临时目录
└── uwsgi_temp # 临时目录
Nginx配置文件nginx.conf有哪些属性模块?⭐
分为三部分
- 全局区块
- 事件区块
- http区块
- 全局区块
- server区块
- 全局区块
- location区块
location指令的作用是根据用户请求的URI来执行不同的应用,也就是根据用户请求的网站URL进行匹配,匹配成功即进行相关的操作。
worker_processes 1; # worker进程的数量
events { # 事件区块开始
worker_connections 1024; # 每个worker进程支持的最大连接数
} # 事件区块结束
http { # HTTP区块开始
include mime.types; # Nginx支持的媒体类型库文件
default_type application/octet-stream; # 默认的媒体类型
sendfile on; # 开启高效传输模式
keepalive_timeout 65; # 连接超时
server { # 第一个Server区块开始,表示一个独立的虚拟主机站点
listen 80; # 提供服务的端口,默认80
server_name localhost; # 提供服务的域名主机名
location / { # 第一个location区块开始
root html; # 站点的根目录,相当于Nginx的安装目录
index index.html index.htm; # 默认的首页文件,多个用空格分开
} # 第一个location区块结果
error_page 500502503504 /50x.html; # 出现对应的http状态码时,使用50x.html回应客户
location = /50x.html { # location区块开始,访问50x.html
root html; # 指定对应的站点目录为html
}
}
......
Nginx压缩了解过吗? 如何开启压缩?^13
开启Nginx Gzip压缩后, 图片, css等静态资源的大小会减小可以节省带宽, 提高传输效率, 但是会消耗CPU资源.
推荐的配置[^16]:
如何用Nginx解决前端跨域问题?
- 使用Nginx转发请求。把跨域的接口写成调本域的接口,然后将这些接口转发到真正的请求地址。
Nginx为什么要动静分离? 怎么做的动静分离?
动静分离是为了加快访问速度, 静态内容是指图片, html, css, js等资源, 动态数据则请求tomcat等后端服务器来返回. 把静态资源放在Nginx服务器上, 用户请求时从Nginx中直接返回.
使用location指定路径对应的目录即可
location /image/ {
root /usr/local/static/;
autoindex on;
}
这样, 就可以访问server_name/image/1.jpg
就可以访问到服务器上 /usr/local/static/image/1.jpg
的内容了
Nginx虚拟主机怎么配置?⭐
- 1、基于域名的虚拟主机,通过域名来区分虚拟主机——应用:外部网站
- 2、基于端口的虚拟主机,通过端口来区分虚拟主机——应用:公司内部网站,外部网站的管理后台
- 3、基于ip的虚拟主机。
基于虚拟主机配置域名
- 需要建立
/data/www
和/data/bbs
目录,windows本地hosts添加虚拟机ip地址对应的域名解析;对应域名网站目录下新增index.html文件;
#当客户端访问www.lijie.com,监听端口号为80,直接跳转到data/www目录下文件
server {
listen 80;
server_name www.lijie.com;
location / {
root data/www;
index index.html index.htm;
}
}
#当客户端访问bbs.lijie.com,监听端口号为80,直接跳转到data/bbs目录下文件
server {
listen 80;
server_name bbs.lijie.com;
location / {
root data/bbs;
index index.html index.htm;
}
}
基于端口的虚拟主机
- 使用端口来区分,浏览器使用域名或ip地址:端口号 访问
#当客户端访问www.lijie.com,监听端口号为8080,直接跳转到data/www目录下文件
server {
listen 8080;
server_name www.lijie.com;
location / {
root data/www;
index index.html index.htm;
}
}
#当客户端访问www.lijie.com,监听端口号为80直接跳转到真实ip服务器地址 127.0.0.1:8080
server {
listen 80;
server_name www.lijie.com;
location / {
proxy_pass http://127.0.0.1:8080;
index index.html index.htm;
}
}
Nginx负载均衡的算法怎么实现的? 策略有哪些?^13⭐
为了避免服务器访问量过大奔溃, 会通过负载均衡的方式, 对多台服务器组成一个集群, 当用户访问时先访问到一个转发服务器, 再有转发服务器分发给其他压力更小的服务器.
Nginx负载均衡实现的策略有以下五种, 有==轮询, 权重, ip_hash, fair, url_hash==五种, 一般全局区块的upstream中配置:
轮询(默认)
upstream backserver { server 192.168.0.12; server 192.168.0.13; }
权重, 主要用于后端每台服务器性能不均衡的情况下, 其次是为在主从的情况下设置不同的权值从而有效的利用主机资源.
upstream backserver { server 192.168.0.12 weight=2; server 192.168.0.13 weight=8; }
ip_hash
每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题
upstream backserver { ip_hash; server 192.168.0.12:88; server 192.168.0.13:80; }
fair(第三方插件)
必须安装upstream_fair模块, 根据页面大小和加载时间长短智能地进行负载均衡, 响应时间短的优先分配.upstream backserver { server server1; server server2; fair; }
url_hash(第三方插件)
必须安装Nginx的hash软件包, 根据访问url的hash结果来分配请求, 可以进一步提高后端缓存服务器的效率
upstream backserver { server squid1:3128; server squid2:3128; hash $request_uri; hash_method crc32; }
Nginx配置高可用性怎么配置?
- 当上游服务器(真实访问服务器),一旦出现故障或者是没有及时相应的话,应该直接轮训到下一台服务器,保证服务器的高可用.
- Nginx配置代码:
server {
listen 80;
server_name www.lijie.com;
location / {
### 指定上游服务器负载均衡服务器
proxy_pass http://backServer;
###nginx与上游服务器(真实访问的服务器)超时时间 后端服务器连接的超时时间_发起握手等候响应超时时间
proxy_connect_timeout 1s;
###nginx发送给上游服务器(真实访问的服务器)超时时间
proxy_send_timeout 1s;
### nginx接受上游服务器(真实访问的服务器)超时时间
proxy_read_timeout 1s;
index index.html index.htm;
}
}
限流有了解过吗? Nginx是如何限流的?^12⭐
Nginx提供两种限流方式, ==一种是控制速率, 一种是控制并发连接数, 控制速率又分为控制正常流量速率和控制突发流量速率, 也就是三种==.
控制正常流量速率
ngx_http_limit_req_module
提供漏桶算法
, 可以限制单个ip的请求频率以下配置表明对所有ip地址(
$binary_remote_addr为内置变量
)开启一个10M大小名称为zoneName
的共享内存区, 每秒限制进行五个请求的处理#定义限流维度,一个用户一分钟一个请求进来,多余的全部漏掉 limit_req_zone $binary_remote_addr zone=zoneName:10m rate=5r/s; #绑定限流维度 server{ location/seckill.html{ limit_req zone=zoneName burst=20 nodelay; proxy_pass http://lj_seckill; } }
控制突发流量速率
在5r/s的速率下, 如果流量突然变大, 超出的请求就被拒绝返回503了, 这时候可以**加上brust
参数, 结合nodelay
**可以处理突发流量.
上个配置文件中limit_req zone=zoneName burst=20 nodelay;
表明对于一个用户可以立即处理前20个, 没有其他用户的请求就可以处理多余的, 如果有其他的请求就先处理其他的用户的请求.控制并发连接数
ngx_http_limit_conn_module
提供了限制连接数功能, 可以使用limit_conn_zone
指令以及limit_conn
来配置http { limit_conn_zone $binary_remote_addr zone=myip:10m; limit_conn_zone $server_name zone=myServerName:10m; } server { location / { limit_conn myip 10; limit_conn myServerName 100; rewrite / http://www.lijie.net permanent; } }
上述配置表明单个ip同时并发连接数最大只能10个连接, 并且且设置了整个虚拟服务器同时最大并发数最多只能100个链接。当然,只有当请求的header被服务器处理后,虚拟服务器的连接数才会计数。刚才有提到过Nginx是基于漏桶算法原理实现的,实际上限流一般都是基于漏桶算法和令牌桶算法实现的。
扩展
如果不想做限流, 可以查看ngx_http_geo_module
和 ngx_http_map_module
两个工具模块来设置白名单
除此之外, ngx_http_core_module
还提供了限制数据传输速度的能力(即常说的下载速度)
location /flv/ {
flv;
limit_rate_after 500m;
limit_rate 50k;
}
针对每个请求,表示客户端下载前500m的大小时不限速,下载超过了500m后就限速50k/s。
漏铜算法和令牌桶算法知道吗?
漏桶算法是网络世界中流量整形或速率限制时经常使用的一种算法,它的主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。也就是我们刚才所讲的情况。漏桶算法提供的机制实际上就是刚才的案例:突发流量会进入到一个漏桶,漏桶会按照我们定义的速率依次处理请求,如果水流过大也就是突发流量过大就会直接溢出,则多余的请求会被拒绝。所以漏桶算法能控制数据的传输速率。
令牌桶算法是网络流量整形和速率限制中最常使用的一种算法。典型情况下,令牌桶算法用来控制发送到网络上的数据的数目,并允许突发数据的发送。Google开源项目Guava中的RateLimiter使用的就是令牌桶控制算法。令牌桶算法的机制如下:存在一个大小固定的令牌桶,会以恒定的速率源源不断产生令牌。如果令牌消耗速率小于生产令牌的速度,令牌就会一直产生直至装满整个令牌桶。
Nginx的全局变量[^13][^21]
变量名 | |
---|---|
$args | 这个变量等于请求行中的参数,同$query_string |
$content length | 请求头中的Content-length字段。 |
$content_type | 请求头中的Content-Type字段。 |
$document_root | 当前请求在root指令中指定的值。 |
$host | 请求主机头字段,否则为服务器名称。 |
$http_user_agent | 客户端agent信息 |
$http_cookie | 客户端cookie信息 |
$limit_rate | 这个变量可以限制连接速率。 |
$request_method | 客户端请求的动作,通常为GET或POST。 |
$remote_addr | 客户端的IP地址。 |
$remote_port | 客户端的端口。 |
$remote_user | 已经经过Auth Basic Module验证的用户名。 |
$request_filename | 当前请求的文件路径,由root或alias指令与URI请求生成。 |
$scheme | HTTP方法(如http,https)。 |
$server_protocol | 请求使用的协议,通常是HTTP/1.0或HTTP/1.1。 |
$server_addr | 服务器地址,在完成一次系统调用后可以确定这个值。 |
$server_name | 服务器名称。 |
$server_port | 请求到达服务器的端口号。 |
$request_uri | 包含请求参数的原始URI,不包含主机名,如”/foo/bar.php?arg=baz”。 |
$uri | 不带请求参数的当前URI,$uri不包含主机名,如”/foo/bar.html”。 |
$document_uri | 与$uri相同。 |
ngx_http_upstream_module有了解吗?^12
ngx_http_upstream_module
用于定义可通过fastcgi
传递、proxy
传递、uwsgi
传递、memcached
传递和scgi传递指令来引用的服务器组。
比如访问www.a.com 缓存+调度:
http{
proxy_cache_path /var/cache/nginx/proxy_cache levels=1:2:2 keys_zone=proxycache:20m inactive=120s max_si #缓存
ze=1g;
upstream mysqlsrvs{
ip_hash; #源地址hash调度方法 写了backup就不可用
server 172.18.99.1:80 weight=2; #weight权重
server 172.18.99.2:80; #标记down,配合ip_hash使用,实现灰度发布
server 172.18.99.3:80 backup; #backup将服务器标记为“备用”,即所有服务器均不可用时才启用
}
}
server{
server_name www.a.com;
proxy_cache proxycache;
proxy_cache_key $request_uri;
proxy_cache_valid 200 302 301 1h;
proxy_cache_valid any 1m;
location / {
proxy_pass http://mysqlsrvs;
}
}
这里需要注意的点:
upstream mysqlsrvs
与proxy_pass http://mysqlsrvs;
相对应, 也就是www.a.com会被反向代理为http://mysqlsrvs, 然后再通过upstream
的负载均衡分发给其它后端服务器.
Location区块的alias和root什么区别[^20]
root 会加在路径的最前面, 比如当请求http://qingshan.com/123/abc/logo.png时,会返回 /ABC/123/abc/logo.png文件,即用/ABC 加上 /123/abc。
location /123/abc/ {
root /ABC;
}
alias会把路径替换为别名, 当请求http://qingshan.com/123/abc/logo.png时,会返回 /ABC/logo.png文件,即用/ABC替换 /123/abc。
location /123/abc/ {
alias /ABC;
}
其他中间件
MyBatis Plus
Shiro(身份验证)⭐
logback⭐
slf4j
Solr
ElasticSearch⭐
开发工具
Linux
ApiFox
Docker
Gradle
K8S
场景题
订单到期未支付自动关闭功能如何实现?
- JDK延时队列
- 分布式延时嘟列
- 定时任务
- MQ延时消费
- redis过期监听
- 时间戳
高并发下接口幂等保障技术
幂等问题引发常见元
幂等测试指标
幂等使用场景:
- 订单, 支付, 退款, 结算, 财务
- 权益, 积分, 优惠券
- 会员升级, 降级, 保级
- push消息
- 定时worker
- 营销活动
- 秒杀
缓存相关问题
缓存穿透解决方案:
- 缓存空
- 布隆过滤器
缓存击穿解决方案
- 分布式锁
缓存雪崩
- 采用集群, 降低宕机概率
- enchache本地缓存+限量+降级
- 均匀过期, 通常可以为有效期增加
- 随机值
电商业务
其他
为什么要把头像图片存到阿里云中?
- 图片也可以上传到本地服务器, 但需要自己管理和备份
- 上传到阿里云OSS, 管理和备份简单
上传的过程有两种, 一种是前端上传到后端, 后端再上传到OSS, 一种是前端请求后端获取签名后前端直传OSS, 后一种效率比较高并且安全性比较好, 不用前端暴露accessKey.
[^2]: rbmonster Github
[^3]: 20道操作系统常见面试题-思否
[^4]: 这 50 道操作系统面试题,真牛批!-腾讯云
[^5]: 一篇学会CPU上下文
[^6]: 进程间的通信方式: 信号, 管道, 消息队列, 共享内存-博客园(代码级别展示了各通信方式的原理和使用)
[^7]: 进程间通信IPC (InterProcess Communication)-简书(非常详细且清楚的讲明了7种通信方式)
[^8]: 进程间8种通信方式详解-腾讯云(讲套接字将的非常清楚)
[^9]: 消息队列的使用场景是怎样的?
[^14]: Nginx面试中最常见的18道题 抱佛脚必备-思否
[^15]: nginx实现高并发的原理
[^16]: Nginx 如何实现高并发?常见的优化手段有哪些?-今日头条
[^17]: 彻底理解 IO 多路复用实现机制
[^18]: Connection processing methods
[^19]: Full Example Configuraion
[^20]: nginx配置静态资源访问-博客园
[^21]: Nginx Variables
[^22]: nginx 之 proxy_pass详解
[^23]: 最全的 116 道 Redis 面试题解答
[^24]: Redis面试题阅读指南-帅地玩编程
[^25]: JavaFamily-Gituhb
[^26]: Redis持久化的两种方式RDB和AOF理解
[^30]: 介绍下Redis Sentinel(哨兵)
[^31]: 分布式数据库与缓存双写一致性方案解疑
[^32]: JavaGuide Spring框架
[^42]: JVM-rbmonster
欢迎在评论区中进行批评指正,转载请注明来源,如涉及侵权,请联系作者删除。