• 一文带你玩转offer-01



    文章持续更新中。。。

    1.RabbitMq是如何实现消息路由的

    1.1 工作流程

    RabbitMq:一个基于AMQP协议实现的分布式消息中间件
    AMQP的工作机制如下图所示 :
    在这里插入图片描述

    首先生产者把消息发送到RabbitMQ Broker上的Exchange交换机上,Exchange交换机会把收到的消息根据路由规则分发给绑定的队列,最后再把消息投递给订阅了这个队列的消费者从而去完成消息的异步通信。

    其中Exchange交换机就可以去定义这个消息的路由规则,将消息去路由到指定的队列,然后队列就是消息的载体,每个消息就可以根据路由规则路由到一个或者多个队列中。

    1.2 路由策略

    完成RabbitMq路由的核心组件是Exchange交换机,而消息的路由又是由Exchange类型(交换机类型)和Binding决定的。

    Binding是表示在队列和交换机之间的一个绑定关系,那么每个绑定关系会存在一个BindingKey,通过这种方式相当于是在Exchange交换机中建立了一个路由关系表,在每个生产者发送消息的时候,需要声明一个RoutingKey(路由键),Exchange拿到RoutingKey之后,根绝RoutingKey和路由表里面的BindingKey进行匹配,而匹配的规则是通过Exchange类型来决定的

    在 RabbitMq中默认有四种类型,常用的有三种:

    • Direct
    • Fanout
    • Topic

    Direct Exchange

    其中Direct叫做直连,也就是完整的匹配方式,他需要Routing Key和Binding Key完全一致,相当于是点对点的发送,原理如下图所示:
    在这里插入图片描述

    如果发生了Routing Key为spring的消息,只有一个队列能接受到消息

    Topic Exchange

    Topic叫做主题,那么这种方式是通过设置通配符来动态匹配,类似于正则,就是用Routing Key去匹配Binding Key,Binding Key支持两个通配符:

    • #号代表0个或多个单词
    • *号代表匹配不多不少一个单词

    另外Binding Key是用 点隔开两个单词,所以*和#就相当于是正则表达式的一个作用
    在这里插入图片描述

    我们有4个队列绑定到 Topic类型的交换机中,而且使用的是不同的绑定键,如上图所示,那么如果我们发送routing key为“junior.abc.jvm”的消息,那么只有第一个队列可以收到。

    如果我们发送routing key为“senior.netty”的消息,那么第二个队列第三个队列都可以收到。

    Fanout Exchange

    Fanout叫做广播,这种方式是不需要设置Routing key的,而且他会把消息广播给绑定到当前Exchange上的所有队列上,如下图所示:
    在这里插入图片描述

    我们只需要发送消息到Fanout的Exchange上,那么3个队列都会收到消息。

    目前主流的分布式中间件有:

    • Rabbit Mq
    • Kafka
    • Rocket Mq

    2.谈谈你对时间轮的理解

    2.1 什么是时间轮

    时间轮:一种用来存储定时任务的环状数组

    他的工作原理和钟表的表盘类似,他有两个部分组成:

    • 环形数组
    • 遍历环形数组的指针

    首先要定义一个固定长度的环形数组,然后数组的每一个元素代表一个时间刻度,假设每个刻度之间的间隔是1s,那么长度为8s的数组就代表8秒钟。

    然后就是需要有一个指针,那么这个指针是按照顺时针的方向,无限的循环这个数组,每隔一个最小的时间单位就前进一个数组的索引,那么这个指针完整的转一圈的话就代表8秒钟,转一圈的话就代表16秒钟,假设从0点0分0秒开始,转一圈之后就到了0点0分9秒

    2.2 时间轮的工作原理

    环形数组里面的每一个元素,都是用来存储定时任务的容器,当我们向时间轮里添加一个定时任务的时候,我们会根据定时任务的执行时间计算他所存储的数组下标,当然会在某个时间刻度上会存在多个定时任务,那么这个时候就会采用双向链表的方式进行存储。

    当我们的指针指向某个数组的时候,就会把这个数组中存储的任务取出来,然后就遍历这个链表,逐个去运行这个链表中的任务

    那么如果某个定时任务的执行时间,大于环状数组的长度,一般就可以使用一个圈数来表示该任务的延时执行时间,比如一个第16秒执行的任务,那就意味着这个任务应该在第2圈的数组下标为0的时候去执行。

    2.3 时间轮优缺点分析

    使用时间轮的方式来管理多个定时任务的好处有很多,我认为有两个比较重要的优点:

    • 1.可以减少定时任务添加和删除的时间复杂度,提升性能
    • 2.可以保证每次执行定时任务都是o(1)的复杂度,在定时任务执行密集的情况下,性能优势十分明显

    当然时间轮也有缺点:对于执行时间非常严格的任务,时间轮不是很合适,因为时间轮算法的精度取决于最小时间单元的粒度,假设以1秒为时间刻度的话,那么小于1s的任务就无法被时间轮调度

    同时时间轮算法在很多框架中都有用到,比如说:Dubbo,Netty,Kafka等。

    3.什么是幂等?如何解决幂等性问题

    3.1 什么是幂等

    幂等是一个数学上的概念,而在计算机编程领域中幂等是指一个方法任意多次执行所产生的影响均与一次执行的影响相同

    简单来说:一个逻辑即使被重复执行多次,也不影响最终结果的一致性。

    之所以要考虑幂等性问题,主要是因为在网络通讯中有两种行为都有可能导致我们的接口被重复执行:

    • 1.用户重复提交或者用户的恶意攻击会导致重复执行
    • 2.在分布式系统中,为了去避免数据的丢失,采用的超时重试机制

    所以在我的程序设计中对于数据变更操作的接口都要去保证接口的幂等性,而幂等性的核心思想,其实就是保证这个接口的执行结果只影响一次,后续再次调用,也不能对数据产生影响

    所以基于这个需求呢,如何去解决幂等性呢?

    3.2 如何解决幂等性问题

    解决幂等性问题的方法有很多,下面我分享一下一些常用的解决方案:

    • 1.使用数据库的唯一约束来实现幂等。

    比如说对于数据插入的场景而言,假设我们要创建一个订单,因为订单号肯定是唯一的,所以如果我们多次去调用数据库的唯一约束,他就会产生异常,从而去避免一个请求创建多个订单的问题。

    • 2.使用redis提供的setNX

    比如说我们对于MQ的消息的场景,我们要去避免MQ重复消费,从而导致数据多次被修改的问题,可以在接受MQ消息的时候把这个消息通过setNX写入到redis中,一旦这个消息被消费之后,我们就就不会被再次消费

    • 3.使用状态机来实现幂等,所谓状态机是指一条数据的完整的运行状态的转化流程

    比如说订单的状态,因为他的状态只会向前变更,所以多次修改同一条数据的时候一旦状态发生改变,那么这条数据修改造成的影响也只会发生一次。

    除了以上三种方法之外,我们还可以通过token机制或者去增加重表的方法来实现幂等。

    但是无论使用何种方法,无非也就是两种思路,要么就是接口只允许调用一次,比如说唯一约束、基于Redis的锁机制,要么就是对数据的影响只会发生一次,比如说悲观锁、乐观锁等等。

    4.在秒杀场景中,常见的限流算法有哪些

    5.Spring中的Bean是线程安全的吗?

    6.谈谈你对Spring Bean的理解

    7.Spring Bean的定义包含哪些内容

    8.为什么每个Spring Bean中每个Bean都要定义作用域?

    9.Spring Bean声明周期的全过程

    10.Spring为何需要三级缓存解决循环依赖而不是二级缓存

  • 相关阅读:
    CUDA学习笔记(七)Kernel性能调节
    基本代码讲解
    python+Vue企业人事考勤管理系统django_30n9o
    Qt正则表达式
    官方推荐:6种Pandas读取Excel的方法
    java计算机毕业设计海康物流MyBatis+系统+LW文档+源码+调试部署
    Linux命令-sed
    Android 底部导航栏(一、BottomNavigationView+Menu+Fragment)
    Python使用MySQL数据库
    我理解的反射
  • 原文地址:https://blog.csdn.net/zhiyikeji/article/details/126066416