自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

water Wang

每个人都会有觉醒期,只是来的晚或者早罢了。

  • 博客(241)
  • 资源 (15)
  • 论坛 (1)
  • 收藏
  • 关注

原创 Redis系列汇总

Redis 汇总Redis(1): SQL or NoSqlredis(2):redis简介redis(3):安装redis(4):数据结构-String字符串redis(5):数据结构-Hash散列类型redis(6):数据结构-List列表类型redis(8):数据结构-zset有序集合类型redis(7):数据结构-set集合类型redis(9):Redis 5种数据类型vs java类型redis(10):redis五种数据结构应用场景redis(11):事务redis(.

2021-03-13 17:04:01 1709 29

原创 DataX源码阅读汇总

将自己datax的系列文章进行汇总形成目录DataX(1):编译打包使用DataX(2): 通过idea搭建源码阅读+调试环境DataX(3): win环境cmd乱码DataX(4): dDataX.py解读DataX(5):改造升级-自动识别py环境,执行dDataX任务DataX(6):启动步骤解析DataX(7):JobContainer源码解读DataX(8):TaskGroupContainer源码解读DataX(9):Job和TaskGroup的通讯机制DataX(10).

2021-03-10 11:15:29 53044 8

原创 4.4.3 同步提交偏移量

4.4.3 同步提交偏移量消费者同步提交偏移盐的做法,和4.2.2节第3小节“组合模式的运用:获取偏移量”中的获取偏移盘处理方式类似,都是在最外层用一个死循环来确保必须收到服务端返回的响应结果才能结束。自动提交任务使用异步模式提交偏移量,调用cHent.qutckPoll()后,可以立即回到主线程,所以异步模式是无阻塞的。而同步模式提交偏移量,调用者必须等到提交偏移量完成后才回到主线程,所以同步模式是阻塞的。相关代码如下:自动提交任务使用异步方式提交偏移量,因为任务是周期性运行的,没有什么依赖条件,不

2021-04-20 00:10:45 7

原创 4.3.4 处理心跳结果的示例

4.3.4 处理心跳结果的示例如图4-34所示,客户端启动时会创建调度时间为0秒的延迟任务加入队列。客户端轮询的时间为2秒,会弹出延迟任务(因为延迟任务的调度时间小于当前时间),现在队列为空了。但是因为没有上一次心跳,只有上一次的会话重置时间,经过下面3个步骤的计算后,会重新创建一个调度时间为5秒的延迟任务加入队列。(1)距离上次心跳的时间间隔=当前轮询的时间-上次会话的重置时间=2秒一0秒=2秒。(2)距离下次心跳的时间间隔=心跳间隔距离上次心跳的时间间隔=5秒-2秒=3秒。(3)下次心跳任务的.

2021-04-19 23:22:04 5

原创 4.3.3 运行心跳任务

4.3.3 运行心跳任务心跳任务(HeartbeatTask)作为一个延迟的任务,定义在抽象的客户端协调者类’(AbstractCoordi.nator)中。在4.2.3节第3小节“延迟的任务队列”中客户端在轮询时,只会取出延迟队列中调度时间小于当前时间(反过来更容易理解:当前时间大于调度时间)的延迟任务,将其弹出来并调用它的run()方法。如果任务的调度时间大于当前时间,它不会从队列中弹出,也不会执行run()方法。相关代码如下:当调用延迟任务的run()方法时,说明当前时间已经超过这个延迟任务的.

2021-04-19 22:19:14 3

原创 4.3.2 心跳状态

4.3.2 心跳状态每个消费者客户端都只有一个心跳任务,心跳对象(Heartbeat)除了记录心跳任务的元数据-一会话超时时间(timeout)、定时任务时间间隔(interval),还会记录当前心跳任务的状态一一最近的会话重置时间、最近的心跳发送时间、最近的心跳接收时间。相关代码如下:timeToNextHeartbeat()方法会计算当前时间到下一次调度的时间间隔,它跟上一次心跳任务的发生时间有关,会用来判断什么时候可以发送下一次心跳:如果返回值为0,表示当前时间减去上一次调度时间的差距大于心跳.

2021-04-19 21:38:44 5

原创 4.4.2 将拉取偏移量作为提交偏移量

4.4.2 将拉取偏移量作为提交偏移量旧API中,当客户端迭代消费消息时会更新分区信息的已消费偏移量,并且有一个后台线程定时将分区信息的已消费偏移量作为已提交偏移量发送给协调者节点。新API中,订阅状态的分区状态有拉取偏移量(posi.ti.on)和提交偏移量(COmmitted)两个变量。客户端的轮询方法会在返回拉取的记录集之前,更新分区状态的拉取偏移量,为下一次轮询操作中的拉取做准备。但客户端在迭代消费者记录集时,并没有更新分区状态的提交偏移量。所以拉取偏移量变量也要能够代表分区的消费进度,即新A.

2021-04-19 20:11:49 8

原创 4.2.3 网络客户端轮询

4.2.3 网络客户端轮询本节一开始提到消费者通过消费者网络客户端对象(ConsumerNetworkClient)这中间花了很大篇幅去分析异步请求。现在再回到消费者网络客户端发送请求之后的流程,即消费者网络客户端的轮询。轮询发送请求客户端发送请求后,但又不知道什么时候服务端才返回结果。客户端获取结果的3种轮询方法如下。客户端不想等待,设置超时时间为0,表示请求发送完就立即回到调用者的主线程中。指定了超时时间,如果在指定时间内没有结果,最后也要返回到调用者的主线程中。设置超时时间为最大.

2021-04-19 19:18:18 5

原创 4.2.2异步请求高级模式

4.2.2异步请求高级模式有时候客户端响应对象中的数据比较简单,可能就只有一条数据,而且类型也是确定的。比如获取分区偏移量,客户端响应结果只有一条数据,类型为Long。我们可能希望从异步请求得到的结果就是这个偏移盘,而不希望根据Cl1.entResponse对象再去获取。异步请求对象提供了“组合加适配器”(co111pose+Adapter)的模式,可以让调用者直接获取异步请求对象的结果。异步请求适配器异步请求为客户端提供调用自定义业务处理逻辑的人口,除了“添加监昕器”的方式,还有一种是“组合加.

2021-04-19 15:19:40 7

原创 5.4.6 再平衡超时与会话超时

5.4.6 再平衡超时与会话超时消费组成员[Cl][Cl,C2](CI,C2](Cl:Pl,C2:P2][Cl][CI][Cl:{Pl,P2}]当消费组状态是“准备再平衡”,协调者会创建一个“延迟的加入组”对象。这个对象表示协调者在处理消费者的“加入组请求”时,由于还没有收集完整“重新发送加入组请求”的消费者,所以还不能返回“加入组响应”给发送了“加入组请求”的消费者。当消费组中的所有消费者都发送(或重新发送)了“加入组请求”,“延迟的加入组”对象就可以完成,协调者这时才会返回“加入组响应”给所有的消.

2021-04-19 14:54:21 6

原创 5.4.5 协调者处理“离开组请求”

5.4.5 协调者处理“离开组请求”消费者离开消费组有多种情况,比如消费者应用程序被关闭,或者应用程序没有关闭,但消费者不订阅主题了。消费者离开消费组,表示协调者不需要在消费组中管理这个消费者了。消费者客户端的工作如下。(1)取消定时心跳任务,因为离开组意昧着不被协调者官:理,就不需要向协调者发送心跳了。(2)通过消费者的协调者对象(ζon阳SUI冒(3)重置相关的信息,比如设置成员编号为“未知编号”、重置rejolnNeeded变更为false。协调者在处理“离开组请求”时,在条件检查通过后.

2021-04-18 23:37:43 7

原创 5.4.4 协调者处理“同步组请求”

5.4.4 协调者处理“同步组请求”消费组状态进入“等待同步”后,协调者会发送“加入组响应”给每个消费者。如果是普通消费者收到“加入组响应”,会立即发送“同步组请求”。而如果是主消费者收到,它会先执行完分区分配工作,然后才发送“同步组请求”。正常情况下,普通消费者会先于主消费者发送“同步组请求”。协调者处理普通消费者的“同步组请求”,只会设置对应消费者成员元数据的回调方法,因为主消费者还没有发送“同步组请求”,就还没有到返回“同步组响应”的时机,所以只能将回调方法暂存到元数据中。相关代码如下:协调者处

2021-04-18 21:39:53 7

原创 5.4.3 协调者处理“加入组请求”

5.4.3 协调者处理“加入组请求”按照5.4.l节第三种的示例,每个消费者加入消费组都有足够的时间触发一次再平衡操作。在没有完成再平衡操作之前,不会有新的消费者加入消费组。消费组的状态会按照“稳定→准备再平衡→等待同步→稳定”的顺序一直循环下去。虽然消费组的状态变化很有规律,但协调者处理不同消费者的“加入组请求”时执行流程是不同的。下面再举3个不同的示例,前两个示例有两个消费者,我们从正常的状态转换开始,逐步引入异常的状态转换。最后为了模拟另一种异常情况,第气个示例有3个消费者,对应的是5.4.1节.

2021-04-18 19:50:52 8

原创 4.1.6消费消息

4.1.6消费消息拉取器返回的记录集是消费者记录列表,在返回给客户端时,会被封装成消费者记录集(ConsumerRecords)迭代器,便于客户端直接进行迭代处理。和旧消费者使用ConsumerIterator类似,消费者记录集迭代器也实现了Iterable接口,所以可以用for循环处理每条消息。旧API应用程序用到了消费者连接器、消息流和消费者迭代器,新API只用到了消费者对象(KafkaConsumer)、消费者记录集迭代器。还有一个不同点是:|臼API返回的消费者迭代器消息是字节数组,而新API.

2021-04-18 18:59:42 9

原创 4.1.5 消费者获取记录

4.1.5 消费者获取记录拉取器处理拉取响应时已经将原始的响应数据封装成了分区记录集,并放到全局的成员变量this.records中 。 但要真正被消费者可用,还需要封装成消费者记录( ConsumerRecord )。 相关代码如下:拉取器的获取记录集方法会使用414节“处理拉取响应”方法生成的全局成员变茧,作为数据源构成最终的拉取结果。既然数据已经在全局成员变量中了,那么要提供给客户端使用,就可以直接返回。但实际上拉取器在这一步还做了下面几点优化。一次轮询发送两次拉取请求,必须确保第一个请求.

2021-04-18 16:42:56 7

原创 4.1.3 消费者轮询的流程

4.1.3 消费者轮询的流程按照消费者应用程序的示例,消费者订阅主题的下一步是“轮询”。前面分析的准备t作(确保协调者存在,确保分配分区,更新拉取偏移量)都内置在轮询操作里,所以本节的“轮询”主要指准备工作之后的拉取消息流程。这些准备工作不放在订阅主题中去做,是因为消费者订阅了主题不一定会消费消息,但消费者有轮询操作就表示它一定想要拉取并消费消息。客户端轮询的两种方案方案一是把准备工作放在循环外,虽然可以保证循环拉取消息,但是如果需要再平衡,就无法执行重新分配分区的处理逻辑。方案二是把准备工.

2021-04-18 12:24:55 7

原创 3.5.5 缓存分区的偏移量

3.5.5 缓存分区的偏移量消费者提交自己负责分区的偏移量,除了写入服务端(协调节点)内部主题某个分区的日志文件中,还要把这部分数据保存一份到当前服务端的内存中,这样分区的偏移量保存在了磁盘和内存两个地方。偏移量消息的键由消费组、主题、分区组成(GoupTopicPat1tion),消息的值是分区的偏移盘。查询分区的偏移量时给定GoupTop1cPat1hon,会返回分区对应的偏移盘,即分区当前的消费进度。由于消费者会周期性地提交偏移量,同一个分区在每次提交时都会产生新的偏移盐。比如分区p。在第一次提交

2021-04-18 10:51:59 20 2

原创 3.6.4 发送拉取请求并消费消息

3.6.4 发送拉取请求井消费消息消费者使用高级API拉取消息,再平衡后第一次拉取时,从ZK或消费组的协调节点读取一次偏移£10扣,取消息后会更新本地内存partitionMap的拉取状态,后续拉取线程以最新的分区拉取状态构建拉取请求,并不需要再从ZK或协调节点读取偏移量。因为拉取状态每次都会更新,所以新创建的拉取请求也是最新的。低级API也使用类似的方式,第一次读取偏移量通过getlastOffset()从服务端读取,拉取到消息后要更新读取偏移量,下一次拉取时以最近更新的读取偏移量构建拉取请求。低

2021-04-18 08:04:15 12

原创 3.6.3 获取分区的读取偏移量

3.6.3 获取分区的读取偏移量读取分区的偏移量涉及日志存储,这里我们先给出一些简单的结论(具体细节会在第6章详细分析):一个分区有多个片段文件(Segment),每个片段文件都包含全局有序的片段基准偏移量(segmentBaseOffset)。客户端调用getlastOffset()获取的是每个片段文件的基准偏移量。客户端发送的偏移毡’请求(OffsetRequest)包含的数据是:分区偏移量的请求信息(PartitionOffsetinfo)。这个对象有两个参数:whichTime表示拉取的时间戳.

2021-04-17 21:43:54 8

原创 4.1.2 消费者轮询的准备工作

4.1.2 消费者轮询的准备工作客户端的消费者与服务端的协调者通信通过消费者的协调者类完成,在拉取消息前有两个ensure()方法:第一个是ensureCoordinatorKnown()方法,确保客户端已经连接上协调者;第二个是ensureParti.ti.onAssi.gnment(),确保消费者收到协调者分配给它的分区,如果消费者没有分配到分区,就无法拉取消息。客户端在第一步必须先连接上协调者,才能调用第二步从协调者获取分区,否则第二步就无法执行。**注意:**这里有两个“协调者”对象,消费者客.

2021-04-17 19:53:03 12

原创 4.1.4 消费者拉取消息

4.1.4 消费者拉取消息消费者创建拉取请求的准备工作,和生产者创建生产请求的准备工作类似,它们都必须和分区的主副本交互。一个生产者写人的分区和消费者分配的分区都可能有多个,同时多个分区的主副本有可能在同一个节点上为了减少客户端和服务端集群的网络连接,客户端并不是以分区为粒度和服务端交互,而是以服务端节点为粒度如果分区的主副本在同一个节点上,应当在客户端先把数据按照节点整理好,把属于同一个节点的多个分区作为一个请求发送出去一个消费者可以允许同时向多个主副本节点发送请求,这个请求包括属于这个主副本节点的多

2021-04-17 16:32:28 13

原创 3.5.3 连接偏移量管理器

3.5.3 连接偏移量管理器前面我们分析的拉取偏移#方法和提交偏移量’方法,都需要和偏移主-管理器通信。在这之前,消费者需要通过channelToOffsetManager()方法向服务端任意一个节点发送“消费组的协调者请求”(GroupCoordinatorRequest),来获取消费组对应的协调节点,即偏移量管理器(OffsetManager)节点。服务端处理消费组的协调者请求,实际上也是通过查询主题的元数据来完成的。不过和LeaderFinderThread中返回主题元数据,然后还要在客户端继续处理

2021-04-17 11:52:44 10

原创 3.5.2 提交偏移量到内部主题

3.5.2 提交偏移量到内部主题消费者提交偏移量到Kafka的内部主题,首先要确定连接哪个或者哪些服务端节点。回顾一下,生产者发送消息时会根据分区的主副本分组,和多个节点者rs建立连接;消费者分配多个分区,也要根据分区的主副本分组,和多个节点建立连接。而消费者提交所有分区的偏移量时,实际上只和-个服务端节点建立连接。同样要处理多个分区,为什么普通消息需要多个连接,而偏移量只需要一个连接?如图3-24所示,目标节点指的是分区的主副本节点,我们给出了偏移聋的多种连接方案。(1)如果不同分区的偏移盐写到了不同

2021-04-17 09:59:46 6

原创 3.6.2 找出分区的主副本

3.6.2 找出分区的主副本客户端为了获得分区的主副本,可以向任意一个节点发送主题元数据请求(Top"i.cMetadataRequest),因为每个节点都保存了集群所有的主题元数据,而且数据都是一致的。主题元数据包含了多个分区的元数据,而消费者只指定消费特定的分区,所以需要找出对应的分区元数据。第一次获取分区的主副本节点的候选集合是客户端给定的种子节点(a_seedBrokers)。主副本挂掉后,新的候选集合为凡repli.caBrokerS,它来自于第一次调用fi.ndleader()返回分区元数.

2021-04-17 07:17:19 29

原创 3.4.2 消费者迭代消费消息

3.4.2 消费者迭代消费消息消费者迭代器生成包含消息的迭代器,首先弹出队列的每个数据块,然后获取数据块对应的消息集,最后迭代消息集中的每条消息。客户端迭代的消息是队列的所有数据块,而不是一个数据块。所以在迭代过程中,要确保读取完一个数据块后,接着读取下一个数据块。也就是说,消费者迭代器是:所有数据块通过消息集f!fi成的消息迭代器。下面的伪代码实际上用了两层循环:消费者迭代器实现了Java的Iterator接口,必须重载hasNext()和next()方法。hasNext()方法会用来判断迭代

2021-04-16 23:54:58 13

原创 3.5.4 服务端处理提交偏移量的请求

3.5.4 服务端处理提交偏移量的请求协调节点会将消费者的偏移量提交请交给GroupCoordlnator类的handleCommitOffsets()方法处理,其中参数offsetMetadata表示分配给消费者的所有分区消费进度。相关代码如下:写入偏移消息会调用RepllcaManager.appendMessages()方法,将消息集追加到本地日志文件,并且会把分区和对应的偏移量保存在协调节点的缓存中。目的是:再平衡后如果其他消费者需要读取分区的偏移毡,在连接上协调节点后,可以直接读取缓存,而不

2021-04-16 21:32:08 21 2

原创 3.3.3 消费者拉取线程

3.3.3 消费者拉取线程消费者拉取管理器在创建拉取线程时,会将表示分区及其分区信息对象的全局partitionMap作为类级别的变量传给每个拉取线程,但每个拉取线程在拉取时实际上只会负责一部分的分区。拉取线程在拉取到分区数据后,需要将拉取结果保存到分区信息的队列中。因为每个拉取线程都持有全局的partitionMap引用,所以processPartitionData()方法在处理拉取结果时,可以获取到分区信息中的队列,并将拉取结果填充到队列中。相关代码如下:注意:拉取线程的抽象类在拉取工作中也有一个

2021-04-16 17:55:43 16

原创 3.3.2 抽象拉取线程

3.3.2 抽象拉取线程抽象拉取线程(AbstractFetcherThread)定义了拉取工作的主要流程,不同的实现类通过抽象方法嵌套在主流程中,保证了主流程执行的一致性。拉取线程工作时,首先要确定数据源(即拉取状态),每次拉取到消息还要更新拉取状态,确保下一次拉取请求时获得的拉取状态是最新的。构建拉取请求拉取管理器后台线程调用拉取线程的addPartitians()方法,partitionMap变量保存了每个分区的拉取状态。拉取线程的运行方法会根据拉取状态构建井处理拉取请求。相关代码如下:.

2021-04-16 16:35:17 18

原创 3.2.5分区信息对象的偏移量

3.2.5分区信息对象的偏移量在结束本节之前,我们来看一下分区信息对象的偏移量在拉取钱程中的使用方式。消费者的拉取线程第一次拉取消息时,会从ZK中读取fetchedOffset来决定要从分区的哪个位置开始拉取消息。消费者在读取到消息后,会更新分区的consuMedOffset。同时,消费者也会使用consuMedOffset作为分区的消费进度并定时地提交到ZK中。注意:但并不是说拉取线程每次拉取消息都要读取ZK的偏移量作为fetchedOffset(那样和ZK交互就太频繁了)。因为客户端已经保存了con

2021-04-16 12:52:31 16

原创 3.2.4 关闭和更新拉取线程管理器

3.2.4 关闭和更新拉取线程管理器再平衡操作中我们已经分析了分区的所有权、分区的分配,剩下和l拉取线程(Consul’lerFetcherThread)相关的是:关闭和更新消费者的拉取线程管理器(Consul’lerFetcherManager,下文简称“拉取管理器”)。再平衡操作前,closeFetchersForQueues()方法关闭拉取管理器时,也要关闭它管理的所有线程。除了拉取线程应该关闭,和拉取线程相关的数据结构也需要清理,比如分区信息对象的队列需要清空。另外,消费者在拉取数据时会周期.

2021-04-16 09:14:07 15

原创 3.2.3 创建分区信息对象

3.2.3 创建分区信息对象从ZK中读取出的分区的偏移量,会被用来构造分区信息对象(PartitionTopicinfo)。分区信息对象的主要内容有:分区,表示拉取线程的“目标”;队列,作为消息的“存储”介质;偏移量,作为拉取“状态”。消费者的拉取线程会以最新的“状态”拉取ZK的offsetCounter是这个分区最近一次的消费偏移量,也是最新的拉取偏移量。消费者向服务端发起拉取数据请求时,拉取偏移量(fetchOffset)表示要从哪里开始拉取。消费者从服务端拉取消息写到本地后,消费偏移量(cons.

2021-04-16 00:37:30 18

原创 3.2.2 为消费者分配分区

3.2.2 为消费者分配分区每一个消费者都需要分配到分区才能拉取信息,当发生再平衡时,消费组中的所有消费者都会重新分配分区。 为了让每个消费者都能被分配到分区,需要从ZK中查询出所有的分区以及所有的消费者成员歹lj表 。 当然,分区要限定主题范围,消费者要限定消费组范围 。 对于触发再平衡的消费者而言,它所属的消费组是确定的,而且订阅的主题和分区也是确定的,所以从ZK中获取订阅相同主题的消费者成员列表、包含相同主题的分区都没有问题。如图3-13所示,消费者l订阅了主题1和主题2,消费者2订阅了主题1和.

2021-04-15 23:36:24 22

原创 3.1.3 重新初始化消费者

3.1.3 重新初始化消费者消费者连接器的consume()方法在注册消费者至UZK后,调用reinitializeConsumer()方法执行重新初始化。消费者启动时希望被加入消费组,必须执行一次初始化方法,并触发消费组内所有消费者成员(当然也包括自己)的再平衡。如图3-12所示,触发消费者连接器执行再平衡操作有两种方式:外部事件和直接触发。直接触发会在消费者启动时执行,即重新初始化消费者时,直接调用syncedRebalance()方法强制触发一次再平衡。外部事件会通过下面3种监昕器和线程检查的.

2021-04-15 23:05:11 22 2

原创 3.1.2 消费者客户端的线程模型

3.1.2 消费者客户端的线程模型消费者连接器的createMessageStreams()方法会调用consume()方法,但consume()方法并不真正消费数据,而只是为消费消息做准备工作,具体步骤如下。(1)根据客户端传入的topicCountMap构造对应的队列和消息流,消息流引用了队列。(2)在ZK的消费组父节点下注册消费者子节点。(3)执行初始化工作,触发再平衡,为消费者分配分区,拉取线程会拉取消息放到队列中。(4)返回消息流列表,队列中有数据时,客户端就可以从消息流中迭代读取消息。

2021-04-15 22:38:30 24

原创 2.2.5 服务端的请求处理入口

2.2.5 服务端的请求处理入口现在请求通道上请求的发送(由处理器执行)和接收(由请求处理线程执行),以及响应的接收(由处理器执行)都有了,只剩下响应的发送由rKafkaApis负责。r客户端请求通过请求处理器交给负责具体业务逻辑处理的rKafkaApisr,rKafkaApis收到请求执行完业务逻辑,r将请求对应的响应结果发送到请求通道的响应队歹ljr中r。r因为rKafkaApis类持有请求通道的引用,所以它可以把响应发送到请求通道中。现在,请求和响应的发送和接收四个步骤就都齐了 。KafkaAp"

2021-04-15 20:00:59 17

原创 2.2.4 Kafka请求处理线程

2.2.4 Kafka请求处理线程KafkaServer会创建请求处理线程池(KafkaRequestHandlerPool),在请求处理钱程池中会创建并启动多个请求处理线程(KafkaRequestHandler)。SocketServer中全局的请求通道会传递给每个请求处理线程。这样每个请求处理线程共同消费同一个请求通道中的所有客户端请求。每个请求处理线程获取到请求后,都交给统一的KafkaApis处理。注意:一个KafkaServer有多个请求处理线程,但是只有一个KafkaApis。相关代码如下:

2021-04-15 19:09:07 18

原创 2.2.3 请求通道的请求队列和响应队列

2.2.3 请求通道的请求队列和响应队列创建SocketServer也会创建一个请求通道(RequestChannel),在KafkaServer中,会将SocketServer的请求通道传给Kafka请求处理线程(KafkaRequestHandler,下文简称“请求处理线程”)和KafkaApis。在上一节中客户端的请求已经到达服务端的处理器(processor),那么请求通道就是处理器与请求处理线程和KafkaApis交换数据的地方:如果处理器往请求通道添加请求,请求处理线程和KafkaApis都.

2021-04-15 18:51:54 16

原创 2.2.2 处理器使用选择器的轮询处理网络请求

2.2.2 处理器使用选择器的轮询处理网络请求接收器采用Round-Robin的方式分配客户端的SocketChannel给多个处理器,每个处理器都会有多个SocketChannel,对应多个客户端连接。就像NetworkClient中用一个选择器管理多个服务端的连接,服务端的每个处理器也都使用一个选择器管理多个客户端连接。处理器接受一个新的SocketChannel通道连接时,先将其放入阻塞队列,然后唤醒选择器线程开始工作。回顾客户端连接服务端时会创建Kafka通道,这里服务端的处理器也会为Socke

2021-04-15 17:50:46 14

原创 2.1.4 选择器处理网络请求

2.1.4 选择器处理网络请求生产者客户端会按照节点对消息进行分组,每个节点对应一个客户端请求,那么一个生产者客户端需要管理到多个服务端节点的网络连接。 涉及网络通信时, 一般使用选择器模式 。 选择器使用JavaNIO异步非阻塞方式管理连接和读写请求,它用单个线程就可以管理多个网络连接通道 。 使用选择器的好处是:生产者客户端只需要使用一个选择器,就可以同时和Kafka集群的多个服务端进行网络通信。 为了更好地理解Kafka的网络层通信方式,我们先来复习下Java NIO的一些重要概念。Socket

2021-04-15 16:55:23 19

原创 2.1.3 客户端网络连接对象

2.1.3 客户端网络连接对象客户端网络连接对象( Netwo 「kCllent )管理了客户端和服务端之间的 网络通信,包括连接的建立、发送客户端请求 、 读取客户端响应 。 回顾下2 . 1.2节中第 1小节“从记录收集器获取数据”部分,发送线程的run ()方法中会调用 Netwo「kCli.ent的3个方法 ,如下 。ready ()方法。从记录收集器获取准备完毕的节点,并连接所有准备好的节点 ;send ()方法。为每个节点创建一个客户端请求 , 将请求暂存到节点对应的通道 中;poll

2021-04-15 12:21:15 21

kingbase8-8.2.0.jar

kingbase8-8.2.0.jar,是链接人大金仓数据库的jar文件

2021-01-13

JVM脑图-必须名称要十个字

JVM脑图

2021-03-11

java-pdf.rar

java-pdf.rar

2021-03-11

redis-PDF.rar

redis-PDF.rar

2021-03-11

ePass1000ND 开发包.rar

对ukey中双向认证的key进行正删查,ukey插上电脑后自动识别ukey中的证书

2020-10-14

https双向认证ukey管理软件

https双向认证ukey管理软件

2020-10-14

mysql-5.5.20-winx64

mysql-5.5.20-winx64

2016-09-01

mysql_5.6.24_winx64

mysql_5.6.24_winx64

2016-09-01

测试驱动开发(中文完整版-带书签)

测试驱动开发(中文完整版-带书签)

2016-08-30

clean_code(中文完整版)

clean_code(中文完整版)

2016-08-26

单元测试之道Java版:使用JUnit

单元测试之道Java版:使用JUnit

2016-08-30

Pragmatic Unit Testing

Pragmatic Unit Testing

2016-08-30

navicat for mysql破解版

先安装navicat,然后执行patch navicat指向navicat.exe

2016-07-25

sqlyog10绿色版

sqlyog10绿色版

2016-07-25

Navicat for MySQL绿色版

Navicat for MySQL绿色版

2016-09-01

water___Wang的留言板

发表于 2020-01-02 最后回复 2020-01-02

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人 TA的粉丝

提示
确定要删除当前文章?
取消 删除