目录
9.如何确保消息正确地发送至RabbitMQ? 如何确保消息接收方消费了消息?
11.为什么不应该对所有的 message 都使用持久化机制?
RabbitMQ
1.什么是MQ?为什么使用MQ?MQ的优点
MQ:消息队列;是在消息传输过程中保存消息的容器。
主要是:
解耦:系统间通过消息通信,不用关心其他系统的处理
异步:多个系统写库时,不需同步执行,可以减少响应时间
削峰:减少高峰时期对服务器压力
2.什么是RabbitMQ?使用场景
RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的消息中间件;
使用场景:定时任务、服务间异步通信、顺序消费、请求削峰
3.RabbitMQ有什么优缺点?
优点:
1.应用解耦(MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序进行解耦合)
2.任务异步处理(将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间)
3.削峰填谷(数据量大时,数据库来不及处理,存入mq中保存,根据消费能力来进行处理)
缺点:
1.系统可用性降低(系统引入的外部依赖越多,系统稳定性越差)
2.系统复杂度提高(大大增加了系统的复杂度,以前系统间是同步的远程调用,现在是通过 MQ 进行异步调用)
3.一致性问题(如何保证消息数据处理的一致性)
4.RabbitMQ的工作模式
1.简单模式:产生消息,将消息放入队列,消费者监听 消息队列,如果队列中有消息,就消费掉
2.工作模式:产生消息,将消息放入队列,多个消费者同时监听,谁先拿到谁消费
3.发布/订阅模式:消息被路由投递给多个队列,一个消息被多个消费者获取
4.路由模式:消息生产者将消息发送给交换机按照路由判断,交换机根据配上路由 key 对应的消息队列,对应的消费者才能消费消息
5.主题模式:消息产生者产生消息把消息交给交换机,交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费
5.MQ 有哪些常见问题?
1.消息的顺序性问题
2.消息的重复问题
6.如何保证RabbitMQ消息的顺序性?
1.拆分成多个队列,每个队列一个消费者;
2.一个消费者对应一个队列,然后这个消费者内部用内存队列做排队,然后分发给底层不同的worker来处理
7.如何保证消息不被重复消费?
产生原因:因为消费者和MQ服务器网络闪断等原因,造成了消费者消费后,返回给MQ服务器一个ack确认消息,结果MQ没有接收到,造成了重复消费。
解决思路是:保证消息的唯一性,就算是多次传输,不要让消息的多次消费带来影响
1.在写入消息队列的数据做唯一标示,消费消息时,根据唯一标识判断是否消费过
2.利用一张日志表来记录已经处理成功的消息的 ID,如 果新到的消息 ID 已经在日志表中,那么就不再处理这条消息
8.消息如何分发?
分发机制:
1.轮询分发(默认):多个工作线程从队列中接收消息的时候采用的是轮询的方式,又称为公平分发
2.不公平分发:将任务发给空闲的消费者,而不是一直在那里等待
3.预值分发:就是设置该信道预取5条消息,当接受5条消息后,就将不再应答后续的消息,而内部传参的数字就是预取值的数量(要求大于1)
9.如何确保消息正确地发送至RabbitMQ? 如何确保消息接收方消费了消息?
正确发送:将信道设置成发送方确认模式,则所有在信道上发布的消息都会被指派一个唯一的ID。一旦消息被投递到目的队列后,或者消息被写入磁盘后,信道会发送一个确认给生产者;如果 RabbitMQ 发生内部错误从而导致消息丢失,会发送一条nack消息。
接收消费:接收方确认机制,消费者接收每一条消息后都必须进行确认。只有消费者确认消息,RabbitMQ 才能安全地把消息从队列中删除。
10.如何保证RabbitMQ消息的可靠传输?
消息不可靠的情况可能是消息丢失,劫持等原因;丢失又分为:生产者丢失消息、消息列表丢失消息、消费者丢失消息;
生产者丢失消息:发送消息前,开启事务,然后发送消息,如果发送过程中出现什么异常,事务就会回滚,如果发送成功则提交事务
消息列表丢失消息:消息持久化(开启持久化磁盘的配置)
消费者丢失消息:改为手动确认消息模式;消费者在收到消息之后,处理消息之前,会自动回复RabbitMQ已收到消息;如果这时处理消息失败,就会丢失该消息;解决方案:处理消息成功后,手动回复确认消息
11.为什么不应该对所有的 message 都使用持久化机制?
导致性能的下降;仅对关键消息作持久化处理(根据业务重要程度),且应该保证关键消息的量不会导致性能瓶颈
12.如何保证高可用的?
单机模式、普通集群模式、镜像集群模式
13.如何保证消息的一致性
1.生产者先把消息发送给MQ,消息状态标记为待确认;
2.MQ收到消息之后,把消息持久化到消息存储中,但并不向消费者投递消息;
3.MQ返回消息持久化结果(成功,或者失效),生产者根据返回结果进行判断如何处理业务操作处理;(失败:放弃业务操作处理;成功:执行业务操作处理)
4.业务操作完成后,把业务操作结果(成功/失败)发送给MQ;
5.MQ收到业务操作结果后,根据结果进行处理;(失败:删除消息存储中的消息;成功:更新消息存储中的消息状态为∙待发送)紧接着执行消息投递;
6.前面的正向流程都成功后,向消费者投递消息;
14.如何进行消息的重试机制?
消费者消费消息的时候,发生异常情况,导致消息未确认,该消息会被重复消费(默认没有重复次数,即无限循环消费),可以通过设置重试次数以及达到重试次数之后的消息处理
15.项目中有哪些地方用到了RabbitMQ
聊天室、秒杀、积分
16.RabbitMQ事务
事务是MQ中保证消息是否全部发送成功,防止丢失消息的一种策略;
开启事务:txSelect()方法
提交事务:txCommit()方法
回滚事务:txRollback()方法(回滚事务必须在关闭之前)
关闭:close()
17.什么是死信队列?如何导致?
当消息在一个队列中变成死信之后,它能被重新被发送到另一个交换器中,这个交换器就是 死信交换器,绑定死信交换器的队列就称之为死信队列。
导致死信的几种原因:
1.消息被拒
2.队列满了,无法再添加
3.消息存活时间过期
如果配置了死信队列信息,那么该消息将会被丢进死信队列中,如果没有配置,则该消息将会被丢弃;
死信队列应用场景:
一般用在较为重要的业务队列中,确保未被正确消费的消息不被丢弃,一般发生消费异常可能原因主要有由于消息本身存在错误导致处理异常,通过配置死信队列,可以让未正确处理的消息暂存到另一个队列中,待后续排查清楚问题后,编写相应的处理代码来处理死信消息
18.大量数据积压,该如何解决
当消息数量过多时,可能会导致消息积压,进而影响系统性能。
解决:
1.增加消费者:增加消费者数量可以提高消息处理速度
2.增加队列:可以增加队列的数量来缓解消息积压
3.增加MQ节点:增加MQ节点可以提高消息处理能力
4.消息重试机制:当消息处理失败时,可以将消息重新投递到队列中
5.设置消息过期时间:可以设置消息的过期时间,当消息在队列中等待时间超过指定时间时,会被自动删除,从而减少消息积压
6.使用限流机制:可以使用限流机制来控制消费者的消费速度,避免消息过多导致消费者无法及时处理
19.延迟消费
-
创建一个死信交换机并绑定一个死信队列
-
给消息的目标队列设置队列超时时间并指定死信交换机和路由 key
-
将消息的目标队列绑定到死信交换机
-
消费者监听死信队列获取超时消息
20.RabbitMQ的运行流程
生产者发送消息:
1.生产者连接到MQ,建立一个连接,开启一个信道
2.生产者声明一个交换器,并设置属性;
3.生产者声明一个队列,并设置属性;
4.生产者通过路由键将交换器和队列进行绑定
5.生产者发送消息到MQ,其中包含路由键、交换器等信息
6.交换器通过路由键匹配队列,找到存入队列;没找到回退给生产者
7.关闭信道、关闭连接
消费者发送消息:
1.消费者连接到MQ,建立一个连接,开启一个信道
2.消费者向MQ请求消费队列中的消息
3.等待MQ回应并投递队列中的消息,消费者接收消息
4.消费者确认接收到消息
5.MQ中删除确认的消息
6.关闭信道、关闭连接
Shiro
1.Shiro是什么?
是一个功能强大且易于使用的 Java 安全(权限)框架。Shiro 可以完成:认证、授权、加密、会话管理、与 Web 集成、缓存 等
2.为什么要用Shiro
易于使用:使用 Shiro 构建系统安全框架非常简单
全面:Shiro 包含系统安全框架需要的功能,满足安全需求的“一站式服“
灵活:Shiro 可以在任何应用程序环境中工作
强力支持 Web:Shiro 具有出色的 Web 应用程序支持
兼容性强:Shiro 的设计模式使其易于与其他框架和应用程序集成
社区支持:Shiro 是 Apache 软件基金会的一个开源项目,有完备的社区支持,文档支持
3.三大核心组件
Subject :当前用户的操作
SecurityManager:用于管理所有的Subject
Realm:用于进行权限信息的验证
4.有哪些基本功能
1.身份认证/登录,验证用户是不是拥有相应的身份
2.授权,即权限验证,验证某个已认证的用户是否拥有某个权限
3.会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有 信息都在会话中
4.加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储
5.Web 支持,可以非常容易的集成到 Web 环境
6.缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查
7.Shiro 支持多线程应用的并发验证
8.提供测试支持
9.允许一个用户假装为另一个用户(如果他们允许)的身份进行访问
10.记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了
5.Shiro 的优点
1.简单的身份认证, 支持多种数据源
2.对角色的简单的授权
3.不跟任何的框架或者容器捆绑, 可以独立运行
6.Shiro的四重权限控制方式
1.url级别权限控制
2.方法注解权限控制
3.代码级别权限控制
4.页面标签权限控制
7.Shiro的登录运行流程
1.首先调用Subject.login(token)进行登录
2.SecurityManager进行身份验证逻辑
3.把token传入Realm,从Realm获取身份验证信息,如果没有就返回认证失败,有的话就继续执行操作。
8.如何实现自实现授权
实际开发中,通常提供AuthorizingRealm的实现类,并提供 doGetAuthorizationInfo() 方法的具体实现。
9.Shiro授权过程
1.应用程序调用Subject 的方法, 传递权限
2.Subject调用securityManager 的对应的方法
3.SecurityManager调用Authorizer 接口的对应方法
4.每个配置好的 Realm 被检查是否实现了相同的 Authorizer 接口
10.什么是粗颗粒和细颗粒权限?
粗颗粒权限:对资源类型的管理;即只控制到菜单、按钮、方法。粗粒度的例子比如:用户具有用户管理的权限,具有导出订单明细的权限
细颗粒权限:对资源实例的控制;即控制到数据级别的权限,比如:用户只允许修改本部门的员工信息,用户只允许导出自己创建的订单明细
11.粗颗粒和细颗粒如何授权?
粗颗粒权限:可以使用过虑器统一拦截url
细颗粒权限:在service中控制,在程序级别来控制,个性化编程