Broker是metaq的核心组件,负责消息的物理存储,分区指定等。例子配置文件
[system] #broker编号,集群唯一 brokerId=0 #这个broker指定的分区数 numPartitions=2 #nio port serverPort=8123 #异步刷盘策略,为0表示同步刷盘 unflushThreshold=0 #同上,刷盘间隔 unflushInterval=10000 #单个消息文件的最大size maxSegmentSize=1073741824 #单个请求最大传输size maxTransferSize=1048576 #数据清理 deletePolicy=delete,168 #quartz的delete任务表达式 deleteWhen=0 0 6,18 * * ? flushTxLogAtCommit=1 stat=true ;; Update consumers offsets to current max offsets when consumers offsets are out of range of current broker's messages. ;; It must be false in production.But recommend to be true in development or test. updateConsumerOffsets=true [zookeeper] zk.zkConnect=localhost:2181 zk.zkSessionTimeoutMs=30000 zk.zkConnectionTimeoutMs=30000 zk.zkSyncTimeMs=5000 ;; Topics section #topic名称 [topic=test] [topic=meta-test]
broker核心类图如下
Broker处理如下
1.broker启动
MetaMorphosisBroker创建,初始化zk连接
public MetaMorphosisBroker(final MetaConfig metaConfig) {
super();
this.metaConfig = metaConfig;
//NIO server
this.remotingServer = newRemotingServer(metaConfig);
this.executorsManager = new ExecutorsManager(metaConfig);
//全局ID生成器
this.idWorker = new IdWorker(metaConfig.getBrokerId());
//文件管理
this.storeManager = new MessageStoreManager(metaConfig, this.newDeletePolicy(metaConfig));
//监控
this.statsManager = new StatsManager(this.metaConfig, this.storeManager, this.remotingServer);
//zookeeper客户端
this.brokerZooKeeper = new BrokerZooKeeper(metaConfig);
final BrokerCommandProcessor next =
new BrokerCommandProcessor(this.storeManager, this.executorsManager, this.statsManager,
this.remotingServer, metaConfig, this.idWorker, this.brokerZooKeeper);
JournalTransactionStore transactionStore = null;
try {
transactionStore = new JournalTransactionStore(metaConfig.getDataLogPath(), this.storeManager, metaConfig);
}
catch (final Exception e) {
throw new MetamorphosisServerStartupException("Initializing transaction store failed", e);
}
//带事务的处理器
this.brokerProcessor =
new TransactionalCommandProcessor(metaConfig, this.storeManager, this.idWorker, next, transactionStore,
this.statsManager);
this.shutdownHook = new ShutdownHook();
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
MetaMBeanServer.registMBean(this, null);
}
broker启动
public synchronized void start() {
if (!this.shutdown) {
return;
}
this.shutdown = false;
//加载已有数据并校验老数据
this.storeManager.init();
this.executorsManager.init();
this.statsManager.init();
//不同command对应不同处理器
this.registerProcessors();
try {
//NIO server启动
this.remotingServer.start();
}
catch (final NotifyRemotingException e) {
throw new MetamorphosisServerStartupException("start remoting server failed", e);
}
try {
//在/brokers/ids下创建临时节点,名称为节点Id
//如果为master节点,则创建/brokers/ids/0/master节点
this.brokerZooKeeper.registerBrokerInZk();
//如果为master节点,则创建/brokers/ids/master_config_checksum节点
this.brokerZooKeeper.registerMasterConfigFileChecksumInZk();
this.addTopicsChangeListener();
//在/brokers/topics-sub和/brokers/pub创建对应topic临时节点-topics
this.registerTopicsInZk();
this.registerZkSuccess = true;
}
catch (final Exception e) {
this.registerZkSuccess = false;
throw new MetamorphosisServerStartupException("Register broker to zk failed", e);
}
log.info("Starting metamorphosis server...");
this.brokerProcessor.init();
log.info("Start metamorphosis server successfully");
}
注册的处理器
private void registerProcessors() {
this.remotingServer.registerProcessor(GetCommand.class, new GetProcessor(this.brokerProcessor,
this.executorsManager.getGetExecutor()));
this.remotingServer.registerProcessor(PutCommand.class, new PutProcessor(this.brokerProcessor,
this.executorsManager.getUnOrderedPutExecutor()));
this.remotingServer.registerProcessor(OffsetCommand.class, new OffsetProcessor(this.brokerProcessor,
this.executorsManager.getGetExecutor()));
this.remotingServer
.registerProcessor(HeartBeatRequestCommand.class, new VersionProcessor(this.brokerProcessor));
this.remotingServer.registerProcessor(QuitCommand.class, new QuitProcessor(this.brokerProcessor));
this.remotingServer.registerProcessor(StatsCommand.class, new StatsProcessor(this.brokerProcessor));
this.remotingServer.registerProcessor(TransactionCommand.class, new TransactionProcessor(this.brokerProcessor,
this.executorsManager.getUnOrderedPutExecutor()));
}
2.无事务put请求
根据注册的处理器,put请求由PutProcessor处理
public void handleRequest(final PutCommand request, final Connection conn) {
final TransactionId xid = request.getTransactionId();
final SessionContext context = SessionContextHolder.getOrCreateSessionContext(conn, xid);
try {
this.processor.processPutCommand(request, context, new PutCallback() {
@Override
public void putComplete(final ResponseCommand resp) {
RemotingUtils.response(context.getConnection(), resp);
}
});
// RemotingUtils.response(context.getConnection(),
// PutProcessor.this.processor.processPutCommand(request, context));
}
catch (final Exception e) {
RemotingUtils.response(context.getConnection(), new BooleanCommand(HttpStatus.InternalServerError,
e.getMessage(), request.getOpaque()));
}
}
无事务请求由BrokerCommandProcessor处理
public void processPutCommand(final PutCommand request, final SessionContext sessionContext, final PutCallback cb) {
final String partitionString = this.metaConfig.getBrokerId() + "-" + request.getPartition();
.....
//partition信息
final int partition = this.getPartition(request);
//partition对应的store
final MessageStore store = this.storeManager.getOrCreateMessageStore(request.getTopic(), partition);
// 如果是动态添加的topic,需要注册到zk
this.brokerZooKeeper.registerTopicInZk(request.getTopic(), false);
// 设置唯一id
final long messageId = this.idWorker.nextId();
//写数据
store.append(messageId, request,
new StoreAppendCallback(partition, partitionString, request, messageId, cb));
}
catch (final Exception e) {
this.statsManager.statsPutFailed(request.getTopic(), partitionString, 1);
log.error("Put message failed", e);
if (cb != null) {
cb.putComplete(new BooleanCommand(HttpStatus.InternalServerError, e.getMessage(), request.getOpaque()));
}
}
}
具体写数据过程
private void appendBuffer(final ByteBuffer buffer, final AppendCallback cb) {
if (this.closed) {
throw new IllegalStateException("Closed MessageStore.");
}
if (this.useGroupCommit() && buffer.remaining() < this.maxTransferSize) {
this.bufferQueue.offer(new WriteRequest(buffer, cb));
}
else {
Location location = null;
final int remainning = buffer.remaining();
//单线程append
this.writeLock.lock();
try {
//当前最新的消息文件
final Segment cur = this.segments.last();
//append,返回写入数据量
final long offset = cur.start + cur.fileMessageSet.append(buffer);
//根据刷盘策略,判断需要刷盘
this.mayBeFlush(1);
//超过一定大小,生成新的消息文件
this.mayBeRoll();
location = new Location(offset, remainning);
}
catch (final IOException e) {
log.error("Append file failed", e);
location = Location.InvalidLocaltion;
}
finally {
this.writeLock.unlock();
if (cb != null) {
cb.appendComplete(location);
}
}
}
}
append
public long append(final ByteBuffer buf) throws IOException {
if (!this.mutable) {
throw new UnsupportedOperationException("Immutable message set");
}
final long offset = this.sizeInBytes.get();
int sizeInBytes = 0;
//循环写入buffer,直到完成
while (buf.hasRemaining()) {
sizeInBytes += this.channel.write(buf);
}
this.sizeInBytes.addAndGet(sizeInBytes);
this.messageCount.incrementAndGet();
return offset;
}
flush
public void flush() throws IOException {
//写入磁盘
this.channel.force(true);
this.highWaterMark.set(this.sizeInBytes.get());
}
3.get请求
根据注册的处理器,get请求由GetProcessor处理,get请求无事务,BrokerCommandProcessor处理
public ResponseCommand processGetCommand(final GetCommand request, final SessionContext ctx, final boolean zeroCopy) {
final String group = request.getGroup();
final String topic = request.getTopic();
this.statsManager.statsGet(topic, group, 1);
// 如果分区被关闭,禁止读数据 --wuhua
if (this.metaConfig.isClosedPartition(topic, request.getPartition())) {
log.warn("can not get message for topic=" + topic + " from partition " + request.getPartition()
+ ",it closed,");
return new BooleanCommand(HttpStatus.Forbidden, "Partition["
+ this.metaConfig.getBrokerId() + "-" + request.getPartition() + "] has been closed", request.getOpaque());
}
//根据partition拿store
final MessageStore store = this.storeManager.getMessageStore(topic, request.getPartition());
if (store == null) {
this.statsManager.statsGetMiss(topic, group, 1);
return new BooleanCommand(HttpStatus.NotFound, "The topic `" + topic
+ "` in partition `" + request.getPartition() + "` is not exists", request.getOpaque());
}
if (request.getMaxSize() <= 0) {
return new BooleanCommand(HttpStatus.BadRequest, "Bad request,invalid max size:"
+ request.getMaxSize(), request.getOpaque());
}
try {
//根据offset和transferSize拿messageSet视图
final MessageSet set =
store.slice(request.getOffset(),
Math.min(this.metaConfig.getMaxTransferSize(), request.getMaxSize()));
if (set != null) {
//zeroCopy直接从OS内核写入socket缓存,不经过用户态
if (zeroCopy) {
set.write(request, ctx);
return null;
}
else {
// refer to the code of line 440 in MessageStore
// create two copies of byte array including the byteBuffer
// and new bytes
// this may not a good use case of Buffer
final ByteBuffer byteBuffer =
ByteBuffer.allocate(Math.min(this.metaConfig.getMaxTransferSize(), request.getMaxSize()));
set.read(byteBuffer);
byteBuffer.flip();
final byte[] bytes = new byte[byteBuffer.remaining()];
byteBuffer.get(bytes);
return new DataCommand(bytes, request.getOpaque());
}
}
//没取到数据。。。
else {
this.statsManager.statsGetMiss(topic, group, 1);
this.statsManager.statsGetFailed(topic, group, 1);
// 当请求的偏移量大于实际最大值时,返回给客户端实际最大的偏移量.
final long maxOffset = store.getMaxOffset();
final long requestOffset = request.getOffset();
if (requestOffset > maxOffset
&& (this.metaConfig.isUpdateConsumerOffsets() || requestOffset == Long.MAX_VALUE)) {
log.info("offset[" + requestOffset + "] is exceeded,tell the client real max offset: " + maxOffset
+ ",topic=" + topic + ",group=" + group);
this.statsManager.statsOffset(topic, group, 1);
return new BooleanCommand(HttpStatus.Moved, String.valueOf(maxOffset), request.getOpaque());
}
else {
return new BooleanCommand(HttpStatus.NotFound, "Could not find message at position " + requestOffset,
request.getOpaque());
}
}
}
catch (final ArrayIndexOutOfBoundsException e) {
log.error("Could not get message from position " + request.getOffset() + ",it is out of bounds,topic="
+ topic);
// 告知最近可用的offset
this.statsManager.statsGetMiss(topic, group, 1);
this.statsManager.statsGetFailed(topic, group, 1);
final long validOffset = store.getNearestOffset(request.getOffset());
this.statsManager.statsOffset(topic, group, 1);
return new BooleanCommand(HttpStatus.Moved, String.valueOf(validOffset), request.getOpaque());
}
catch (final Throwable e) {
log.error("Could not get message from position " + request.getOffset(), e);
this.statsManager.statsGetFailed(topic, group, 1);
return new BooleanCommand(HttpStatus.InternalServerError, e.getMessage(), request.getOpaque());
}
}
slice获取message视图
/**
* 根据offset和maxSize返回所在MessageSet, 当offset超过最大offset的时候返回null,
* 当offset小于最小offset的时候抛出ArrayIndexOutOfBounds异常
*
* @param offset
*
* @param maxSize
* @return
* @throws IOException
*/
public MessageSet slice(final long offset, final int maxSize) throws IOException {
//二分查找命中segment
final Segment segment = this.findSegment(this.segments.view(), offset);
if (segment == null) {
return null;
}
else {
//返回message视图
return segment.fileMessageSet.slice(offset - segment.start, offset - segment.start + maxSize);
}
}