Kafka能抗住百万并发的秘密...

kafka 如何动态设置并发 kafka 并发 springboot setConcurrency 决定kafka 并发,kafka 的分区决定了并发上限 ,concurrency<=分区数 ,如果大于分区数并发会等于分区 每个分区都是一个有序的、不可变的记录序列,这些记录不断附加到结构化提交日志。分区中的记录被分配给一个顺序 ID 号,称为唯一标识分区内每个记录的偏移量。 KafkaBootstrapConfiguration @SuppressWarnings(“rawtypes”) @Bean(name = KafkaLis 阅读详情

这篇文章干货很多,希望你可以耐心读完。

01 总体概述

要想理解 Kafka Broker 请求处理架构设计,我们需要从简单请求处理模型来说起。

对于日常系统开发,我们都知道是基于 Request/Response 的模式来实现的, 对于 Kafka 来说, 无论是 Producer 端、Consumer 端 还是 Broker 端,他们之间的请求交互也都是基于「 Request/Response 」模式来完成的。比如,客户端会通过网络发送消息生产请求给 Broker,而 Broker 处理完成后,会发送对应的响应给到客户端。

下面,我会从自我设计角度出发,如果是我们会如何设计,带你一步步演化出来「 kafka Broker 的网络请求处理 」架构。

在这个过程中,你会看到 Kafka 在处理请求的过程中会遇到哪些高性能和高并发问题,以及架构为什么要这样演进,从而理解 Kafka 这么设计的意义和精妙之处。

02 顺序处理模式

我们从最简单的网络编程思路处理方式讲起。

因为对于 Kafka Broker 来说就是用来接收生产者发送过来的请求,那这个时候最简单的实现大概是这样的:

如上述代码所示:我们可以理解 Kafka 每个服务器启动起来后就是一个 while 循环, 不断的 accept 生产者提交上来的请求, 然后进行处理并存储到磁盘上,这种方式实现最简单,也非常好理解,但是这种方式存在2个致命的缺陷?

  1. 请求阻塞:只能顺序处理每个请求,即每个请求都必须等待前一个请求处理完毕才能得到处理。

  2. 吞吐量非常差:由于只能顺序处理,无法并发,效率太低,所以吞吐量非常差,只适合请求发送非常不频繁的系统。

从上面来看很明显,如果你的 Kafka 系统请求并发量很大,意味着要处理的时间就会越久。那按照前面我们提到的 Kafka「 吞吐量 」的标准,这个方案远远无法满足我们对高性能、高并发的要求。

那有什么更好的方案可以快速处理请求吗?

接下来我们可以试着采取这个方案: 独立线程异步处理模式 。

03 多线程异步处理模式

既然同步方式会阻塞请求,吞吐量差, 我们可以尝试着使用独立线程异步方式进行处理, 即经典的 connection per thread 模型, 那这个时候的实现大概是这样的:

如上述代码所示:同上还是一个 while 循环不断的 accept 生产者提交上来的请求,但是这时候 Kafka 系统会为每个请求都创建一个「 单独的线程 」来处理。

这个实现方案的好处就是:

  1. 吞吐量稍强:相对上面同步方式的方案,一定程度上极大地提高了服务器的吞吐量。

  2. 非阻塞:它是完全异步的,每个请求的处理都不会阻塞下一个请求。

但同样缺陷也同样很明显: 即为每个请求都创建线程的做法开销很大 ,在某些高并发场景下会压垮整个服务。可见,这个方案也只适用于请求发送频率很低的业务场景。还是无法满足我们对高性能、高并发的要求。

既然这种方案还是不能满足, 那么我们究竟该使用什么方案来支撑高并发呢?

这个时候我们可以想想我们日常开发用到的7层负载Nginx或者Redis在处理高并发请求的时候是使用什么方案呢?

从上面启发你可以看出,提升系统 I/O 并发性能的关键思路就是:「 事件驱动 」。

想必大家已经猜到了,没错,就是「 多路复用 」。那么Kafka 是不是也是采用这种方案来实现呢?

这里我们先考虑采用基于「 事件驱动 」的设计方案,当有事件触发时,才会调用处理器进行数据处理。

04 Reactor 模式

在高性能网络编程领域,有一个非常著名的模式——Reactor模式。那么何为「 Reactor模式 」,首先它是基于事件驱动的,有一个或多个并发输入源,有一个Service Handler,有多个Request Handler;这个Service Handler会同步的将输入的请求轮询地分发给相应的Request Handler进行处理。

借助于 Doug Lea(就是那位让人无限景仰的大爷)的 "Scalable IO in Java" 中讲述的Reactor模式。

"Scalable IO in Java" 的地址是:

http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

简单来说, Reactor 模式特别适合应用于处理多个客户端并发向服务器端发送请求的场景 。这里借用大神 PDF 中的一幅图来说明 Reactor 架构:

从上面这张图中,我们可以看出多个客户端会发送请求给到 Reactor。Reactor 有个请求分发线程 Dispatcher,也就是图中的绿色的 Acceptor,它会将不同的请求下分发到多个工作线程中处理。

在这个架构中,Acceptor 线程只是用来进行请求分发,所以非常轻量级,因此会有很高的吞吐量。而这些工作线程可以根据实际系统负载情况动态调节系统负载能力,从而达到请求处理的平衡性。

基于上面的 Reactor 架构, 我们来看看如果是我们该如何设计 Kafka 服务端的架构?

  1. 这里我们采用多路复用方案,Reactor 设计模式,并引用 Java NIO 的方式可以更好的解决上面并发请求问题。

  2. 当 Client 端将请求发送到 Server 端的时候, 首先在 Server 端有个多路复用器( Selector ),然后会启动一个 Accepter 线程将 OP_CONNECT 事件注册到多路复用器上, 主要用来监听连接事件到来。

  3. 当监听到连接事件后,就会在多路复用器上注册 OP_READ 事件, 这样 Cient 端发送过来的请求, 都会被接收到。如果请求特别多的话, 我们这里进行优化, 创建一个 Read HandlePool 线程池 。

  4. 当 Read HandlePool 线程池接收到请求数据后,最终会交给 Handler ThreadPool 线程池进行后续处理。比如如果是生产者发送过来的请求,肯定会解析请求体,处理并最终存储到磁盘中,待处理完后要返回处理结果状态, 这时候就由它在多路复用器上注册 OP_WRITE 事件来完成。这样多路复用器遍历到 OP_WRITE 事件后就会将请求返回到 Client 端。

  5. 在上图中我们看到在整个流程中还有一个 MessageQueue 的队列组件存在, 为什么要加这个组件呢?我们可以想象一下, 如果请求量非常大,直接交给 Handler ThreadPool 线程池进行处理, 可能会出现该线程池处理不过来的情况发生,如果处理不过来,也会出现阻塞瓶颈。所以这里我们在 Server 端内部也设计一个消息队列, 起到一个缓冲的作用,Handler ThreadPool 线程池会根据自己的负载能力进行处理。

以上就是我们引用了「 多路复用 」的设计方案,但是 Kafka Broker 端就是这样的架构设计方案吗?如果我们是 Kafka 系统架构的设计者,采用这样的架构设计方案会不会还是有什么问题,有没有哪个环节会出现系统性能瓶颈呢?

这是个值得思考的问题, 很考验你的架构设计能力。

细心的读者可能会发现:对于 Kafka 这种超高并发系统来说,一个 Selector 多路复用器是 Hold 不住的,从上图可以得出,我们监听这些连接、接收请求、处理响应结果都是同一个 Selector 在进行处理,很容易成为系统性能瓶颈。

接下来,我们将进一步进行优化,为了减轻当前 Selector 的处理负担,引入另外一个Selector 处理队列,如下图所示:

  1. 首先上图是目前我认为最接近 Kafka Broker 真实架构设计方案的。

  2. 整体架构跟上一版的类似,只不过这里多引入了一个多 Selector 处理队列,原来的 Selector 只负责监听连接, 这时候有读者就会有疑问,请求量超级大的时候,一个 Selector 会不会成为瓶颈呢?这里可以大可放心, 这时候它的工作非常单一,是完全能 hold 住的。

  3. 那么对于我们接收请求、处理请求、返回状态操作都会交由多 Selector 处理队列,至于这里到底需要多少个 Selector,又会跟什么参数和配置有关系,我们后续再进行分析,总之这里记住有多个 Selector 就行了,这样系统压力就会被分散处理。

  4. 另外我们要搞清楚的一点就是对于 Kafka 服务端指的是每个 Broker 节点,如果我们的服务集群总共有10个节点, 每个节点内部都是上面的这样的架构,这样我们就有理由相信如果采用这样的架构设计方案,是可以支持高并发和高性能的。

架构设计方案演进到这里,基本上已经差不多了, 接下来我们看看 Kafka 真实超高并发的网络架构是如何设计的 。

05 Kafka 超高并发网络架构

在上面 Kafka 高性能、高吞吐量架构演进的时候,我们提到了 Java NIO 以及 Reactor 设计模式。实际上,搞透了「 Kafka 究竟是怎么使用 NIO 来实现网络通信的 」,不仅能让我们掌握 Kafka 请求处理全流程处理,也能让我们对 Reactor 设计模式有更深的理解,还能帮助我们解决很多实际问题。

那么接下来我们就来深入剖析下 Kafka 的 NIO 通讯机制吧。

我们先从整体上看一下完整的网络通信层架构,如下图所示:

正在上传…重新上传取消

  1. 从上图中我们可以看出,Kafka 网络通信架构中用到的组件主要由两大部分构成: SocketServer 和 RequestHandlerPool 。

  2. SocketServer 组件是 Kafka 超高并发网络通信层中最重要的子模块。它包含 Acceptor 线程、Processor 线程和 RequestChannel 等对象,都是网络通信的重要组成部分。它主要实现了 Reactor 设计模式,主要用来处理外部多个 Clients(这里的 Clients 可能包含 Producer、Consumer 或其他 Broker)的并发请求,并负责将处理结果封装进 Response 中,返还给 Clients。

  3. RequestHandlerPool 组件就是我们常说的 I/O 工作线程池,里面定义了若干个 I/O 线程, 主要用来执行真实的请求处理逻辑 。

  4. 这里注意的是:跟 RequestHandler 相比, 上面所说的Acceptor、Processor 线程 还有 RequestChannel 等都不做请求处理, 它们只是请求和响应的「搬运工」 。

接下来我们来具体聊聊SocketServer中的实现原理,这里先来讲讲:

  1. Acceptor 线程

  2. Processor 线程

以Kafka 2.5版本,源码位置:

https://github.com/apache/kafka/blob/2.5.0-rc3/core/src/main/scala/kafka/network/SocketServer.scala

05.1 聊聊 Acceptor 线程

在经典的 Reactor 设计模式有个 「Dispatcher」 的角色,主要用来接收外部请求并分发给下面的实际处理线程。通过上面分析我们知道在 Kafka 网络架构设计中,这个 Dispatcher 就是「 Acceptor 线程 」。

Acceptor 线程是用来接收和创建外部 TCP 连接的线程。在Broker 端每个 SocketServer 实例只会创建一个 Acceptor 线程。它的主要功能就是创建连接,并将接收到的 Request 请求传递给下游的 Processor 线程处理。

/**
 * Thread that accepts and configures new connections. There is one of these per endpoint.
 */
private[kafka] class Acceptor(val endPoint: EndPoint,
                              val sendBufferSize: Int,
                              val recvBufferSize: Int,
                              brokerId: Int,
                              connectionQuotas: ConnectionQuotas,
                              metricPrefix: String) extends AbstractServerThread(connectionQuotas) with KafkaMetricsGroup {
  // 1. 创建底层的NIO Selector对象,用来监听连接创建请求、读写请求等
  private val nioSelector = NSelector.open()
  // 2. Broker端创建对应的ServerSocketChannel实例,然后将Channel注册到Selector对象上
  val serverChannel = openServerSocket(endPoint.host, endPoint.port)
  // 3. 创建Processor线程池
  private val processors = new ArrayBuffer[Processor]()
  ......
  /**
   * Accept loop that checks for new connection attempts
   */
  def run(): Unit = {
    //注册OP_ACCEPT事件
    serverChannel.register(nioSelector, SelectionKey.OP_ACCEPT)
    // 等待Acceptor线程启动完成
    startupComplete()
    try {
      // 当前使用的Processor序号,从0开始
      var currentProcessorIndex = 0
      while (isRunning) {
        try {
          // 每500毫秒获取一次就绪I/O事件
          val ready = nioSelector.select(500)
          // 如果有I/O事件准备就绪
          if (ready > 0) {
           ........
                  // 调用accept方法创建Socket连接
                  accept(key).foreach { socketChannel =>
                  ........
                      // 指定由哪个Processor线程进行处理
                      processor = synchronized {
                        .........
                        processors(currentProcessorIndex)
                      }
                      // 更新Processor线程序号
                      currentProcessorIndex += 1
                    }        
      .........
    }
  }

这里重点看下 Acceptor 线程中三个非常关键且重要的属性和方法:

  1. nioSelector:它就是我们所熟悉的 Java NIO 库中的 Selector 对象实例,所有网络通信组件实现 Java NIO 机制的基础。

  2. processors:通过源码我们可以知道在Acceptor 线程在初始化时,需要创建对应的 Processor 线程池。由此可以得出,Processor 线程是在 Acceptor 线程中管理和维护的。

  3. run方法:它是处理 Reactor 模式中分发逻辑的主要实现方法。

  1. 从上述源码中,我们可以看出 Acceptor 线程主要使用了 Java NIO 的 Selector 以及 SocketChannel 的方式循环的轮询准备就绪的 I/O 事件。

  2. 这里的 I/O 事件主要是指网络连接创建事件即: SelectionKey.OP_ACCEPT 。

  3. 这样注册好事件后,一旦后续接收到连接请求后,Acceptor 线程就会指定一个 Processor 线程,并将该请求交给它并创建网络连接用于后续处理。

05.2 聊聊 Processor 线程

从上面分析我们知道 Acceptor 只是做了请求入口连接处理的,那么,真正创建网络连接以及分发网络请求是由 Processor 线程来完成的。

override def run(): Unit = {
    // 等待Processor线程启动完成
    startupComplete()
    try {
      while (isRunning) {
        try {
          // 创建新连接
          configureNewConnections()
          // 发送Response
          processNewResponses()
          // 执行NIO poll,获取对应SocketChannel上准备就绪的I/O操作
          poll()
          // 将接收到的Request放入Request队列
          processCompletedReceives()
          .......
        } catch {
          .........
        }
      }
    } finally {
      ........
    }
  }
  ........
  // 默认连接对接大小
  val ConnectionQueueSize = 20
  // 保存要创建的新连接信息
  private val newConnections = new ArrayBlockingQueue[SocketChannel](connectionQueueSize)
  // 一个临时 Response 队列
  private val inflightResponses = mutable.Map[String, RequestChannel.Response]()
  // Response 队列
  private val responseQueue = new LinkedBlockingDeque[RequestChannel.Response]()

从上面 Processor 线程源码,可以看出 Kafka 的代码逻辑实现的非常好,各个子方法的边界非常清楚。

这里我们就不展开源码分析了, 更深入详细的等到源码分析专题再进行。我们简单的看下 Processor 线程初始化时要做的事情。

看上面代码最后部分,我们知道每个 Processor 线程在创建时都会创建 3 个队列。

  1. newConnections 队列:它主要是用来保存要创建的新连接信息,也就是SocketChannel 对象,目前是硬编码队列长度大小为20。每当 Processor 线程接收到新的连接请求时,都会将对应的 SocketChannel 对象放入队列,等到后面创建连接时,从该队列中获取 SocketChannel,然后注册新的连接。

  2. inflightResponse 队列:它是一个临时的 Response 队列, 当 Processor 线程将 Repsonse 返回给 Client 之后,要将 Response 放入该队列。它存在的意义:由于有些 Response 回调逻辑要在 Response 被发送回 Request 发送方后,才能执行,因此需要暂存到临时队列。

  3. ResponseQueue 队列:它主要是存放需要返回给Request 发送方的所有 Response 对象。通过源码得知:每个 Processor 线程都会维护自己的 Response 队列。

06 请求处理核心流程剖析

上面深入的剖析了 Kafka 超高并发网络架构 以及 SocketServer 中的 Acceptor 线程跟 Processor 线程的实现原理, 接下来我们来将请求处理核心流程给串起来。

只有搞透这部分的实现原理,才能帮助我们有针对性的进行 Broker端请求处理的性能调优。

比如:在上面网络架构图,有两个参数跟整个流程有关系,分别是 num.network.threads、num.io.threads 。如果我们不掌握请求处理的整个流程,就不能更好的对此进行调整,来达到更高的性能要求。

其中 num.io.threads 就是 I/O 工作线程池的大小配置,即 KafkaRequestHandlerPool 线程池,它才是「 真正处理 Kafka 请求 」的地方。

以Kafka 2.5版本,源码位置:

https://github.com/apache/kafka/blob/2.5.0-rc3/core/src/main/scala/kafka/server/KafkaRequestHandler.scala

/**
 * A thread that answers kafka requests.
 */
class KafkaRequestHandler(id: Int, //I/O线程序号
     brokerId: Int,  //所在Broker序号,即broker.id值
     val aggregateIdleMeter: Meter,
     val totalHandlerThreads: AtomicInteger, //I/O线程池大小
     val requestChannel: RequestChannel, //请求处理通道
     apis: KafkaApis, //KafkaApis类,用于真正实现请求处理逻辑的类
     time: Time) extends Runnable with Logging {
 ......
 def run(): Unit = {
    while (!stopped) {
      val startSelectTime = time.nanoseconds
      // 从请求队列中获取下一个待处理的请求
      val req = requestChannel.receiveRequest(300)
      val endTime = time.nanoseconds
      // 统计线程空闲时间
      val idleTime = endTime - startSelectTime
      // 更新线程空闲百分比指标
      aggregateIdleMeter.mark(idleTime / totalHandlerThreads.get)

      req match {
         // 当关闭线程请求处理
        case RequestChannel.ShutdownRequest =>
          ......
        // 当普通请求到来时
        case request: RequestChannel.Request =>
          try {
            request.requestDequeueTimeNanos = endTime
            // 由KafkaApis.handle方法执行相应处理逻辑
            apis.handle(request)
          } catch {
            ....
          } finally {
            // 释放请求对象资源
            request.releaseBuffer()
          }
        case null => // continue
      }
    }
    shutdownComplete.countDown()
  }
 }

下面我们结合 Kafka 超高并发网络架构图来讲解下一个完整请求处理核心流程:

  1. Clients 发送请求给 Acceptor 线程。

  2. Acceptor 线程会创建 NIO Selector 对象,并创建 ServerSocketChannel 实例,然后将 Channel 和 OP_ACCEPT 事件绑定到 Selector 多路复用器上。

  3. Acceptor 线程还会默认创建3个大小的 Processor 线程池,参数: num.network.threads , 并轮询的将请求对象 SocketChannel 放入到连接队列中(newConnections)。

  4. 这时候连接队列就源源不断有请求数据了,然后不停地执行 NIO Poll , 获取对应 SocketChannel 上已经准备就绪的 I/O 事件。

  5. Processor 线程向 SocketChannel 注册了 OP_READ/OP_WRITE 事件,这样 客户端发过来的请求就会被该 SocketChannel 对象获取到,具体就是CompleteReceives。

  6. 这个时候客户端就可以源源不断进行请求发送了,服务端通过 Selector NIO Poll 不停的获取准备就绪的 I/O 事件。

  7. 然后根据Channel中获取已经完成的 Receive 对象,构建 Request 对象,并将其存入到 Requestchannel 的 RequestQueue 请求队列中 。

  8. 这个时候就该 I/O 线程池上场了,KafkaRequestHandler 线程循环地从请求队列中获取 Request 实例,然后交由 KafkaApis 的 handle 方法,执行真正的请求处理逻辑,并最终将数据存储到磁盘中。

  9. 待处理完请求后, KafkaRequestHandler 线程会将 Response 对象放入 Processor 线程的 Response 队列。

  10. 然后 Processor 线程通过 Request 中的 ProcessorID 不停地从 Response 队列中来定位并取出 Response 对象,返还给 Request 发送方。

至此,我们深入剖析完毕 Kafka 网络架构请求「 核心流程 」。

07 系统调优

搞透了 Kafka 超高并发网络架构设计和请求处理核心流程后,我们来聊聊 Broker 端参数调优。

对 Kafka 而言,性能一般是指吞吐量和延时。所以高吞吐量、低延时是我们调优 Kafka 集群的主要目标。

Broker 端调优主要就是合理地设置 Broker 端参数值,以匹配你的生产环境。另外还有一点要说明的就是「 保证服务器端和客户端版本的一致 」,做到这一点,就能获得很多性能收益了。

num.network.threads

创建 Processor 处理网络请求线程个数,建议设置为 Broker 当前CPU核心数*2,这个值太低经常出现网络空闲太低而缺失副本。

num.io.threads

创建 KafkaRequestHandler 处理具体请求线程个数,建议设置为Broker磁盘个数*2。

num.replica.fetchers

建议设置为CPU核心数/4,适当提高可以提升CPU利用率及 Follower同步 Leader 数据当并行度。

compression.type

建议采用lz4压缩类型,压缩可以提升CPU利用率同时可以减少网络传输数据量。

queued.max.requests

在网络线程停止读取新请求之前,可以排队等待I/O线程处理的最大请求个数,生产环境建议配置最少500以上,默认500。

log.flush.xxx

log.flush.scheduler.interval.ms

log.flush.interval.ms

log.flush.interval.messages

这几个参数表示日志数据刷新到磁盘的策略,应该保持默认配置,刷盘策略让操作系统去完成,由操作系统来决定什么时候把数据刷盘;如果设置来这个参数,可能对吞吐量影响非常大。

auto.leader.rebalance.enable

表示是否开启leader自动负载均衡,默认true;我们应该把这个参数设置为false,因为自动负载均衡不可控,可能影响集群性能和稳定。

08 总结

这里,我们一起来总结一下这篇文章的重点。

1、对于 Kafka 这样一个优秀的服务端系统架构来说,应该遵循高可用、高性能、高并发 3 大原则。

2、本文从最简单的网络编程思路出发一步一步演进到 Reactor 设计模式,假设我们就是 Kafka 架构的设计者,我们该如何设计其服务端网络架构。

3、通过本文的深度剖析,提升系统I/O性能的核心是基于「事件驱动」模型实现。

4、在剖析完服务端网络架构后,我们也深度剖析了 SocketServer中两个最重要的线程:Acceptor 线程和 Processor 线程。

5、接着我们结合 Kafka 超高并发网络架构图又梳理了 Kafka 请求处理核心流程。

6、最后给大家分析并做了 Broker 端系统调优的方案。

kafka请求队列模块 最近一直研究kafka源码,想着有必要记录一下。不管研究是否到位,也算是一个里程碑吧。 当我们说到 Kafka 服务器端,也就是 Broker 的时候,往往会说它承担着消息持久化的功能,但本质上,它其实就是一个不断接收外部请求、处理请求,然后发送处理结果的 Java 进程 (因为scala 代码被编译之后生成.class 文件,它和 Java 代码被编译后的效果是一样的)。 高效地保存排队中的... 阅读详情

相关推荐

Kafka 架构调优最常见的5个问题 够经典

导语 本文是一篇kafka的干货向内容,作者详细的梳理了kafka架构调优的5个经典问题,不论在工作中还是在找工作面试中都是非常经典的问题,希望大家能熟读本篇文章! 正文 Kafka 架构调优5问 了解Kafka超高并发网络架构是如何设计吗? 我们知道 Kafka 网络通信架构使用到了 Java NIO 以及 Reactor 设计模式。我们先从整体上看一下完整的网络通信层架构,如下图所示: 1)从上图中我们可以看出,Kafka 网络通信架构中用到的组件主要由两大部分构成:SocketServ

uuqaz的博客 687

kafka请求全流程(三)—— I/O处理

承接上一篇,请求的接收与分发(https://blog.csdn.net/fenglei0415/article/details/106172921),接下来应该是请求队列的通道(https://blog.csdn.net/fenglei0415/article/details/105960812)。本篇是I/O的线程逻辑。 Broker端参数 num.io.threads 参数表示的就是 I/O 线程池的大小。所谓的 I/O 线程池,即 KafkaRequestHandlerPool,也称请求处理线程池

fenglei0415的博客 1279

Kafka实现高并发的原理(消息中间件如何实现每秒几十万的高并发写入)

Kafka: 是一个高吞吐低延迟的高并发,高性能消息中间件。配置良好的Kafka集群能够做到每秒几十万或者上百万的超高并发写入。 Produce 页缓存技术+磁盘顺序写 Kafka接收到数据的时候,都会往磁盘上去写 Page Cache 内存里面的缓存,是操作系统自己管理的缓存。 在写入磁盘文件的时候,可以直接写入到OS cache里。接下来由操作系统自己决定何时把cache里面的数据刷写到磁盘...

小凯的博客 3180

kafka集群安装

集群规划| hadoop102 hadoop103 hadoop104 zookeeper zookeeper zookeeper kafka kafka kafka 1.解压安装包 [lzh@hadoop102 software]$ tar -zxvf kafka_2.11-0.11.0.2.tgz -C /opt/module/ 2.修改解压后的文件名称 [lzh@ha...

lzh253985690的博客 257

离开小厂进大厂的第一周,kafka连接数过多

Kafka 如何做到支持百万级 TPS ? 先用一张思维导图直接告诉你答案: 顺序读写磁盘 生产者写入数据和消费者读取数据都是顺序读写的,先来一张图直观感受一下顺序读写和随机读写的速度: 从图中可以看出传统硬盘或者SSD的顺序读写甚至超过了内存的随机读写,当然与内存的顺序读写对比差距还是很大。 所以Kafka选择顺序读写磁盘也不足为奇了。 下面以传统机械磁盘为例详细介绍一下什么是顺序读写和随机读写。 盘片和盘面:一块硬盘一般有多块盘片,盘片分为上下两面,其中有效面称为盘面,一般上下都有效,也就是说:盘面

m0_57767600的博客 1506

Golang 处理 Kafka 百万级消息的架构设计

在电商大促、日志采集、实时数据分析等场景中,每秒数十万甚至百万级的消息涌入已成为常态。Kafka 作为高吞吐量消息队列(官方宣称单节点每秒可处理 10 万+消息),是这些场景的核心基础设施。但如何用 Golang 高效处理 Kafka 消息,避免消息堆积、保证低延迟,是开发者面临的实际挑战。本文将聚焦“百万级消息处理”这一场景,覆盖架构设计的关键环节,帮助开发者从理论到实践掌握完整解决方案。

AI Agent Harness Engineering 1148

kafka是如何做到百万级高并发低迟延的?

Kafka是高吞吐低延迟的高并发、高性能的消息中间件,在大数据领域有极为广泛的运用。配置良好的Kafka集群甚至可以做到每秒几十万、上百万的超高并发写入。Kafka到底是如何做到这么高的吞吐量和性能的呢?我们今天来走进kafka的server端探究一下它的Reactor高并发网络模型机制。 1.1、Kafka Reactor模型架构 Kafka客户端和服务端通信采取的是NIO的reactor模...

flykinghg的博客 1070

Allegro17.4原理图-PCB双向联动技巧:从网表生成到同步高亮

本文深入解析了Cadence Allegro 17.4中原理图与PCB的深度双向联动技巧。核心在于通过精准的网表生成与管理、实时的跨窗口交互高亮与信号追踪,以及元件与封装的智能匹配更新,构建高效协同设计工作流。掌握这些技巧能显著提升高速、高密度电路设计的效率与准确性,实现从逻辑设计到物理实现的无缝衔接。

weixin_29178069的博客 358

Kafka如何实现每秒上百万的超高并发写入?

Kafka是高吞吐、低延迟的高并发、高性能的消息中间件,在大数据领域有极为广泛的运用。配置良好的Kafka集群甚至可以做到每秒几十万、上百万的超高并发写入。 那么 Kafka 到底是如何做到这么高的吞吐量和性能的呢? 页缓存技术和磁盘顺序读写 首先 Kafka 每次接收到数据都会往磁盘上去写,如下图所示: 那么在这里我们不禁有一个疑问了,如果把数据基于磁盘来存储,频繁的往磁盘文件里写数据,这个性...

z1941563559的博客 1844

vtk相机_分别用 VTK 体绘制和面绘制来实现医学图像三维重建;

序言,VTK介绍:VTK 全称为 The Visualization Toolkit (可视化工具),是一个开源、跨平台、自由获取、支持并行计算的图形应用函数;拥有3D 渲染的最新工具、提供3D交互模式以及2D绘图等。VTK 包含一个C++类库,目前提供了众多语言接口,例如 Java、Python、TCL;在三维函数库OpenGL 的基础上采用面向对象设计方法发展起来图形学基本概念和数据...

weixin_39665302的博客 688

QT编程系列1--QT学习前需知

本周学习了一些QT编程方面的知识,学写了几个程序,这里把记录下来。一方面对前面学习的知识做一个总结,便于以后复习、再学习和应用;另一方面也和大家做个交流,有不足的地方请各位看官多指点。   首先是做一些学习之前的交代:一,学习QT需要哪些基础;二,学习QT有哪些用途,QT较其他的开发工具有哪些特点;三,学习QT的思路。

霜月孤鸟&RTEMS&TinyOS 1115

Kafka百万级吞吐量的秘密

前言:我们都知道 Kafka 是基于磁盘进行存储的,但 Kafka 官方又称其具有高性能、高吞吐、低延时的特点,其吞吐量动辄几十上百万。小伙伴们是不是有点困惑了,一般认为在磁盘上读写数据是会降低性能的,因为寻址会比较消耗时间。那 Kafka 又是怎么做到其吞吐量动辄几十上百万的呢? Kafka 高性能,是多方面协同的结果,包括宏观架构、分布式 partition 存储、ISR 数据同步、以及“无所不用其极”的高效利用磁盘和操作系统特性。 一、磁盘顺序读写 磁盘的顺序读写的情况下,磁盘的顺序读写速度和

何哥的博客 2957

stm32h743 FM25CL64铁电存储器踩坑记录

调试FRAM经验总结: 1、跑完FRAM读写代码之后,逻分仪发现总线上只有简单、短暂的电平变化,明显不是SPI的通信数据。 (经提醒发现连片选拉高拉低都没有执行到位) 后来发现是因为片选引脚没有初始化,所以直接拉高拉低是无效的。 2、引脚成功初始化后发现CLK、MISO、MOSI数据仍不正常。通过加打印的方式发现跑到HAL_SPI_Transmit中之后还没有执行到写SPI数据寄存器的那一步就return了。 后来经提醒发现: 上图中的指针使用方式错误 后来又发现: 打印出来发现

kuniqiw的博客 3844

Kafka如何实现每秒上百万的超高并发写入?掌握好面试给你打满分

这篇文章来聊一下 Kafka 的一些架构设计原理,这也是互联网公司面试时非常高频的技术考点。 Kafka 是高吞吐低延迟的高并发、高性能的消息中间件,在大数据领域有极为广泛的运用。配置良好的 Kafka 集群甚至可以做到每秒几十万、上百万的超高并发写入。 那么 Kafka 到底是如何做到这么高的吞吐量和性能的呢?这篇文章我们来详细说一下。 页缓存技术 + 磁盘顺序写 首先 Kafka 每次接收到数据都会往磁盘上去写,如下图所示: 那么在这里我们不禁有一个疑问了,如果把数据基于磁盘来存储,频

m0_49496327的博客 1624

Tip-Adapter: Training-free Adaption of CLIP for Few-shot Classification

对比式视觉-语言预训练,也称为CLIP,通过大规模的图像-文本对来学习视觉表示,为zero-shot知识迁移展示了新的范式。它在下游任务上展现出令人瞩目的性能,实现了zeri-shot的知识迁移。为了进一步增强CLIP的适应能力,现有方法提出了微调可学习模块的方法,显著提高了少样本情况下的性能,但也引入了额外的训练时间和计算资源。在本文中,我们提出了一种适用于CLIP的无需训练的少样本分类方法,称为Tip-Adapter。

qq_43800752的博客 1164

C++ 小游戏程序 (共七款)

C++编程小游戏_闪耀的天狼星的博客-优快云博客_游戏c++C++跑酷小游戏_闪耀的天狼星的博客-优快云博客。好玩的c++编程小游戏,共六款。代码】C++跑酷小游戏。

小天狼星_布莱克 的博客 3万+

支持百万级TPS,Kafka是怎么做到的?

作者 | 雷架来源 | 爱笑的架构师谈到大数据传输都会想到 Kafka,Kafka 号称大数据的杀手锏,在业界有很多成熟的应用场景并且被主流公司认可。这款为大数据而生的消息中间件,以其百...

优快云资讯 2678

数据治理路径之辩:从“先治后用”到“边用边治”,企业如何选择最优路径?

数据治理是企业在数智化建设中的核心挑战,主要涉及三种时序策略:先治理后使用、先用后治理和边用边治。先治理后使用强调在数据应用前建立完整的治理框架,适合高合规要求的行业,但可能响应滞后。先用后治理则优先释放数据价值,适合快速变化的业务环境,但可能累积数据质量问题。边用边治寻求动态平衡,通过持续改进实现治理与应用的同步迭代,适合复杂数据环境。技术选型决策矩阵和实施方法论提供了具体的操作指南,建议根据组织特性和业务需求选择适配方案,并通过渐进式演进路径实现治理与业务的共生演进。

石榴姐yyds 405

揭秘Kafka速度魔法:百万级吞吐背后的核心黑科技

Kafka的高性能源于对底层原理的深度把控拥抱磁盘:顺序写比内存随机写更快信任OS:Page Cache比JVM堆更高效减少搬运:零拷贝是网络传输的终极优化分而治之:分区是分布式并行的基石最后思考:当你在设计下一个系统时,是否也执着于“内存即快,磁盘即慢”的刻板印象?Kafka用单集群百万/秒吞吐深入理解原理比盲目堆硬件更重要!学习资源📚Kafka官方性能调优指南💻GitHub性能测试工具。

全栈开发工程师 1153

学Simulink--基于多物理场耦合与系统集成的储能系统场景实例:压缩空气储能(CAES)系统的热力学建模与效率分析

本文提供了一个基于Simulink的压缩空气储能(CAES)系统热力学建模教程。通过多物理场耦合方法,详细演示了从系统架构设计到仿真测试的全过程,包括多级压缩机/膨胀机系统搭建、显热蓄热系统设计以及效率分析。文章重点强调了热管理对提升CAES效率的关键作用,并给出了68%电-电效率的优化案例。最后提出了变工况建模、不同蓄热介质对比等高级优化方向,为开发零碳大容量储能系统提供了实用工具和方法。

amy_mhd的博客 131

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

OpenIddict生产实战:泛微/金蝶/帆软单点登录落地指南

OpenIddict是.NET生态中深度集成ASP.NET Core管道的OIDC协议引擎,区别于黑盒式认证服务,它以可裁剪、无UI、零预设Schema为特征,天然适配Minimal Hosting与EF Core 8.0等现代架构。其核心价值在于通过密钥热更新、客户端粒度权限控制、无状态Token验证等机制,支撑高可用、强审计、多系统兼容的身份中台建设。在政府监管、医疗SaaS、制造业MES等真实场景中,OpenIddict已验证对泛微OA(RSA签名强制要求)、金蝶K3Cloud(Implicit流适配

weixin_34235457的博客 305

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

支持百万级TPS,Kafka是怎么做到的?答案藏在这10张图里

10张图告诉你秘密

华科硕士,大厂打工中。编程问题咨询,请私我 2953

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Kafka如何实现每秒上百万的超高并发写入?掌握好面试给你打满分!

这篇文章来聊一下 Kafka 的一些架构设计原理,这也是互联网公司面试时非常高频的技术考点。Kafka 是高吞吐低延迟的高并发、高性能的消息中间件,在大数据领域有极为广泛的运用。配置良好的 Kafka 集群甚至可以做到每秒几十万、上百万的超高并发写入。那么 Kafka 到底是如何做到这么高的吞吐量和性能的呢?这篇文章我们来详细说一下。页缓存技术 + 磁盘顺序写首先 Kafka 每次接收到数据都会往...

weixin_34383618的博客 171

10 张图告诉你,Kafka 是怎么做到支持百万级 TPS 的?

我的新课《C2C 电商系统微服务架构120天实战训练营》在公众号儒猿技术窝上线了,感兴趣的同学,可以长按扫描下方二维码了解课程详情:课程大纲请参见文末本文转自爱笑的架构师谈到大数据传输都...

石杉的架构笔记 875
上一篇: 上千道Java一线大厂面试题手册,耗时数月进行整理总结分享
下一篇: Istio 可以代替 Spring Cloud 吗?
JavaShark
博客等级 码龄4年 184粉丝 438原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值