大连微信网站建设wordpress博客源码下载
大连微信网站建设,wordpress博客源码下载,石家庄seo推广,.net如何做直播网站今天我们就来安排一篇关于 Kafka 的核心面试题连环炮, 从「基础知识」、「进阶提升」、「架构调优」 三个方向梳理面试题#xff0c;希望在金三银四的关键节点可以帮助到大家。
由于内容很多#xff0c;打算拆分成「上中下」三篇#xff0c;本文是面试系列的下篇。
这篇文…今天我们就来安排一篇关于 Kafka 的核心面试题连环炮, 从「基础知识」、「进阶提升」、「架构调优」 三个方向梳理面试题希望在金三银四的关键节点可以帮助到大家。由于内容很多打算拆分成「上中下」三篇本文是面试系列的下篇。这篇文章干货很多希望你可以耐心读完。03 Kafka 架构调优5问了解Kafka超高并发网络架构是如何设计吗?我们知道 Kafka 网络通信架构使用到了 Java NIO 以及 Reactor 设计模式。我们先从整体上看一下完整的网络通信层架构如下图所示1从上图中我们可以看出Kafka 网络通信架构中用到的组件主要由两大部分构成SocketServer 和 RequestHandlerPool。2SocketServer 组件是 Kafka 超高并发网络通信层中最重要的子模块。它包含 Acceptor 线程、Processor 线程和 RequestChannel 等对象都是网络通信的重要组成部分。3RequestHandlerPool 组件就是我们常说的 I/O 工作线程池里面定义了若干个 I/O 线程主要用来执行真实的请求处理逻辑。01Accept 线程在经典的 Reactor 设计模式有个「Dispatcher」的角色主要用来接收外部请求并分发给下面的实际处理线程。在 Kafka 网络架构设计中这个 Dispatcher 就是「Acceptor 线程」, 用来接收和创建外部 TCP 连接的线程。在 Broker 端每个 SocketServer 实例只会创建一个 Acceptor 线程。它的主要功能就是创建连接并将接收到的 Request 请求传递给下游的 Processor 线程处理。1我们可以看出 Acceptor 线程主要使用了 Java NIO 的 Selector 以及 SocketChannel 的方式循环的轮询准备就绪的 I/O 事件。2将 ServerSocketChannel 通道注册到nioSelector 上并关注网络连接创事件SelectionKey.OP_ACCEPT。3事件注册好后一旦后续接收到连接请求后Acceptor 线程就会指定一个 Processor 线程并将该请求交给它并创建网络连接用于后续处理。02Processor 线程Acceptor 只是做了请求入口连接处理的那么真正创建网络连接以及分发网络请求是由 Processor 线程来完成的。而每个 Processor 线程在创建时都会创建 3 个队列。1newConnections 队列:它主要是用来保存要创建的新连接信息也就是SocketChannel 对象目前是硬编码队列长度大小为20。每当 Processor 线程接收到新的连接请求时都会将对应的 SocketChannel 对象放入队列等到后面创建连接时从该队列中获取 SocketChannel然后注册新的连接。2inflightResponse 队列它是一个临时的 Response 队列当 Processor 线程将 Repsonse 返回给 Client 之后要将 Response 放入该队列。它存在的意义由于有些 Response 回调逻辑要在 Response 被发送回 Request 发送方后才能执行因此需要暂存到临时队列。3ResponseQueue 队列它主要是存放需要返回给Request 发送方的所有 Response 对象。每个 Processor 线程都会维护自己的 Response 队列。03RequestHandlerPool 线程池Acceptor 线程和 Processor 线程只是请求和响应的「搬运工」而「真正处理 Kafka 请求」是 KafkaRequestHandlerPool 线程池在上面网络超高并发通信架构图有两个参数跟整个流程有关系分别是「num.network.threads」、「num.io.threads」。其中 num.io.threads 就是 I/O 工作线程池的大小配置。下面我们结合 Kafka 超高并发网络架构图来讲解下一个完整请求处理核心流程1Clients 发送请求给 Acceptor 线程。2Acceptor 线程会创建 NIO Selector 对象并创建 ServerSocketChannel 通道实例然后将 Channel 和 OP_ACCEPT 事件绑定到 Selector 多路复用器上。3Acceptor 线程默认创建3个Processor 线程参数num.network.threads, 并轮询的将请求对象 SocketChannel 放入到连接队列中。4这时候连接队列就源源不断有请求数据了然后不停地执行 NIO Poll, 获取对应 SocketChannel 上已经准备就绪的 I/O 事件。5Processor 线程向 SocketChannel 注册了 OP_READ/OP_WRITE 事件这样 客户端发过来的请求就会被该 SocketChannel 对象获取到具体就是 processCompleteReceives 方法。6这个时候客户端就可以源源不断进行请求发送了服务端通过 Selector NIO Poll 不停的获取准备就绪的 I/O 事件。7然后根据Channel中获取已经完成的 Receive 对象构建 Request 对象并将其存入到 Requestchannel 的 RequestQueue 请求队列中 。8这个时候就该 I/O 线程池上场了KafkaRequestHandler 线程循环地从请求队列RequestQueue 中获取 Request 实例然后交由KafkaApis 的 handle 方法执行真正的请求处理逻辑并最终将数据存储到磁盘中。9待处理完请求后KafkaRequestHandler 线程会将 Response 对象放入 Processor 线程的 Response 队列。10然后 Processor 线程通过 Request 中的 ProcessorID 不停地从 Response 队列中来定位并取出 Response 对象返还给 Request 发送方。了解Kafka高吞吐日志存储架构是如何设计吗?对于 Kafka 来说 它主要用来处理海量数据流这个场景的特点主要包括1)写操作写并发要求非常高基本得达到百万级 TPS顺序追加写日志即可无需考虑更新操作。2读操作相对写操作来说比较简单只要能按照一定规则高效查询即可,支持offset或者时间戳读取。根据上面两点分析对于写操作来说直接采用「顺序追加写日志」的方式就可以满足 Kafka 对于百万TPS写入效率要求。如何解决高效查询这些日志呢我们可以设想把消息的 Offset 设计成一个有序的字段这样消息在日志文件中也就有序存放了也不需要额外引入哈希表结构可以直接将消息划分成若干个块对于每个块我们只需要索引当前块的第一条消息的 Offset 这个是不是有点二分查找算法的意思。即先根据 Offset 大小找到对应的块 然后再从块中顺序查找。如下图所示这样就可以快速定位到要查找的消息的位置了在 Kafka 中我们将这种索引结构叫做「稀疏哈希索引」。上面得出了 Kafka 最终的存储实现方案 即基于顺序追加写日志 稀疏哈希索引。接下来我们来看看 Kafka 日志存储结构从上图看出来Kafka 是基于「主题 分区 副本 分段 索引」的结构进行日志存储的。了解了整体的日志存储架构我们来看下 Kafka 日志格式Kafka 日志格式也经历了多个版本迭代这里我们主要看下V2版本的日志格式通过上图可以得出V2 版本日志格式主要是通过可变长度提高了消息格式的空间使用率并将某些字段抽取到消息批次RecordBatch中同时消息批次可以存放多条消息从而在批量发送消息时可以大幅度地节省了磁盘空间。接下来我们来看看日志消息写入磁盘的整体过程如下图所示针对 Kafka 线上集群部署方案, 你是怎么做的这里我们从架构师必备能力出发 以电商平台为例讲述了 Kafka 生产级容量评估方案该如何做如何让公司领导以及运维部门得到认可 获准你的方案。详细可以深读八大步骤带你深度剖析Kafka生产级容量评估方案针对 Kafka 线上系统, 你是如何进行监控的?Kafka 作为大型系统架构中重要的一环有着举足轻重的作用因此 Kafka 集群的稳定性尤为重要我们要对生产的 Kafka 集群进行全方位的监控 一般线上系统可以从以下五个维度进行监控01主机节点监控所谓主机节点监控就是监控 Kafka 集群 Broker 所在节点机器的性能。主机节点监控对于 Kafka 来说是最重要的因为很多线上环境问题首先就是由于主机的某些性能出现了问题。因此对于 Kafka 来说主机监控通常是发现问题的第一步主要性能指标如下「机器负载Load」、「CPU 使用率」、「内存使用率」、「磁盘 I/O 使用率」、「网络 I/O 使用率」、「TCP 连接数」、「打开文件数」、「inode 使用情况」。如果想要更好的监控主机性能的话有以下两个教程可以学习和参考02JVM 监控另一个重要的监控维度就是 JVM 监控。监控 JVM 进程主要是为了让你全面地了解Kafka Broker 进程。要监控 JVM 进程需要关注 3 个指标「监控Full GC 发生频率和时长」、「监控堆上活跃对象大小」、「监控应用线程总数」03Kafka 集群监控另外一个重要监控维度就是 Kafka Broker 集群和各类客户端的监控主要有3个方法1查看 Broker 端重要日志主要包括 Broker 端服务器日志 server.log控制器日志 controller.log 以及主题分区状态变更日志 state-change.log。其中server.log 是最重要的如果你的 Kafka 集群出现了故障你要第一时间查看 server.log定位故障原因。2查看 Broker 端关键线程运行状态例如:Log Compaction 线程日志压缩清理。一旦它挂掉了所有 Compaction 操作都会中断但用户对此通常是无感知的。副本拉取消息的线程主要执行 Follower 副本向 Leader 副本拉取消息的逻辑。如果它们挂掉了系统会表现为 Follower 副本延迟 Leader 副本越来越大 。3查看 Broker 端关键的 JMX 性能指标:主要有BytesIn/BytesOut、NetworkProcessorAvgIdlePercent、RequestHandlerAvgIdlePercent、UnderReplicatedPartitions、ISRShrink/ISRExpand、ActiveControllerCount 这几个指标 。04Kafka 客户端监控客户端监控主要是生产者和消费者的监控生产者往 Kafka 发送消息此时我们要了解客户端机器与 Broker 机器之间的往返时延 RTT 是多少对于跨数据中心或者异地集群来说RTT 会更大很难支撑很大的 TPS。Producer角度:request-latency 是需要重点关注的JMX指标即消息生产请求的延时另外 Sender 线程的运行状态也是非常重要的 如果 Sender 线程挂了对于用户是无感知的表象只是 Producer 端消息发送失败。Consumer角度:对于 Consumer Group需要重点关注 join rate 和 sync rate 指标它表示 Rebalance 的频繁程度。另外还包括消息消费偏移量、消息堆积数量等。05Broker 之间的监控最后一个监控维度就是 Broker 之间的监控主要指副本拉取的性能。Follower 副本实时拉取 Leader 副本的数据此时我们希望拉取过程越快越好。Kafka 提供了一个特别重要的 JMX 指标叫做「under replicated partitions」意思就是比如我们规定这条消息应该在两个 Broker 上面保存假设只有一个 Broker 上保存该消息那么这条消息所在的分区就叫 under replicated partitions这种情况是特别关注的因为有可能造成数据的丢失。另外还有一个比较重要的指标是「active controllor count」。在整个 Kafka 集群中应该确保只能有一台机器的指标是1其他全应该是0如果发现有一台机器大于1一定是出现脑裂了此时应该去检查下是否出现了网络分区。Kafka本身是不能对抗脑裂的完全依靠 Zookeeper 来做但是如果真正出现网络分区的话也是没有办法处理的应该让其快速失败重启。针对 Kafka 线上系统, 你是如何进行调优的?对 Kafka 来说「吞吐量」和「延时」是非常重要的优化指标。吞吐量 TPS是指 Broker 端或 Client 端每秒能处理的消息数越大越好。延时表示从 Producer 端发送消息到 Broker 端持久化完成到 Consumer 端成功消费之间的时间间隔。与吞吐量 TPS 相反延时越短越好。总之高吞吐量、低延时是我们调优 Kafka 集群的主要目标。01提升吞吐量首先是提升吞吐量参数和措施Brokernum.replica.fetchers表示 Follower 副本用多少个线程来拉取消息默认1个线程。如果 Broker 端 CPU 资源很充足适当增加该值「但不要超过CPU核数」以加快 Follower 副本的同步速度。这是因为在生产环境中配置了 acksall 的 Producer 端影响吞吐量的首要因素就是副本同步性能。适当增加该值后通常可以看到 Producer 端吞吐量增加replica.lag.time.max.ms在 ISR 中如果 Follower 长时间未向 Leader 发送通信请求或同步数据则该 Follower 将被踢出 ISR该值默认为 30s。num.network.threads单个Acceptor创建Processor处理器的线程个数默认值为3 可以适当提高该值为9。num.io.threads服务器用于处理请求的线程数可能包括磁盘 I/O默认值是 8可以适当提高该值为32。调优参数以避免频繁性的 Full GCProducerbatch.size表示消息批次大小默认是 16kb。如果 batch 设置太小会导致频繁网络请求吞吐量下降如果 batch 设置太大会导致一条消息需要等待很久才能被发送出去增加网络延时。所以适当增加会提高吞吐量建议从默认的16kb增加到512kb或者1M。buffer.memoryRecordAccumulator 发送消息的缓冲区总大小默认值是 32M可以增加到 64M。linger.ms表示批次缓存时间如果数据迟迟未达到 batch.sizesender 等待 linger.ms 之后就会发送数据。单位 ms默认值是 0意思就是消息必须立即被发送。如果设置的太短会导致频繁网络请求吞吐量下降如果设置的太长会导致一条消息需要等待很久才能被发送出去增加网络延时。所以适当增加会提高吞吐量建议10~100毫秒。compression.type默认是 none不压缩但是也可以使用 lz4 压缩效率还是不错的压缩之后可以减小数据量提升吞吐量但是会加大 producer 端的 CPU 开销。支持压缩类型none、gzip、snappy、lz4 和 zstd。设置acks0/1retries0优化目标是吞吐量不要设置 acksall「副本同步时间拉长」 及开启重试 「执行时间拉长」。Consumer利用多线程增加整体吞吐量fetch.min.bytes表示只要 Broker 端积攒了多少数据就可以返回给 Consumer 端。默认值1字节适当增大该值为1kb或者更大。fetch.max.bytes消费者获取服务器端一批消息最大的字节数。一批次的大小受 message.max.bytes 【broker 配置】或 max.message.bytes 【topic config】影响默认是50M。max.poll.records表示一次 poll 拉取数据返回消息的最大条数大小默认是 500 条。分区增加分区来提高吞吐量02降低延时降低延时的目的就是尽量减少端到端的延时。对比上面提升吞吐量的参数我们只能调整 Producer 端和 Consumer 端的参数配置。对于 Producer 端此时我们希望可以快速的将消息发送出去必须设置 linger.ms0同时关闭压缩另外设置 acks 1减少副本同步时间。而对于 Consumer 端我们只保持 fetch.min.bytes1 即 Broker 端只要有能返回的数据就立即返回给 Consumer减少延时。03合理设置分区数分区数不是越多越好也不是越少越好需要搭建完集群进行压测再灵活调整分区个数。这里可以用 Kafka 官方自带的脚本对 Kafka 进行压测。1生产者压测kafka-producer-perf-test.sh2消费者压测kafka-consumer-perf-test.sh