字节真题:高并发消息队列设计
面试重要程度:⭐⭐⭐⭐⭐
真题来源:字节跳动2024校招技术面试
考察重点:高并发架构设计、消息队列原理、系统优化
预计阅读时间:45分钟
真题背景
面试官: "我们需要设计一个高并发的消息队列系统,支持每秒百万级消息处理,要求消息不丢失、有序性保证、支持多种消费模式。请详细设计这个系统的架构,包括存储方案、网络通信、性能优化等方面。如果消息堆积严重怎么处理?"
考察意图:
- 高并发系统架构设计能力
- 消息队列核心原理的深度理解
- 性能优化和问题解决思路
- 分布式系统设计经验
🎯 系统架构设计
整体架构
/**
* 高并发消息队列架构
*/
@Component
public class HighPerformanceMessageQueue {
// 性能指标
public static final int MAX_TPS = 1_000_000; // 百万级TPS
public static final int MAX_LATENCY_MS = 10; // 延迟<10ms
public static final int REPLICATION_FACTOR = 3; // 3副本
/**
* Broker节点
*/
public static class BrokerNode {
private String brokerId;
private BrokerRole role; // MASTER, SLAVE
private StorageEngine storageEngine;
private NetworkServer networkServer;
public SendResult handleSendMessage(SendMessageRequest request) {
try {
// 1. 验证消息
validateMessage(request.getMessage());
// 2. 选择队列
TopicQueue queue = selectQueue(request.getTopic());
// 3. 存储消息
MessageStoreResult result = storageEngine.storeMessage(
queue.getQueueId(), request.getMessage());
// 4. 同步到从节点
if (role == BrokerRole.MASTER) {
syncToSlaves(result);
}
return SendResult.success(result.getMessageId());
} catch (Exception e) {
return SendResult.failed(e.getMessage());
}
}
}
}
🚀 存储引擎设计
高性能存储方案
/**
* 基于文件的存储引擎
*/
@Component
public class FileBasedStorageEngine {
/**
* CommitLog - 顺序写入的消息日志
*/
public static class CommitLog {
private final MappedByteBuffer mappedByteBuffer;
private final AtomicLong wrotePosition;
private final int fileSize = 1024 * 1024 * 1024; // 1GB
/**
* 追加消息到CommitLog
*/
public AppendMessageResult appendMessage(Message message) {
try {
ByteBuffer messageBuffer = serializeMessage(message);
int messageSize = messageBuffer.remaining();
// 检查空间
if (wrotePosition.get() + messageSize > fileSize) {
return AppendMessageResult.END_OF_FILE;
}
// 写入消息
long currentPos = wrotePosition.get();
mappedByteBuffer.position((int) currentPos);
mappedByteBuffer.put(messageBuffer);
wrotePosition.addAndGet(messageSize);
return AppendMessageResult.success(currentPos, messageSize);
} catch (Exception e) {
return AppendMessageResult.failed(e.getMessage());
}
}
/**
* 异步刷盘
*/
public void flush() {
if (mappedByteBuffer != null) {
mappedByteBuffer.force();
}
}
}
/**
* ConsumeQueue - 消费队列索引
*/
public static class ConsumeQueue {
private final MappedByteBuffer mappedByteBuffer;
private final AtomicLong maxOffset;
// 每个索引项20字节:8字节偏移量 + 4字节大小 + 8字节Tag
private static final int CQ_STORE_UNIT_SIZE = 20;
public void putMessagePositionInfo(long offset, int size, long tagsCode) {
ByteBuffer buffer = ByteBuffer.allocate(CQ_STORE_UNIT_SIZE);
buffer.putLong(offset);
buffer.putInt(size);
buffer.putLong(tagsCode);
buffer.flip();
long currentOffset = maxOffset.get();
mappedByteBuffer.position((int) (currentOffset * CQ_STORE_UNIT_SIZE));
mappedByteBuffer.put(buffer);
maxOffset.incrementAndGet();
}
}
}
🌐 网络通信优化
高性能网络层
/**
* 基于Netty的网络服务器
*/
@Component
public class NettyRemotingServer {
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
@PostConstruct
public void start() {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup(16);
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_KEEPALIVE, false)
.childHandler(new ChannelInitializer<SocketChannel>()
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
Java面试圣经 文章被收录于专栏
Java面试圣经,带你练透java圣经
查看5道真题和解析