
kafka
kafka 源码分析,性能调优
画画的老顽童
这个作者很懒,什么都没留下…
展开
-
kafka 消费者-comsumer
public class Consumer extends ShutdownableThread { private final KafkaConsumer<Integer, String> consumer; private final String topic; public Consumer(String topic) { super("KafkaConsumerExample", false); Properties props原创 2021-03-22 23:03:59 · 507 阅读 · 0 评论 -
kafka 集群管理-创建一个topic流程
TopicCommand.createTopic def createTopic(zkUtils: ZkUtils, opts: TopicCommandOptions) { .... try { if (opts.options.has(opts.replicaAssignmentOpt)) { //获取到的分配的方案 /** * topic: * p0: * p0原创 2021-03-22 22:32:18 · 598 阅读 · 0 评论 -
kafka 集群管理-如何感知新注册进来的broker
KafkaController.onControllerFailover//通过这儿注册了一个监听器,感知到集群里面有新的broker进来了。replicaStateMachine.registerListeners() -> registerBrokerChangeListener // 对/brokers/ids 目录设置了监听器 zkUtils.zkClient.subscribeChildChanges(ZkUtils.BrokerIdsPath, brokerChan原创 2021-03-22 22:09:51 · 333 阅读 · 0 评论 -
kafka 集群管理-broker注册
KafkaServer.startup()kafkaHealthcheck.startup() -> register() //往zk的某个目录里面写入进去一个注册信息(最重要的注册信息,就是自己的brokerid) zkUtils.registerBrokerInZk(brokerId, plaintextEndpoint.host, plaintextEndpoint.port, updatedEndpoints, jmxPort, rack, interBroke原创 2021-03-22 21:47:49 · 447 阅读 · 0 评论 -
kafka 集群管理-controller是如何选举的
KafkaServer.startup()kafkaController.startup()controllerElector.startup -> elect def elect: Boolean = { val timestamp = SystemTime.milliseconds.toString //构建一个数据信息 //比如有version //有自己broker id号 //有时间戳 val electString = Json.en原创 2021-03-22 21:26:59 · 246 阅读 · 0 评论 -
kafka 副本同步-如果follower fetch不到数据怎么办
1、follower发送fetch请求到leader,leader无数据更新时,加入时间轮(100ms)延迟调度 给follower发送空响应 (节约网络资源)2、leader有数据更新时,会唤醒 时间轮马上执行给follower发送空响应follower接收到空响应后会继续向leader 发送fetch请求KafkaApi.handle case ApiKeys.FETCH => handleFetchRequest(request)replicaManager.fetchMessages原创 2021-03-22 21:02:35 · 453 阅读 · 0 评论 -
kafka 副本同步-ISR定时检查线程
KafkaServer.startup -> replicaManager.startup()定时调度的线程 scheduler.schedule("isr-expiration", maybeShrinkIsr, period = config.replicaLagTimeMaxMs, unit = TimeUnit.MILLISECONDS) -> partition.maybeShrinkIsr private def tryCompleteDelayedReques原创 2021-03-22 20:38:54 · 466 阅读 · 1 评论 -
kafka 副本同步-leader和follower的leo,hw更新流程
1、流程图2、源码详解Leader端:KafkaApi.handleProducerRequest replicaManager.appendMessages-> appendToLocalLog // 把数据写到leader partition里面-> partition.appendMessagesToLeader-> log.append -> segment.append(把数据写入到segment里面去) 2. 更新自己的LEO -> up原创 2021-03-21 23:58:29 · 545 阅读 · 0 评论 -
kafka 副本同步-Leader处理fetch请求
KafkaApi.handleFetchRequest//拉取数据 replicaManager.fetchMessages // 从本地的磁盘里面去读取日志信息 val logReadResults = readFromLocalLog def readFromLocalLog(fetchOnlyFromLeader: Boolean, readOnlyCommitted: Boolean,原创 2021-03-21 21:34:52 · 465 阅读 · 0 评论 -
kafka 副本同步-ReplicaFetcher
KafkaServer.startupreplicaManager = new ReplicaManager//follower partition是如何拉取leader partition的数据的? val replicaFetcherManager = new ReplicaFetcherManager ... replicaFetcherManager.addFetcherForPartitions def addFetcherForPartitions(partitionAndO原创 2021-03-21 16:41:58 · 447 阅读 · 0 评论 -
kafka 存储-Log append
步骤一:校验数据 (Producer -》 Kafka)步骤二: 分配offset步骤三:获取合法的数据步骤四:获取一个可用的segment步骤五:把数据写入到segment里面去步骤六:更新LEO步骤七:根据条件判断,然后把内存里面的数据写到磁盘Partition.appendMessagesToLeader log.append() def append(messages: ByteBufferMessageSet, assignOffsets: Boolean = true): Lo原创 2021-03-21 14:59:56 · 596 阅读 · 0 评论 -
kafka 存储-LogManager
KafkaServer.startup() //TODO 初始化logManager logManager = createLogManager(zkUtils.zkClient, brokerState) //TODO 启动logManager logManager.startup()-> createLogManager -> new LogManager(){createAndValidateLogDirs(logDir原创 2021-03-21 13:16:33 · 175 阅读 · 0 评论 -
kafka 存储-replicamanager写数据
入口:处理生产者写入数据请求 KafkaApi.handleProducerRequest -> replicaManager.appendMessages() def appendMessages(timeout: Long, requiredAcks: Short, internalTopicsAllowed: Boolean, messagesPerPartiti原创 2021-03-21 12:48:16 · 172 阅读 · 0 评论 -
kafka 存储原理
原创 2021-03-21 11:20:17 · 143 阅读 · 0 评论 -
kafka 服务端-网络-服务端处理Request和发送响应给客户端
接上篇处理请求KafkaServer.startuprequestHandlerPool = new KafkaRequestHandlerPool(config.brokerId, socketServer.requestChannel, apis, config.numIoThreads) //默认启动8个线程,一般情况下,生产环境里面我们是要去设置这个参数。 for(i <- 0 until numThreads) { //创建线程 runnables(i) = n原创 2021-03-21 10:24:53 · 418 阅读 · 0 评论 -
kafka 服务端-网络-processor如何接收和处理请求
Processor.run() override def run() { startupComplete() while (isRunning) { try { // setup any new connections that have been queued up //读取每个SocketChannel,把每个SocketChannel //都往Selector上面注册OP_READ事件。 configure原创 2021-03-21 00:47:36 · 539 阅读 · 0 评论 -
kafka 服务端-网络-processor 线程如何启动
创建SocketServer.startup(){ //创建了三个Processor的线程 for (i <- processorBeginIndex until processorEndIndex) //TODO -> 说明这个里面会创建3个线程 //默认是3个线程,但是我们一般 搭建kafka集群的时候会去配置这个参数num.network.threads processors(i) = newPr原创 2021-03-20 22:20:48 · 377 阅读 · 0 评论 -
kafka 服务端 Accept线程如何启动
Core Kafkamain kafkaServerStartable.startup -> server.startup(){ // -> NIO的服务端 socketServer = new SocketServer(config, metrics, kafkaMetricsTime) // TODO socketServer.startup()} def startup() { this.synchroniz原创 2021-03-20 21:48:15 · 192 阅读 · 0 评论 -
kafka producer 异常处理
1 重试Sender.completeBatchif (error != Errors.NONE && canRetry(batch, error)) { // retry log.warn("Got error produce response with correlation id {} on topic-partition {}, retrying ({} attempts left). Error: {}",原创 2021-03-20 21:07:25 · 1636 阅读 · 0 评论 -
如何处理响应
Selector.pollSelectionKeysif (channel.ready() && key.isReadable() && !hasStagedReceive(channel)) { NetworkReceive networkReceive; //接受服务端发送回来的响应(请求) //networkReceive 代表的就是一个服务端发送原创 2021-03-20 20:29:12 · 325 阅读 · 0 评论 -
kafka Sender 发送网络请求
建立好连接 是的逻辑注册OPWRITESender.run -> /** * 步骤七: * 创建发送消息的请求 * * 创建请求 * 我们往partition上面去发送消息的时候,有一些partition他们在同一台服务器上面 * ,如果我们一分区一个分区的发送我们网络请求,那网络请求就会有一些频繁 * 我们要知道,我们集群里面网络资源是非常珍贵的。原创 2021-03-20 09:54:16 · 161 阅读 · 0 评论 -
kafka sender的NetWorkClient与broker建立连接
初始化Sender.run -> NetWorkClient.ready -> initiateConnect-> selector.connect public void connect(String id, InetSocketAddress address, int sendBufferSize, int receiveBufferSize) throws IOException { if (this.channels.containsKey(id)).原创 2021-03-20 09:20:39 · 305 阅读 · 0 评论 -
kafka 网络设计
Sender.run -> client.ready -> initiateConnect -> selector.connect/* TODO 这个selector是kafka主机封装的一个selector * 他是基于java NIO里面的selector去封装的。 */public class Selector implements Selectable { public static final long NO_IDLE_TIMEOUT_MS = -1; .原创 2021-03-18 19:42:18 · 261 阅读 · 0 评论 -
producer sender 检查与要发送数据的主机的网络是否已经建立好
if (!this.client.ready(node, now)) {-> NetworkClient.ready public boolean ready(Node node, long now) { //如果当前检查的节点为null,就报异常。 if (node.isEmpty()) throw new IllegalArgumentException("Cannot connect to empty node " + node.原创 2021-03-17 00:07:51 · 131 阅读 · 0 评论 -
Sender发送条件
发送条件:1)full: 如果一个批次写满了(无论时间有没有到)2)expired:时间到了(批次没写满也得发送)3)exhausted:内存不够(消息发送出去以后,就会释放内存)4)closed : kafka producer 关闭前先将缓存的数据发送this.accumulator.ready public ReadyCheckResult ready(Cluster cluster, long nowMs) { Set<Node> readyNode原创 2021-03-16 23:47:06 · 194 阅读 · 0 评论 -
kafka sender
步骤一: 获取元数据步骤二: 判断哪些partition有消息可以发送步骤三:标识还没有拉取到元数据的topic步骤四:检查与要发送数据的主机的网络是否已经建立好。步骤五:按照broker进行分组,同一个broker的partition为同一组,一个批次就一个请求 -> broker,减少网络传输到次数Map<Integer, List> batches步骤六:对超时的批次是如何处理的?步骤七:创建发送消息的请求步骤八: 真正执行网络操作的都是这个NetWorkClien原创 2021-03-16 23:25:23 · 192 阅读 · 0 评论 -
kafka producer BufferPool
allocate如果我们这次申请的批次的大小等于 我们设定好的一个批次的大小,并且我们的内存池不为空,那么直接从内存池里面获取一个块内存就可以使用了。还有一种情况就是,我们整个内存池 还剩10k的内存,但是我们这次申请的内存是32k,批次可能就是16k,但是我们的一条消息,就是32K -> max(16,32) = 当前批次 = 32K可能一下子分配不了这么大的内存,但是可以先有点分配一点。如果分配的内存的大小 还是没有要申请的内存大小大。内存池就会一直分配的内存,一点一点的去分配。等着别.原创 2021-03-16 22:35:34 · 238 阅读 · 0 评论 -
RecordAccumulator (一) getOrCreateDeque
private Deque<RecordBatch> getOrCreateDeque(TopicPartition tp) { /** * CopyonWriteMap: * get * put * */ //直接从batches里面获取当前分区对应的存储队列 Deque<RecordBatch> d = this....原创 2021-03-16 21:11:57 · 145 阅读 · 0 评论 -
kafka producer RecordAccumulator初探
步骤一:先根据分区找到应该插入到哪个队列里面。如果有已经存在的队列,那么我们就使用存在队列,如果队列不存在,那么我们新创建一个队列步骤二:尝试往队列里面的批次里添加数据步骤三:计算一个批次的大小步骤四:根据批次的大小去分配内存步骤五:尝试把数据写入到批次里面。步骤六:根据内存大小封装批次步骤七:把这个批次放入到这个队列的队尾 /** * 步骤七: * 把消息放入accumulator(32M的一个内存) .原创 2021-03-16 20:04:43 · 204 阅读 · 0 评论 -
kafka producer 分区器
策略一: 如果发送消息的时候,没有指定key, 轮询达到负载均衡//策略二:这个地方就是指定了key, hash取模,相同的key打到同一个分区上int partition = partition(record, serializedKey, serializedValue, cluster);-> return partition != null ? partition : //使用分区器进行选择合适的分区原创 2021-03-15 23:53:46 · 291 阅读 · 2 评论 -
kafka producer 拉取元数据
/** * 步骤一: * 同步等待拉取元数据。 * maxBlockTimeMs 最多能等待多久。 */ClusterAndWaitTime clusterAndWaitTime = waitOnMetadata(record.topic(), record.partition(), maxBlockTimeMs); ... /** * 很明显,真正去获取元数据是这个线程完成。 */ waitOnMetadata.sender.wakeup(); ->.原创 2021-03-15 22:30:50 · 612 阅读 · 0 评论 -
kafka producer 核心流程
producer.send(new ProducerRecord<>(topic,-> doSend private Future<RecordMetadata> doSend(ProducerRecord<K, V> record, Callback callback) { TopicPartition tp = null; try { /** * 步骤一:原创 2021-03-15 21:17:32 · 141 阅读 · 0 评论 -
Kafka 元数据管理
1、MetaData: //两个更新元数据的请求的最小的时间间隔,默认值是100ms //目的就是减少网络的压力 private final long refreshBackoffMs; //多久自动更新一次元数据,默认值是5分钟更新一次。 private final long metadataExpireMs; //对于producer端来讲,元数据是有版本号 //每次更新元数据,都会修改一下这个版本号。 private int ver原创 2021-03-15 20:39:30 · 497 阅读 · 0 评论 -
kafka producer 初始化
1、设置分区器2、设置序列化器3、设置拦截器4、创建集群Metadata,并定时更新5、设置压缩格式6、创建RecordAccumulator7、创建NetworkClient8、创建Sender线程并启动producer = new KafkaProducer<>(props);-> //1、设置分区器 this.partitioner = config.getConfiguredInstance(ProducerConfig.PARTITIONER_CLASS_原创 2021-03-15 20:12:23 · 645 阅读 · 0 评论 -
kafka producer 源码分析
1、总体概叙原创 2021-03-14 13:04:52 · 127 阅读 · 0 评论 -
kafka 深入浅出
kafka 零拷贝consumer group coondinator机制coondinator如何选择的? broker里面的其中一台服务器。consumer group:group. id: my_conumser -> my consumer hash -> 求出来就是—个数字数字/50 =>获取到 0-49的这样的一个数。比如数就是8,然后就在找到 __consumer_offets的partition 8 的leader partition在哪台服务器上面。那台就原创 2021-03-19 10:48:52 · 320 阅读 · 0 评论