/**
* $Id: BrokerController.java 1831 2013-05-16 01:39:51Z shijia.wxr $
*/
package com.alibaba.rocketmq.broker;
import java.io.IOException;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.rocketmq.broker.client.ClientHousekeepingService;
import com.alibaba.rocketmq.broker.client.ConsumerManager;
import com.alibaba.rocketmq.broker.client.ProducerManager;
import com.alibaba.rocketmq.broker.longpolling.PullRequestHoldService;
import com.alibaba.rocketmq.broker.offset.ConsumerOffsetManager;
import com.alibaba.rocketmq.broker.processor.AdminBrokerProcessor;
import com.alibaba.rocketmq.broker.processor.ClientManageProcessor;
import com.alibaba.rocketmq.broker.processor.EndTransactionProcessor;
import com.alibaba.rocketmq.broker.processor.PullMessageProcessor;
import com.alibaba.rocketmq.broker.processor.QueryMessageProcessor;
import com.alibaba.rocketmq.broker.processor.SendMessageProcessor;
import com.alibaba.rocketmq.broker.topic.TopicConfigManager;
import com.alibaba.rocketmq.common.BrokerConfig;
import com.alibaba.rocketmq.common.DataVersion;
import com.alibaba.rocketmq.common.MixAll;
import com.alibaba.rocketmq.common.namesrv.TopAddressing;
import com.alibaba.rocketmq.common.protocol.MQProtos;
import com.alibaba.rocketmq.common.protocol.MQProtosHelper;
import com.alibaba.rocketmq.remoting.RemotingServer;
import com.alibaba.rocketmq.remoting.netty.NettyRemotingServer;
import com.alibaba.rocketmq.remoting.netty.NettyRequestProcessor;
import com.alibaba.rocketmq.remoting.netty.NettyServerConfig;
import com.alibaba.rocketmq.store.DefaultMessageStore;
import com.alibaba.rocketmq.store.MessageStore;
import com.alibaba.rocketmq.store.config.BrokerRole;
import com.alibaba.rocketmq.store.config.MessageStoreConfig;
/**
* Broker�������������
*
* @author vintage.wang@gmail.com shijia.wxr@taobao.com
*/
public class BrokerController {
private static final Logger log = LoggerFactory.getLogger(MixAll.BrokerLoggerName);
// ����������
private final BrokerConfig brokerConfig;
// ͨ�Ų�����
private final NettyServerConfig nettyServerConfig;
// �洢������
private final MessageStoreConfig messageStoreConfig;
// �����ļ��汾��
private final DataVersion configDataVersion = new DataVersion();
// �洢�����
private MessageStore messageStore;
// ͨ�Ų����
private RemotingServer remotingServer;
// ���ѽ��ȴ洢
private final ConsumerOffsetManager consumerOffsetManager;
// Consumer���ӡ����Ĺ�ϵ����
private final ConsumerManager consumerManager;
// Producer���ӹ���
private final ProducerManager producerManager;
// ������пͻ�������
private final ClientHousekeepingService clientHousekeepingService;
// Topic����
private TopicConfigManager topicConfigManager;
// ��������Ϣ�̳߳�
private ExecutorService sendMessageExecutor;
// ������ȡ��Ϣ�̳߳�
private ExecutorService pullMessageExecutor;
// �������Broker�̳߳�
private ExecutorService adminBrokerExecutor;
private final PullMessageProcessor pullMessageProcessor;
private final PullRequestHoldService pullRequestHoldService;
private ScheduledExecutorService scheduledExecutorService = Executors
.newSingleThreadScheduledExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "BrokerControllerScheduledThread");
}
});
public BrokerController(final BrokerConfig brokerConfig, final NettyServerConfig nettyServerConfig,
final MessageStoreConfig messageStoreConfig) {
this.brokerConfig = brokerConfig;
this.nettyServerConfig = nettyServerConfig;
this.messageStoreConfig = messageStoreConfig;
this.consumerOffsetManager = new ConsumerOffsetManager(this);
this.topicConfigManager = new TopicConfigManager(this);
this.pullMessageProcessor = new PullMessageProcessor(this);
this.pullRequestHoldService = new PullRequestHoldService(this);
this.consumerManager = new ConsumerManager();
this.producerManager = new ProducerManager();
this.clientHousekeepingService = new ClientHousekeepingService(this);
}
public String getBrokerAddr() {
String addr = this.brokerConfig.getBrokerIP1() + ":" + this.nettyServerConfig.getListenPort();
return addr;
}
private boolean registerToNameServer() {
TopAddressing topAddressing = new TopAddressing();
String addrs =
(null == this.brokerConfig.getNamesrvAddr()) ? topAddressing.fetchNSAddr() : this.brokerConfig
.getNamesrvAddr();
if (addrs != null) {
String[] addrArray = addrs.split(";");
if (addrArray != null && addrArray.length > 0) {
Random r = new Random();
int begin = Math.abs(r.nextInt()) % 1000000;
for (int i = 0; i < addrArray.length; i++) {
String addr = addrArray[begin++ % addrArray.length];
boolean result =
MQProtosHelper.registerBrokerToNameServer(addr, this.getBrokerAddr(), 1000 * 10);
log.info("register broker[" + this.getBrokerAddr() + "] to name server[" + addr + "] "
+ (result ? " success" : " failed"));
if (result)
return true;
}
}
}
return false;
}
public boolean initialize() {
boolean result = true;
// ��ӡ���������ò���
MixAll.printObjectProperties(log, this.brokerConfig);
MixAll.printObjectProperties(log, this.nettyServerConfig);
MixAll.printObjectProperties(log, this.messageStoreConfig);
// ע�ᵽName Server
// result = result && this.registerToNameServer();
registerToNameServer();
// ����Topic����
result = result && this.topicConfigManager.load();
// ����Consumer Offset
result = result && this.consumerOffsetManager.load();
// ��ʼ���洢��
if (result) {
try {
this.messageStore = new DefaultMessageStore(this.messageStoreConfig);
}
catch (IOException e) {
result = false;
e.printStackTrace();
}
}
// ���ر�����Ϣ����
result = result && this.messageStore.load();
if (result) {
// ��ʼ��ͨ�Ų�
this.remotingServer = new NettyRemotingServer(this.nettyServerConfig, this.clientHousekeepingService);
// ��ʼ���̳߳�
this.sendMessageExecutor =
Executors.newFixedThreadPool(this.brokerConfig.getSendMessageThreadPoolNums(),
new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "SendMessageThread_" + this.threadIndex.incrementAndGet());
}
});
this.pullMessageExecutor =
Executors.newFixedThreadPool(this.brokerConfig.getPullMessageThreadPoolNums(),
new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "PullMessageThread_" + this.threadIndex.incrementAndGet());
}
});
this.adminBrokerExecutor =
Executors.newFixedThreadPool(this.brokerConfig.getAdminBrokerThreadPoolNums(),
new ThreadFactory() {
private AtomicInteger threadIndex = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "AdminBrokerThread_" + this.threadIndex.incrementAndGet());
}
});
this.registerProcessor();
// ��ʱˢ���ѽ���
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
BrokerController.this.consumerOffsetManager.flush();
}
catch (Exception e) {
log.error("", e);
}
}
}, 1000 * 10, this.brokerConfig.getFlushConsumerOffsetInterval(), TimeUnit.MILLISECONDS);
// ��ʱˢ���ѽ��ȣ���ʷ��¼���������ɱ���
this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
BrokerController.this.consumerOffsetManager.flushHistory();
BrokerController.this.consumerOffsetManager.recordPullTPS();
}
catch (Exception e) {
log.error("", e);
}
}
}, 1000 * 10, this.brokerConfig.getFlushConsumerOffsetHistoryInterval(), TimeUnit.MILLISECONDS);
// �����slave
if (BrokerRole.SLAVE == this.messageStoreConfig.getBrokerRole()) {
if (this.messageStoreConfig.getMasterAddress() != null
&& this.messageStoreConfig.getMasterAddress().length() >= 6) {
this.messageStore.updateMasterAddress(this.messageStoreConfig.getMasterAddress());
}
else {
// TODO ��ʱȥ���µ�ַ
}
}
}
return result;
}
public void registerProcessor() {
this.remotingServer.registerProcessor(MQProtos.MQRequestCode.SEND_MESSAGE_VALUE, new SendMessageProcessor(
this), this.sendMessageExecutor);
this.remotingServer.registerProcessor(MQProtos.MQRequestCode.PULL_MESSAGE_VALUE,
this.pullMessageProcessor, this.pullMessageExecutor);
NettyRequestProcessor queryProcessor = new QueryMessageProcessor(this);
this.remotingServer.registerProcessor(MQProtos.MQRequestCode.QUERY_MESSAGE_VALUE, queryProcessor,
this.pullMessageExecutor);
this.remotingServer.registerProcessor(MQProtos.MQRequestCode.VIEW_MESSAGE_BY_ID_VALUE, queryProcessor,
this.pullMessageExecutor);
NettyRequestProcessor clientProcessor = new ClientManageProcessor(this);
this.remotingServer.registerProcessor(MQProtos.MQRequestCode.HEART_BEAT_VALUE, clientProcessor,
this.adminBrokerExecutor);
this.remotingServer.registerProcessor(MQProtos.MQRequestCode.UNREGISTER_CLIENT_VALUE, queryProcessor,
this.adminBrokerExecutor);
this.remotingServer.registerProcessor(MQProtos.MQRequestCode.END_TRANSACTION_VALUE,
new EndTransactionProcessor(this), this.sendMessageExecutor);
this.remotingServer.registerDefaultProcessor(new AdminBrokerProcessor(this), this.adminBrokerExecutor);
}
public void start() throws Exception {
if (this.messageStore != null) {
this.messageStore.start();
}
if (this.remotingServer != null) {
this.remotingServer.start();
}
if (this.pullRequestHoldService != null) {
this.pullRequestHoldService.start();
}
if (this.clientHousekeepingService != null) {
this.clientHousekeepingService.start();
}
}
public void shutdown() {
if (this.clientHousekeepingService != null) {
this.clientHousekeepingService.shutdown();
}
if (this.pullRequestHoldService != null) {
this.pullRequestHoldService.shutdown();
}
if (this.remotingServer != null) {
this.remotingServer.shutdown();
}
if (this.messageStore != null) {
this.messageStore.shutdown();
}
this.scheduledExecutorService.shutdown();
if (this.sendMessageExecutor != null) {
this.sendMessageExecutor.shutdown();
}
if (this.pullMessageExecutor != null) {
this.pullMessageExecutor.shutdown();
}
if (this.adminBrokerExecutor != null) {
this.adminBrokerExecutor.shutdown();
}
this.consumerOffsetManager.flush();
}
public MessageStore getMessageStore() {
return messageStore;
}
public void setMessageStore(MessageStore messageStore) {
this.messageStore = messageStore;
}
public RemotingServer getRemotingServer() {
return remotingServer;
}
public void setRemotingServer(RemotingServer remotingServer) {
this.remotingServer = remotingServer;
}
public BrokerConfig getBrokerConfig() {
return brokerConfig;
}
public NettyServerConfig getNettyServerConfig() {
return nettyServerConfig;
}
public MessageStoreConfig getMessageStoreConfig() {
return messageStoreConfig;
}
public ConsumerOffsetManager getConsumerOffsetManager() {
return consumerOffsetManager;
}
public TopicConfigManager getTopicConfigManager() {
return topicConfigManager;
}
public void setTopicConfigManager(TopicConfigManager topicConfigManager) {
this.topicConfigManager = topicConfigManager;
}
public void updateAllConfig(Properties properties) {
MixAll.properties2Object(properties, brokerConfig);
MixAll.properties2Object(properties, nettyServerConfig);
MixAll.properties2Object(properties, messageStoreConfig);
this.configDataVersion.nextVersion();
this.flushAllConfig();
}
private void flushAllConfig() {
String allConfig = this.encodeAllConfig();
boolean result = MixAll.string2File(allConfig, this.brokerConfig.getConfigFilePath());
log.info("flush topic config, " + this.brokerConfig.getConfigFilePath() + (result ? " OK" : " Failed"));
}
public String encodeAllConfig() {
StringBuilder sb = new StringBuilder();
{
Properties properties = MixAll.object2Properties(this.brokerConfig);
if (properties != null) {
sb.append(MixAll.properties2String(properties));
}
else {
log.error("encodeAllConfig object2Properties error");
}
}
{
Properties properties = MixAll.object2Properties(this.messageStoreConfig);
if (properties != null) {
sb.append(MixAll.properties2String(properties));
}
else {
log.error("encodeAllConfig object2Properties error");
}
}
{
Properties properties = MixAll.object2Properties(this.nettyServerConfig);
if (properties != null) {
sb.append(MixAll.properties2String(properties));
}
else {
log.error("encodeAllConfig object2Properties error");
}
}
return sb.toString();
}
public String getConfigDataVersion() {
return this.configDataVersion.currentVersion();
}
public PullMessageProcessor getPullMessageProcessor() {
return pullMessageProcessor;
}
public PullRequestHoldService getPullRequestHoldService() {
return pullRequestHoldService;
}
public ConsumerManager getConsumerManager() {
return consumerManager;
}
public ProducerManager getProducerManager() {
return producerManager;
}
}