【小滴课堂】RabbitMQ的核心组件+工作原理

525 阅读3分钟

我们知道rabbitmq主要是用在分布式系统里面的对消息的转发,它在扩展性、扩展性、高可用性都表现得不错,所以得到了不错的反响,它也是社区活跃度较高的消息中间件之一。


Rabbitmq的核心组件

先来看看Rabbitmq的结构模型,由生产者给交换机发送消息,然后交换机根据所定制的路由规则,就把不同的消息路由到不一样的队列里。监听队列就当有消息过来的时候就开始消费。

vHost虚拟主机

在rabbitmq服务器上可以设置多个虚拟主机,也可以说一个broker里面可以开多个vhost。其实每一个vhost它都是一个迷你版的rabbitmq服务器,都拥有自己的交换机,binding、队列。更核心的就是每一个vhost它是独立的权限机制,这样的话就可以安全的使用rabbitmq来服务多个程序。

Exchange交换机

根据路由规则把消息转发到队列里。

Connection

生产/消费者都需要跟broker来进行连接,它是一条tcp连接。

什么是AMQP?

其实就是生产者发送消息,然后经过了交换机,交换机再根据路由规则来给队列,最后面AMQP代理就会把消息投递给订阅了这个队列的消费者。

ChannelManager解析

首先看看它的成员变量有哪些

变量名称默认值描述
final Object monitornew Object()加锁的对象
final Map<Integer, ChannelN> _channelMapnew HashMap通道map对象
final IntAllocator channelNumberAllocator通道编号分配器
final ConsumerWorkService workService工作服务对象
final Set shutdownSetnew HashSet()关闭线程等待

方法

方法名描述
ChannelManager( workService, channelMax,threadFactory,metricsCollector)构造方法
ChannelN getChannel(int channelNumber)获取通道对象,需要对于monitor加锁
void handleSignal(final ShutdownSignalException signal)处理关闭信号,也就关闭对应通道
ChannelN createChannel(AMQConnection connection)创建通道
void realeaseChannelNumber(ChannelN channel)释放通道

在生产/消费消息之前需要初始化Channel

Channel channel = connection.createChannel();

上面的createChannel它是AMQConnection里的一个方法

public Channel createChannel(int channelNumber) throws IOException {
    ensureIsOpen();
    ChannelManager cm = _channelManager;
    if (cm == null) return null;
    return cm.createChannel(this, channelNumber);
}
public Channel createChannel() throws IOException {
    ensureIsOpen();
    ChannelManager cm = _channelManager;
    if (cm == null) return null;
    return cm.createChannel(this);
}

这里调用了createChannel方法,接下来就是ChannelManager创建了Channel

public ChannelN createChannel(AMQConnection connection) throws IOException {
    ChannelN ch;
    synchronized (this.monitor) {
        int channelNumber = channelNumberAllocator.allocate();
        if (channelNumber == -1) {
            return null;
        } else {
            ch = addNewChannel(connection, channelNumber);
        }
    }
    ch.open(); // now that it's been safely added
    return ch;
}

public ChannelN createChannel(AMQConnection connection, int channelNumber) throws IOException {
    ChannelN ch;
    synchronized (this.monitor) {
        if (channelNumberAllocator.reserve(channelNumber)) {
            ch = addNewChannel(connection, channelNumber);
        } else {
            return null;
        }
    }
    ch.open(); // now that it's been safely added
    return ch;
}

private ChannelN addNewChannel(AMQConnection connection, int channelNumber) throws IOException {
    if (_channelMap.containsKey(channelNumber)) {
        // That number's already allocated! Can't do it
        // This should never happen unless something has gone
        // badly wrong with our implementation.
        throw new IllegalStateException("We have attempted to "
                + "create a channel with a number that is already in "
                + "use. This should never happen. "
                + "Please report this as a bug.");
    }
    ChannelN ch = instantiateChannel(connection, channelNumber, this.workService);
    _channelMap.put(ch.getChannelNumber(), ch);
    return ch;
}

protected ChannelN instantiateChannel(AMQConnection connection, int channelNumber, ConsumerWorkService workService) {
    return new ChannelN(connection, channelNumber, workService);
}

其实addNewChannel它就是创建了ChannelN对象,然后就是在ChannelManager里的_channelMap当中,易于管理,而chanelNumberAllocator它其实是channelNumber的分配器,就是采用BitSet来实现分配的。

void handleSignal(final ShutdownSignalException signal)

(1)需要同步获取到所有的通道

(2)移除掉通道的编号

(3)创建channel关闭的Runnable接口

(4)shudownExecutor为空,那么就直接同步run方法

(5)shudownExecutor不为空,就异步的执行和确定关闭通道的超时时间

(6)把每一个channel关闭,再把countdownlatch对象给收集起来

(7)通知关闭监听器,执行关闭的操作

(8)在关闭consumerworkservice的时候需要等待所有的channel才执行。

ChannelN createChannel

(1)分配通道编号

(2)添加新通道(父级方法)

(3)判断通道编号是否存在,存在则抛出异常

(4)将通道加入到通道map中

(5)打开通道操作,连接