面试中的消息队列考点
作者:互联网
辛辛苦苦查了大半天资料,总结出来面试没被问,不能白复习,贴上来~
1.什么是消息队列
生产者先将消息投递一个叫做「队列」的容器中,然后再从这个容器中取出消息,最后再转发给消费者,仅此而已。
是一种FIFO的数据结构
2.消息队列的模型
1.初代 ----队列模型
原始的生产者消费者模型, 多生产者,多消费者,通过缓存队列,通知 去取资源
2.进阶 ----发布-订阅模型
将一份消息数据分发给多个消费者,并且每个消费者都要求收到全量的消息
3.消息队列适用场景
- 解耦
通过消息队列就不会原来一个模块,而是拆分成几个模块
- 异步
通过消息队列,这些不需要返回的(如写入文件),的操作,将对于的数据给了之后,就立即返回响应,实际的操作放到后台去执行,执行完成再通知
- 削峰
如果一次需要5k个请求,则先放入MQ中,每次请求2k, 这样不会直接请求,导致缓存击穿
4.MQ的成熟方案
- ActiveMQ:
早起产品,现在基本没人用
- RabbitMQ:
开发语言 erlang 导致不好二次开发,但有人维护,追求性能和稳定性,推荐使用
- RocketMQ:
开发语言java, 阿里出品
- Kafka
大数据用的多
5.消息队列的缺点 与解决方案
- 系统可用性降低
搭建集群
- 系统复杂度提高
如以下几种:
1.消息丢失
原因:
可能由服务器宕机
解决:
确认机制,每一步进行一个ACK应答后处理,类似TCP重传处理
2.消息重复
原因:
多服务监听时,可能某个服务未收到,要求重发,导致消息重复
解决:
1>.设置幂等次接口,相同参数传进来,生产唯一标识,返回的一定是相同结果
强校验:
校验唯一标识是否一同返回,返回则有效
弱校验:
校验唯一标识一定时间内是否存在
2>.乐观锁
3>.记录每条被消费的消息状态
3.消息的顺序
原因:
网络波动,传达到各服务的速率不一致
解决:
设置 发送端的 QUEUE
6.消息队列 分布式队列
- 两阶段提交协议
- 三阶段提交协议
- Paxos协议
- Raft协议
7.观察者模式
基于发布-订阅观察者模式
1.类图关系
假装有图,懒得画
2.一个简易的观察者模式
#include <iostream>
#include <vector>
#include <string>
using namespace std;
#include <iostream>
using namespace std;
/**
抽象基类
*/
class base
{
public:
virtual void update(string message) = 0;
};
/**
客户端1
*/
class qqUser : public base
{
public:
void update(string message) {
cout << "qq -" << message<< endl;
}
};
/**
客户端2
*/
class weiXinUser : public base
{
public:
void update(string message) {
cout << "weixin -" << message << endl;
}
};
/**
服务器
*/
class interface{
private:
vector<base*> baseList;
public:
void add(base* input){
baseList.push_back(input);
}
void del() {
baseList.pop_back();
}
void notify(string message){
for(auto i : baseList) {
i->update(message);
}
}
};
int main() {
interface* mInterface = new interface();
qqUser* mQQUSER = new qqUser();
weiXinUser* mweiXinUser = new weiXinUser();
mInterface->add(mQQUSER);
mInterface->add(mweiXinUser);
mInterface->notify("recv string");
}
8.基于Rocket MQ的分布式事务
参考博客:
Rocket MQ分布式事务
1.原因:
一个操作是A价钱 B扣钱, 但是A、B 不在同一个数据库,需要引入消息队列
2.流程:
RocketMq消息中间件把消息分为两个阶段:Prepared阶段和确认阶段Prepared阶段(预备阶段)
进程变为:
1、在扣款之前,先发送预备消息
2、发送预备消息成功后,执行本地扣款事务
3、扣款成功后,再发送确认消息
4、消息端(加钱业务)可以看到确认消息,消费此消息,进行加钱
- 可能存在异常:
异常1:如果发送预备消息失败,下面的流程不会走下去;这个是正常的
异常2:如果发送预备消息成功,但执行本地事务失败;这个也没有问题,因为此预备消息不会被消费端订阅到,消费端不会执行业务。
异常3:如果发送预备消息成功,执行本地事务成功,但发送确认消息失败;这个就有问题了,因为用户A扣款成功了,但加钱业务没有订阅到确认消息,无法加钱。这里出现了数据不一致。
针对异常3 RocketMq 会进行【状态回查】,也就是RocketMq会定时遍历commitlog中的预备消息。
对于已发送的事务扣款成功,就补发commit,如果没有 成功就执行rollback
标签:队列,预备,void,发送,面试,考点,消息,message 来源: https://blog.csdn.net/Tyrion9/article/details/119464008