Kafka java api-生产者代码、高性能吞吐
来源:互联网 发布:tcp网络调试助手 编辑:程序博客网 时间:2024/05/18 03:47
前面做过命令行让生产者发送消息,现在使用java api来进行消息的生产,以及解释kafka高性能是如何实现(来源于学习资料)。
使用shell创建topic和发送消息如下:
#参数:zookeeper连接地址和端口号,副本数(包括自身),使用几个partition,topic的名称[root@mini1 bin]# ./kafka-topics.sh --create --zookeeper mini1:2181 --replication-factor 2 --partitions 3 --topic orderMqCreated topic "orderMq".[root@mini1 bin]# kafka-console-producer.sh --broker-list mini1:9092 --topic orderMqhello tomhi jerryspring hhaahxixinini
下面使用java api来发送消息
注:如果topic已经存在那么肯定就不创建了,但是不存在则会创建。
public class KafkaProducerSimple { public static void main(String[] args) { /** * 1、指定当前kafka producer生产的数据的目的地 * 创建topic可以输入以下命令,在kafka集群的任一节点进行创建。 * bin/kafka-topics.sh --create --zookeeper mini1:2181 --replication-factor 2 --partitions 3 --topic test */ String TOPIC = "orderMQ"; /** * 2、读取配置文件 */ Properties props = new Properties(); /* * key.serializer.class默认为serializer.class key的序列化使用哪个类 */ props.put("serializer.class", "kafka.serializer.StringEncoder"); /* * kafka broker对应的主机,格式为host1:port1,host2:port2 */ props.put("metadata.broker.list", "mini1:9092,mini2:9092,mini3:9092"); /* * request.required.acks,设置发送数据是否需要服务端的反馈,有三个值0,1,-1 * 0,意味着producer永远不会等待一个来自broker的ack,这就是0.7版本的行为。 * 这个选项提供了最低的延迟,但是持久化的保证是最弱的,当server挂掉的时候会丢失一些数据。 * 1,意味着在leader replica已经接收到数据后,producer会得到一个ack。 * 这个选项提供了更好的持久性,因为在server确认请求成功处理后,client才会返回。 * 如果刚写到leader上,还没来得及复制leader就挂了,那么消息才可能会丢失。 * -1,意味着在所有的ISR都接收到数据后,producer才得到一个ack。 * 这个选项提供了最好的持久性,只要还有一个replica存活,那么数据就不会丢失 */ props.put("request.required.acks", "1"); /* * 可选配置,如果不配置,则使用默认的partitioner partitioner.class * 默认值:kafka.producer.DefaultPartitioner * 用来把消息分到各个partition中,默认行为是对key进行hash。 */ props.put("partitioner.class", "com.scu.kafka.MyLogPartitioner");// props.put("partitioner.class", "kafka.producer.DefaultPartitioner"); /** * 3、通过配置文件,创建生产者 */ Producer<String, String> producer = new Producer<String, String>(new ProducerConfig(props)); /** * 4、通过for循环生产数据 */ for (int messageNo = 1; messageNo < 100000; messageNo++) { /** * 5、调用producer的send方法发送数据 * 注意:这里需要指定 partitionKey,用来配合自定义的MyLogPartitioner进行数据分发 */ producer.send(new KeyedMessage<String, String>(TOPIC, messageNo + "", "appid" + UUID.randomUUID() + "itcast")); } }}
public class MyLogPartitioner implements Partitioner { private static Logger logger = Logger.getLogger(MyLogPartitioner.class); public MyLogPartitioner(VerifiableProperties props) { } /** * * @param obj 传来的key 用它来进行hash分到partition * @param numPartitions 几个partition 如果集群中已存在该topic,那么partition数为原本存在数,否则默认是2 * @return 生产到哪个partition */ public int partition(Object obj, int numPartitions) { //使用下面被注释掉的代码,则类似于hadoop的partition分发方式,hash取模去发到对应序号的partition,这里使用1则表示发送到orderMQ-1的topic// return Integer.parseInt(obj.toString())%numPartitions; return 1; }}
启动kafka集群,执行main方法,去集群中查看。
[root@mini1 orderMQ-1]# ll总用量 14296-rw-r--r--. 1 root root 10485760 11月 22 07:53 00000000000000000000.index-rw-r--r--. 1 root root 14610099 11月 22 07:53 00000000000000000000.log[root@mini1 orderMQ-1]# ll总用量 14696-rw-r--r--. 1 root root 10485760 11月 22 07:53 00000000000000000000.index-rw-r--r--. 1 root root 15012813 11月 22 07:53 00000000000000000000.log[root@mini1 orderMQ-1]# ll总用量 15184-rw-r--r--. 1 root root 10485760 11月 22 07:53 00000000000000000000.index-rw-r--r--. 1 root root 15513339 11月 22 07:53 00000000000000000000.log[root@mini1 orderMQ-1]# ll总用量 15448-rw-r--r--. 1 root root 10485760 11月 22 07:53 00000000000000000000.index-rw-r--r--. 1 root root 15783297 11月 22 07:53 00000000000000000000.log[root@mini1 orderMQ-1]# ll总用量 16288-rw-r--r--. 1 root root 10485760 11月 22 07:53 00000000000000000000.index-rw-r--r--. 1 root root 16643559 11月 22 07:53 00000000000000000000.log[root@mini1 orderMQ-1]# ll总用量 16600-rw-r--r--. 1 root root 10485760 11月 22 07:53 00000000000000000000.index-rw-r--r--. 1 root root 16961019 11月 22 07:53 00000000000000000000.log
看到消息在不断增加,由于文件内容乱码就不看了。
kafka高性能吞吐
(来源于学习资料自己并不咋懂网络只能去感受了)
kafka实现高性能吞吐主要就是2个原因:1、使用了pageCache,2、使用了sendfile技术
(1)、pageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用,生成的消息大部分存储在缓存中,大数据环境下,生产和消费都是非常快的,那么基本上大部分操作都能同时在缓存中进行,所以吞吐性能高。具体介绍如下:
不同于Redis和MemcacheQ等内存消息队列,Kafka的设计是把所有的Message都要写入速度低容量大的硬盘,以此来换取更强的存储能力。实际上,Kafka使用硬盘并没有带来过多的性能损失,“规规矩矩”的抄了一条“近道”。
首先,说“规规矩矩”是因为Kafka在磁盘上只做Sequence I/O,由于消息系统读写的特殊性,这并不存在什么问题。关于磁盘I/O的性能,引用一组Kafka官方给出的测试数据(Raid-5,7200rpm):
Sequence I/O: 600MB/s
Random I/O: 100KB/s
所以通过只做Sequence I/O的限制,规避了磁盘访问速度低下对性能可能造成的影响。
接下来我们再聊一聊Kafka是如何“抄近道的”。
首先,Kafka重度依赖底层操作系统提供的PageCache功能。当上层有写操作时,操作系统只是将数据写入PageCache,同时标记Page属性为Dirty。
当读操作发生时,先从PageCache中查找,如果发生缺页才进行磁盘调度,最终返回需要的数据。实际上PageCache是把尽可能多的空闲内存都当做了磁盘缓存来使用。同时如果有其他进程申请内存,回收PageCache的代价又很小,所以现代的OS都支持PageCache。
使用PageCache功能同时可以避免在JVM内部缓存数据,JVM为我们提供了强大的GC能力,同时也引入了一些问题不适用与Kafka的设计。
(2)sendfile技术
PageCache还只是第一步,Kafka为了进一步的优化性能还采用了Sendfile技术。在解释Sendfile之前,首先介绍一下传统的网络I/O操作流程,大体上分为以下4步。
OS 从硬盘把数据读到内核区的PageCache。
用户进程把数据从内核区Copy到用户区。
然后用户进程再把数据写入到Socket,数据流入内核区的Socket Buffer上。
OS 再把数据从Buffer中Copy到网卡的Buffer上,这样完成一次发送。
整个过程共经历两次Context Switch,四次System Call。同一份数据在内核Buffer与用户Buffer之间重复拷贝,效率低下。其中2、3两步没有必要,完全可以直接在内核区完成数据拷贝。这也正是Sendfile所解决的问题,经过Sendfile优化后,整个I/O过程就变成了下面这个样子。
通过以上的介绍不难看出,Kafka的设计初衷是尽一切努力在内存中完成数据交换,无论是对外作为一整个消息系统,或是内部同底层操作系统的交互。如果Producer和Consumer之间生产和消费进度上配合得当,完全可以实现数据交换零I/O。这也就是我为什么说Kafka使用“硬盘”并没有带来过多性能损失的原因。
- Kafka java api-生产者代码、高性能吞吐
- Kafka 高性能吞吐
- Kafka 高性能吞吐揭秘
- Kafka 高性能吞吐揭秘
- Kafka 高性能吞吐揭秘
- Kafka 高性能吞吐揭秘
- Kafka之Java API-生产者(Producers)
- Kafka 高吞吐率的实现
- Kafka java api-消费者代码与消费分析、生产者消费者配置文件详解
- kafka系列-kafka调优篇-高并发高吞吐架构设计
- kafka生产者与消费者java代码示例
- kafka 生产者消费者 api接口
- KAFKA生产者消费者API学习
- Java高性能代码
- 构建高性能服务(二)减小锁粒度 提高Java并发吞吐实例
- Kafka是如何实现高吞吐率的
- Kafka是如何实现高吞吐率的
- java写kafka的生产者与消费者代码
- 评论抓取:Python爬取微信在APPStore上的评论内容及星级
- fopen
- PHP魔术方法:Typecho反序列化漏洞
- recyclerview多条目加载
- 初学logistic回归
- Kafka java api-生产者代码、高性能吞吐
- 最新版MySQL操作---语句规范
- SpringBoot小程序
- 我的学习资源
- ES优化总结(特别是在bulk大量数据到ES的时候),持续续更新中。。。。
- mongo我的库
- Spring Boot实现文件上传
- python中join()函数
- Could not update Activiti database schema: unknown version from database: '5.20.0.1'