领取阿里云服务器优惠券
上接Kafka解惑之Old Producer(1)—— Beginning
欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。
一下子扩展的有点多,我们还是先回到DefaultEventHandler上来,当调用producer.send方法发送消息的时候,紧接着就是调用DefaultEventHandler的handle方法。下面是handle方法的主要内容,虽然行数有点多,但是这是Producer中最最核心的一块,需要反复研磨,方能一探究竟:
def handle(events: Seq[KeyedMessage[K,V]]) {
val serializedData = serialize(events)
var outstandingProduceRequests = serializedData
var remainingRetries = config.messageSendMaxRetries + 1
val correlationIdStart = correlationId.get()
while (remainingRetries > 0 && outstandingProduceRequests.nonEmpty) {
topicMetadataToRefresh ++= outstandingProduceRequests.map(_.topic)
if (topicMetadataRefreshInterval >= 0 &&
Time.SYSTEM.milliseconds - lastTopicMetadataRefreshTime > topicMetadataRefreshInterval) {
CoreUtils.swallowError(brokerPartitionInfo.updateInfo(topicMetadataToRefresh.toSet, correlationId.getAndIncrement))
sendPartitionPerTopicCache.clear()
topicMetadataToRefresh.clear
lastTopicMetadataRefreshTime = Time.SYSTEM.milliseconds
}
outstandingProduceRequests = dispatchSerializedData(outstandingProduceRequests)
if (outstandingProduceRequests.nonEmpty) {
Thread.sleep(config.retryBackoffMs)
CoreUtils.swallowError(brokerPartitionInfo.updateInfo(outstandingProduceRequests.map(_.topic).toSet, correlationId.getAndIncrement))
sendPartitionPerTopicCache.clear()
remainingRetries -= 1
producerStats.resendRate.mark()
}
}
}
注意handle方法的参数是个Seq[KeyedMessage]类型的,而不是KeyedMessage。虽然Demo中用的只是单个KeyedMessage,最后调用底层的handle方法都是转换为Seq类型,你可以把Seq看成是java中的List,在Scala中表示序列,指的是一类具有一定长度的可迭代访问的对象,其中每个元素均带有一个从0开始计数的固定索引位置。
这个handle方法中首先是调用serialize(events)方法对消息进行序列化操作,这个容易理解,就是通过serializer.class参数指定的序列化类进行序列化。
其次获取所发送消息对应的元数据信息,然后将一坨消息(也有可能是一条)转换为HashMap[Int, collection.mutable.Map[TopicAndPartition, Seq[KeyedMessage[K,Message]]]]格式,其中key:Int表示broker的id,value是TopicAndPartition与消息集的Map,对应的方法为dispatchSerializedData()。因为客户端发消息是发到对应的broker上,所以要对每个消息找出对应的leader副本所在的broker的位置,然后将要发送的消息集分类,每个broker对应其各自所要接收的消息。而TopicAndPartition是针对broker上的存储层的,每个TopicAndPartition对应特定的当前的存储文件(Segment文件),将消息写入到存储文件中。
获取元数据信息并不是每次发送消息都要向metadata.broker.list所指定地址中的服务索要拉取,而是向缓存中的元数据进行拉取,拉取失败后才向metadata.broker.list所指定地址中的服务发送元数据更新的请求进行拉取。很多朋友会把metadata.broker.list看成是broker的地址,这个不完全正确,官网解释:
This is for bootstrapping and the producer will only use it for getting metadata (topics, partitions and replicas). The socket connections for sending the actual data will be established based on the broker information returned in the metadata. The format is host1:port1,host2:port2, and the list can be a subset of brokers or a VIP pointing to a subset of brokers.
因为这个地址只提供给客户端拉取元数据信息之用,而剩下的动作比如发送消息是通过与元数据信息中的broker地址建立连接之后再进行操作,这也就意味着metadata.broker.list可以和broker的真正地址没有任何交集。你完全可以为metadata.broker.list配置一个“伪装”接口地址,这个接口配合kafka的传输格式并提供相应的元数据信息,这样方便集中式的配置管理(可以集成到配置中心中)。为了简化说明,我们姑且可以狭义的认为metadata.broker.list指的就是kafka broker的地址。
缓存中的元数据每隔topic.metadata.refresh.interval.ms才去broker拉取元数据信息,可以参考上面大段源码中的if语句:
if (topicMetadataRefreshInterval >= 0 &&
Time.SYSTEM.milliseconds - lastTopicMetadataRefreshTime > topicMetadataRefreshInterval)
1
2
topic.metadata.refresh.interval.ms参数的默认值是600*1000ms,也就是10分钟。如果设置为0,则每次发送消息时都要先向broker拉取元数据信息;如果设置为负数,那么只有在元数据获取失败的情况下才会请求元数据信息。由于这个老版的Scala的Producer请求元数据和发送消息是在同一个线程中完成的,所以此处会有延迟的隐患,具体的笔者会在后面的案例分析环节为大家详细介绍。
接下去所要做的工作就是查看是否需要压缩,如果客户端设置了压缩,则根据compression.type参数配置的压缩方式对消息进行压缩处理。0.8.2.x版本支持gzip和snappy的压缩方式,1.0.0版本还支持lz4的压缩方式。compression.type参数的默认值值none,即不需要压缩。
最后根据brokerId分组发送消息。这个分组发送的过程就与ProducerPool有关了,我们前面提到在实例化Producer的时候引入了DefaultEventHandler和ProducerPool。这个ProducerPool保存的是生产者和broker的连接,每个连接对应一个SyncProducer对象。SyncProducer包装了NIO网络层的操作,每个SyncProducer都是一个与对应broker的socket连接,是真正发送消息至broker中的执行者。
@deprecated("This class has been deprecated and will be removed in a future release.", "0.10.0.0")
class ProducerPool(val config: ProducerConfig) extends Logging {
private val syncProducers = new HashMap[Int, SyncProducer]
1
2
3
当调用最上层的send方法发送消息的时候,下面的执行顺序为DefaultEventHandler.handle()->DefaultEventHandler.dispatchSerializedData()->DefaultEventHandler.send()。在底层的DefaultEventHandler.send方法定义为:
private def send(brokerId: Int, messagesPerTopic: collection.mutable.Map[TopicAndPartition, ByteBufferMessageSet])
1
这个方法就需要根据brokerId从ProducerPool中的HashMap中找到对应SyncProducer,然后在将“messagesPerTopic: collection.mutable.Map[TopicAndPartition, ByteBufferMessageSet]”这个消息发送到SyncProducer对应的broker上。如果在获取缓存中的元数据失败的时候就需要重新向broker拉取元数据,或者定时(topic.metadata.refresh.interval.ms)向broker端请求元数据的数据,都会有可能更新ProducerPool的信息,对应的方法为ProducerPool.updateProducer():
def updateProducer(topicMetadata: Seq[TopicMetadata]) {
val newBrokers = new collection.mutable.HashSet[BrokerEndPoint]
topicMetadata.foreach(tmd => {
tmd.partitionsMetadata.foreach(pmd => {
if(pmd.leader.isDefined) {
newBrokers += pmd.leader.get
}
})
})
lock synchronized {
newBrokers.foreach(b => {
if(syncProducers.contains(b.id)){
syncProducers(b.id).close()
syncProducers.put(b.id, ProducerPool.createSyncProducer(config, b))
} else
syncProducers.put(b.id, ProducerPool.createSyncProducer(config, b))
})
}
}
会Java的读者看这段代码的时候应该能看出来个90%以上,解释下这段代码:首先是找到更新的元数据中所有的brorker(更具体的来说是broker的id、主机地址host和端口号port三元组信息);之后在查到原有的ProducerPool中是否有相应的SyncProducer,如果有则关闭之后再重新建立;如果没有则新建。SyncProducer底层是阻塞式的NIO,所以关闭再建立会有一定程度上的开销,相关细节如下:
channel = SocketChannel.open()
if(readBufferSize > 0)
channel.socket.setReceiveBufferSize(readBufferSize)
if(writeBufferSize > 0)
channel.socket.setSendBufferSize(writeBufferSize)
channel.configureBlocking(true)
channel.socket.setSoTimeout(readTimeoutMs)
channel.socket.setKeepAlive(true)
channel.socket.setTcpNoDelay(true)
channel.socket.connect(new InetSocketAddress(host, port), connectTimeoutMs)
玩过NIO的读者对这段代码相比很是熟络,虽然是scala版的。如果没有接触过NIO,那么可以先看看这一篇:攻破JAVA NIO技术壁垒。
说道这里我们用一副结构图来说明下Old Producer的大致脉络(注:图中的所有操作都是在一个线程中执行的):
欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。
分享资料:
链 接 : https://pan.baidu.com/s/1ihwAYjeMbq1RInmNKeRxqw
提取码: wwsc
- 2020年脑机接口即将落地.pdf
- 2030年科幻落地的前夜:人类如何应对机器觉醒.pdf
- 3D深度视觉产业链全解读 TOF技术或成黑马.pdf
- 5G技术将如何影响全球经济.pdf
- AI三板斧_智东西出品.pdf
- AI产业链解读:老美家大财厚 中国如何才能后发先至.pdf
- AR红包技术层面全解读 引爆场景营销.pdf
- CB Insights发布独角兽英雄榜 揭秘资本寒冬下的生存法则.pdf
- CB Insights起底VC八杰 谁在做独角兽的幕后推手.pdf
- CB Insight发布创业百强榜单 AI成功案例最强盘点.pdf
- GfK 2017一季度VR零售市场报告 全面解读产业盈利模式.pdf
- GFK中国VR零售市场调研报告 平价设备成主力军.pdf
- GSMA移动经济发展态势全解读 亚太+5G成未来钥匙.pdf
- IBM全面解读认知计算:IoT和AI并非全部 行业已经开始盈利.pdf
- IDC:机器人3.0时代开启 细分市场兹待爆发.pdf
- 联合国:2017全球投资报告.pdf
- VR市场现状调研:启动期资金才是王道 2C应用五年内难有突破.pdf
- VR开发者报告:不炒作!我们正经做生意.pdf
- WEF 2017全球风险报告当平缓的经济撞上技术爆炸.pdf
- 中国互联网单车租赁市场专题分析 资本驱动下的圈地战.pdf
- 互联网迎来AI 时代,海外科技巨头争先布局.pdf
- 产业链视角:怎样设计一款全面屏手机.pdf
- 人工智能和工业4.0进行时 机器人创企50强都有谁?.pdf
- 从苹果ARkit看AR未来的黄金五年.pdf
- 企业AI转型价值详解:百亿资本催化的数字鸿沟.pdf
- 企业数字化落地加速 下一波机遇在哪里?.pdf
- 信通院物联网产业深度报告 平台化和数据服务即将爆发.pdf
- 刘强东马云正面杠 新零售时代智慧物流平台战打响.pdf
- 创业公司尸检报告:盈利模式错误 融资失败成致命打击.pdf
- 剧透高通9150 C-V2X.pdf
- 区块链+IPO靠谱吗?解密首次代币众筹的逻辑与隐忧.pdf
- 区块链创投热潮力推技术转化 构建价值互联网.pdf
- 千亿级智能安防市场解读:设备和技术都已经准备好了.pdf
- 华为VR大数据:全面解读2C市场突破口和技术门槛.pdf
- 国内AI技术发展快 资本寒冬不难挨.pdf
- 埃森哲解读5G智慧城市 GDP狂增5000亿美元.pdf
- 如何抓准新能源汽车蓝海的目标用户.pdf
- 学院派发达国家是如何制定AI发展计划的?.pdf
- 已有12+飞行器研发公司 NASA联手FAA推进航空商业化.pdf
- 德勤技术趋势全面盘点:企业如何搭上现代化快车.pdf
- 德勤物联网工业全解读:从“后知后觉”到“先见之明”.pdf
- 战略解读:库克为何入局智能音箱.pdf
- 截至2030年技术爆发点全面预测 3D打印和人工智能火力全开.pdf
- 捷孚凯3C市场报告:手机大卖电脑回血消费走向中高端.pdf
- 摩根大通智能汽车百亿市场深度调研 看23家中国零部件制造商如何突围.pdf
- 数字时代北京深圳创业最强 川渝地区或成第四极经济圈.pdf
- 数据大象流对网络架构发起挑战 MR才是产业的未来 .pdf
- 新能源后补贴时代 自主品牌的“野化”路.pdf
- 新能源浪潮的第二大风口:电能存储.pdf
- 无人机基站——应急通信新方案.pdf
- 普华永道全球科技行业IPO回顾 独角兽缺席导致的冷场.pdf
- 普华永道蓝皮书 全面盘点中国汽车市场新常态.pdf
- 普华永道:15.7万亿美元AI市场的八大入口.pdf
- 新能源后补贴时代 自主品牌的“野化”路.pdf
- 智慧医疗是如何成为AI规模最大,增长最快的领域的?.pdf
- 智能传感器:未来机器的感官 百亿美元的市场.pdf
- 智能语音生态盘点:科技巨头战略布局 两大场景率先爆发.pdf
- 智能音箱市场分析:为什么大家都在抢这个两亿小蛋糕?.pdf
- 毕马威17Q1风投报告:正常化下的VC生存法则.pdf
- 毕马威电子商务深度调研:中国成手机端网购大户 引领社交平台的品牌宣传.pdf
- 毕马威颠覆性技术调研 841名高管共寻突破.pdf
- 毕马威:20个痛点对策看懂金融科技.pdf
- 深度学习成最大爆点 巨头们如何构建AI生态.pdf
- 深度解读白宫58页AI白皮书:全面盘点技术、产业和战略.pdf
- 深度:从供需革命看智能手机的七大发展趋势.pdf
- 特斯拉现有及Model3潜在国产产业链梳理.pdf
- 电子消费市场总值缩水又怎样 17年移动互联和可穿戴照样赚个盆满钵.pdf
- 白宫再推人工智能白皮书 技术过渡期应如何应对工种转型.pdf
- 突围新零售电商时代:移动为先 社交互动.pdf
- 维度提升 AR 开启视觉入口时代.pdf
- 美国信息技术产业委员会:14条人工智能政策准则.pdf
- 联合国点名表扬:中国数字支付生态系统是如何实现领先的.pdf
- 致企业管理者:下一场工业革命的十大原则.pdf
- 解密:NB-IoT商用元年的背后推手都有谁?.pdf
- 让李彦宏梭哈的AI+医疗有何神通 产业链报告解读万亿市场.pdf
- 诚实回答:AI产业界现在,究竟在做啥?.pdf
- 谈谈你们都在怕的国内AI人才缺口.pdf
- 谷歌壕无人性收购史:14家公司,260.5亿美元.pdf
- 谷歌自曝无人驾驶核心技术!700亿估值Waymo炼成之谜.pdf
- 软银世界大会:一文读懂孙正义眼中的不久和将来.pdf
- 量子计算创业盘点:无敌是多么寂寞.pdf
- 阿里云服务战略解读:马云如何布张新零售包围圈.pdf
- 高盛史上最全面AI产业盘点 深度解析背后技术.pdf
- 麦肯锡中国市场调研:AI是科技板块的狂欢 传统行业的两难.pdf
- 麦肯锡市场深度观察:如何电动汽车的销售和盈利.pdf
- 麦肯锡深度解读中国AI路的三座大山预言五大战略重点.pdf