netoxi

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理
  27 Posts :: 0 Stories :: 19 Comments :: 0 Trackbacks

公告

Table of contents

· Overview

    · Introduction

    · Use cases

· Manual Setup

    · Assumption

    · Configuration

    · Startup & test

· Principle

    · Topic

    · Distribution

    · Producer

    · Consumer

· Operation

    · Adding topics

    · Modifying topics

    · Removing a topic

    · Graceful shutdown

    · Balancing leadership

    · Checking consumer position

    · Listing consumer groups

    · Infrequently used operations

· API

    · Overview

    · Producer API

    · Consumer API

· Performance tuning


 

Overview

Introduction

1. Apache kafka is distributed streaming platform.

2. Capabilities of streaming platform:

    a) It lets you publish and subscribe to streams of records. It is similar to a message queue or enterprise messaging system.

    b) It lets you store streams of records in a fault-tolerant way.

    c) It lets you process streams of records as they occur.

Use cases

1. Messaging

    a) In comparison to most messaging systems(e.g. ActiveMQ, RocketMQ) Kafka has better throughput, built-in partitioning, replication, and fault-tolerance which makes it a good solution for large scale message processing applications.

2. Website activity tracking

    a) The original use case for Kafka was to be able to rebuild a user activity tracking pipeline as a set of real-time publish-subscribe feeds.

    b) Site activity (page views, searches, or other actions users may take) is published to central topics with one topic per activity type. These feeds are available for subscription for a range of use cases including real-time processing, real-time monitoring, and loading into Hadoop or offline data warehousing systems for offline processing and reporting.

3. Metrics

    a) Kafka is often used for operational monitoring data. This involves aggregating statistics from distributed applications to produce centralized feeds of operational data.

4. Log aggregation

    a) Log aggregation typically collects physical log files off servers and puts them in a central place (a file server or HDFS perhaps) for processing. Kafka abstracts away the details of files and gives a cleaner abstraction of log or event data as a stream of messages. This allows for lower-latency processing and easier support for multiple data sources and distributed data consumption.

    b) In comparison to log-centric systems like Scribe or Flume, Kafka offers equally good performance, stronger durability guarantees due to replication, and much lower end-to-end latency.

5. Stream processing

    a) Many users of Kafka process data in processing pipelines consisting of multiple stages, where raw input data is consumed from Kafka topics and then aggregated, enriched, or otherwise transformed into new topics for further consumption or follow-up processing. Apart from Kafka Streams, alternative open source stream processing tools include Apache Storm and Apache Samza.

6. Event sourcing

    a) Event sourcing is a style of application design where state changes are logged as a time-ordered sequence of records.

7. Commit log

    a) Kafka can serve as a kind of external commit-log for a distributed system. The log helps replicate data between nodes and acts as a re-syncing mechanism for failed nodes to restore their data. The log compaction feature in Kafka helps support this usage. In this usage Kafka is similar to Apache BookKeeper project.

Manual Setup

Assumption

We assume that JDK and Zookeeper have been installed.

Configuration

1. Configure on one server.

tar zxvf kafka_2.10-0.10.2.1.tgz -C /opt/app
cd /opt/app/kafka_2.10-0.10.2.1
vi config/server.properties
broker.id=1 # Unique
log.dirs=/opt/data/kafka.logs # Data directory
default.replication.factor=3
zookeeper.connect=centos1:2181,centos2:2181/kafka # Specify chroot at the end, default chroot is /

num.partitions=8 # Configurations for product server
delete.topic.enable=false
auto.create.topics.enable=false
log.retention.hours=168
min.insync.replicas=2
queued.max.requests=500

2. Copy Kafka directory to the other servers.

scp -r /opt/app/kafka_2.10-0.10.2.1 hadoop@centos2:/opt/app
scp -r /opt/app/kafka_2.10-0.10.2.1 hadoop@centos3:/opt/app

3. Remember to configure 'broker.id' on the other servers.

vi config/server.properties

Startup & test

4. Startup daemon on all servers.

bin/kafka-server-start.sh -daemon config/server.properties
jps
Kafka

5. Test.

bin/kafka-topics.sh --create --zookeeper centos1:2181,centos2:2181,centos3:2181/kafka --replication-factor 2 --partitions 2 --topic test-topic
bin/kafka-topics.sh --list --zookeeper centos1:2181,centos2:2181,centos3:2181/kafka
bin/kafka-topics.sh --describe --zookeeper centos1:2181,centos2:2181,centos3:2181/kafka --topic test-topic
bin/kafka-console-producer.sh --broker-list centos1:9092,centos2:9092,centos3:9092 --topic test-topic
bin/kafka-console-consumer.sh --bootstrap-server centos1:9092,centos2:9092,centos3:9092 --topic test-topic --from-beginning

6. Shutdown daemon on all servers.

bin/kafka-server-stop.sh

Principle

Topic

1. A topic is a category or feed name to which records are published.

2. Partition

    a) Each partition is an ordered, immutable sequence of records that is continually appended to—a structured commit log. The records in the partitions are each assigned a sequential id number called the offset that uniquely identifies each record within the partition.

    b) The partitions in the log serve several purposes. First, they allow the log to scale beyond a size that will fit on a single server. Each individual partition must fit on the servers that host it, but a topic may have many partitions so it can handle an arbitrary amount of data. Second they act as the unit of parallelism—more on that in a bit.

3. Storage

    a) The Kafka cluster retains all published records—whether or not they have been consumed—using a configurable retention period. For example, if the retention policy is set to two days, then for the two days after a record is published, it is available for consumption, after which it will be discarded to free up space. Kafka's performance is effectively constant with respect to data size so storing data for a long time is not a problem.

4. Offset control

    a) In fact, the only metadata retained on a per-consumer basis is the offset or position of that consumer in the log. This offset is controlled by the consumer: normally a consumer will advance its offset linearly as it reads records, but, in fact, since the position is controlled by the consumer it can consume records in any order it likes. For example a consumer can reset to an older offset to reprocess data from the past or skip ahead to the most recent record and start consuming from "now".

Distribution

Each partition has one server which acts as the "leader" and zero or more servers which act as "followers". The leader handles all read and write requests for the partition while the followers passively replicate the leader. If the leader fails, one of the followers will automatically become the new leader. Each server acts as a leader for some of its partitions and a follower for others so load is well balanced within the cluster.

Producer

The producer is responsible for choosing which record to assign to which partition within the topic. This can be done in a round-robin fashion simply to balance load or it can be done according to some semantic partition function (say based on some key in the record).

Consumer

1. Consumers label themselves with a consumer group name, and each record published to a topic is delivered to one consumer instance within each subscribing consumer group. Consumer instances can be in separate processes or on separate machines.

2. If all the consumer instances have the same consumer group, then the records will effectively be load balanced over the consumer instances.

3. If all the consumer instances have different consumer groups, then each record will be broadcast to all the consumer processes.

4. This process of maintaining membership in the group is handled by the Kafka protocol dynamically. If new instances join the group they will take over some partitions from other members of the group; if an instance dies, its partitions will be distributed to the remaining instances.

5. Kafka only provides a total order over records within a partition, not between different partitions in a topic. Per-partition ordering combined with the ability to partition data by key is sufficient for most applications. However, if you require a total order over records this can be achieved with a topic that has only one partition, though this will mean only one consumer process per consumer group.

Operation

Adding topics

1. Command:

bin/kafka-topics.sh --zookeeper zk_host:port/chroot --create --topic my_topic_name --partitions 20 --replication-factor 3 --config x=y

2. You have the option of either adding topics manually or having them be created automatically when data is first published to a non-existent topic.

3. The replication factor controls how many servers will replicate each message that is written. We recommend you use a replication factor of 2 or 3 so that you can transparently bounce machines without interrupting data consumption.

4. Each sharded partition log is placed into its own folder under the Kafka log directory. The name of such folders consists of the topic name, appended by a dash (-) and the partition id.

Modifying topics

1. Commands:

    a) Add partitions

bin/kafka-topics.sh --zookeeper zk_host:port/chroot --alter --topic my_topic_name --partitions 40

    b) Add configs

bin/kafka-topics.sh --zookeeper zk_host:port/chroot --alter --topic my_topic_name --config x=y

    c) Remove a config

bin/kafka-topics.sh --zookeeper zk_host:port/chroot --alter --topic my_topic_name --delete-config x

2. Adding partitions doesn't change the partitioning of existing data so this may disturb consumers if they rely on that partition. That is if data is partitioned by 'hash(key) % number_of_partitions' then this partitioning will potentially be shuffled by adding partitions but Kafka will not attempt to automatically redistribute data in any way.

3. Kafka does not currently support reducing the number of partitions for a topic.

Removing a topic

1. Command

bin/kafka-topics.sh --zookeeper zk_host:port/chroot --delete --topic my_topic_name

2. Topic deletion option is disabled by default. To enable it set the server configdelete.

delete.topic.enable=true

Graceful shutdown

1. The Kafka cluster will automatically detect any broker shutdown or failure and elect new leaders for the partitions on that machine.

2. Note that controlled shutdown will only succeed if all the partitions hosted on the broker have replicas (i.e. the replication factor is greater than 1 and at least one of these replicas is alive). This is generally what you want since shutting down the last replica would make that topic partition unavailable.

3. Controlled leadership migration requires using a special setting:

controlled.shutdown.enable=true

Balancing leadership

1. Whenever a broker stops or crashes leadership for that broker's partitions transfers to other replicas. To avoid this, Kafka has a notion of preferred replicas. If the list of replicas for a partition is 1,5,9 then node 1 is preferred as the leader to either node 5 or 9 because it is earlier in the replica list.

2. You can have the Kafka cluster try to restore leadership to the restored replicas by running the command:

bin/kafka-preferred-replica-election.sh --zookeeper zk_host:port/chroot

3. Configure Kafka to do this automatically:

auto.leader.rebalance.enable=true

Checking consumer position

1. Before 0.9.0.0

bin/kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --zookeeper localhost:2181 --group test

2. Since 0.9.0.0

bin/kafka-consumer-groups.sh --bootstrap-server broker1:9092 --describe --group test-consumer-group

3. If you are using the old high-level consumer and storing the group metadata in ZooKeeper (i.e. 'offsets.storage=zookeeper')

bin/kafka-consumer-groups.sh --zookeeper localhost:2181 --describe --group test-consumer-group

Listing consumer groups

1. List all consumer groups across all topics:

bin/kafka-consumer-groups.sh --bootstrap-server broker1:9092 --list

2. If you are using the old high-level consumer and storing the group metadata in ZooKeeper (i.e. 'offsets.storage=zookeeper')

bin/kafka-consumer-groups.sh --zookeeper localhost:2181 --list

Infrequently used operations

The following infrequently used operations refer to official documentation.

    a) Migrating data to new machines

    b) Increasing replication factor

    c) Limiting bandwidth usage during data migration

    d) Setting quotas

API

Overview

1. Four core APIs:

    a) The Producer API allows an application to publish a stream of records to one or more Kafka topics.

    b) The Consumer API allows an application to subscribe to one or more topics and process the stream of records produced to them.

    c) The Streams API allows an application to act as a stream processor, consuming an input stream from one or more topics and producing an output stream to one or more output topics, effectively transforming the input streams to output streams.

    d) The Connector API allows building and running reusable producers or consumers that connect Kafka topics to existing applications or data systems. For example, a connector to a relational database might capture every change to a table.

2. Maven dependency for producer API and consumer API.

<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>0.10.2.0</version>
</dependency>

Producer API

1. The producer is thread safe and sharing a single producer instance across threads will generally be faster than having multiple instances.

2. The producer consists of a pool of buffer space that holds records that haven't yet been transmitted to the server as well as a background I/O thread that is responsible for turning these records into requests and transmitting them to the cluster. Failure to close the producer after use will leak these resources.

3. The send() method is asynchronous. When called it adds the record to a buffer of pending record sends and immediately returns. This allows the producer to batch together individual records for efficiency.

4. Producer provides software load balancing through an optionally user-specified kafka.producer.Partitioner.

5. An example.

 1 import java.util.Properties;
 2 import java.util.UUID;
 3 
 4 import org.apache.kafka.clients.producer.KafkaProducer;
 5 import org.apache.kafka.clients.producer.Producer;
 6 import org.apache.kafka.clients.producer.ProducerRecord;
 7 
 8 public class TestProducer {
 9 
10     public static void main(String[] args) {
11         Properties conf = new Properties();
12         conf.put("bootstrap.servers", "centos1:9092,centos2:9092");
13         conf.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
14         conf.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
15         
16         final String topic = "test-topic";
17         Producer<String, String> producer = new KafkaProducer<>(conf);
18         try {
19             for (int index = 0; index < 10000; index++) {
20                 String recordKey = UUID.randomUUID().toString();
21                 String recordValue = UUID.randomUUID().toString();
22                 ProducerRecord<String, String> record = new ProducerRecord<>(topic, recordKey, recordValue);
23                 producer.send(record);
24             }
25             
26         } finally {
27             producer.close();
28         }
29     }
30     
31 }

Consumer API

1. The position of the consumer gives the offset of the next record that will be given out. It will be one larger than the highest offset the consumer has seen in that partition. It automatically advances every time the consumer receives messages in a call to poll(long).

2. The committed position is the last offset that has been stored securely. Should the process fail and restart, this is the offset that the consumer will recover to. The consumer can either automatically commit offsets periodically; or it can choose to control this committed position manually by calling one of the commit APIs (e.g. commitSync and commitAsync).

3. Membership in a consumer group is maintained dynamically: if a process fails, the partitions assigned to it will be reassigned to other consumers in the same group. Similarly, if a new consumer joins the group, partitions will be moved from existing consumers to the new one. This is known as rebalancing the group and is discussed in more detail below. Group rebalancing is also used when new partitions are added to one of the subscribed topics or when a new topic matching a subscribed regex is created. The group will automatically detect the new partitions through periodic metadata refreshes and assign them to members of the group.

4. Automatic offset committing example.

 1 import java.util.Arrays;
 2 import java.util.Properties;
 3 
 4 import org.apache.kafka.clients.consumer.ConsumerRecord;
 5 import org.apache.kafka.clients.consumer.ConsumerRecords;
 6 import org.apache.kafka.clients.consumer.KafkaConsumer;
 7 
 8 public class TestConsumer {
 9 
10     public static void main(String[] args) {
11         Properties conf = new Properties();
12         conf.put("bootstrap.servers", "centos1:9092,centos2:9092");
13         conf.put("group.id", "test-group");
14         conf.put("enable.auto.commit", "true");
15         conf.put("auto.commit.interval.ms", "1000");
16         conf.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
17         conf.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
18 
19         final String topic = "test-topic";
20         KafkaConsumer<String, String> consumer = new KafkaConsumer<>(conf);
21         try {
22             consumer.subscribe(Arrays.asList(topic));
23             while (true) {
24                 ConsumerRecords<String, String> records = consumer.poll(100);
25                 for (ConsumerRecord<String, String> record : records) {
26                     System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
27                 }
28             }
29         } finally {
30             consumer.close();
31         }
32     }
33 
34 }

5. Manual offset committing example.

 1 import java.util.ArrayList;
 2 import java.util.Arrays;
 3 import java.util.List;
 4 import java.util.Properties;
 5 
 6 import org.apache.kafka.clients.consumer.ConsumerRecord;
 7 import org.apache.kafka.clients.consumer.ConsumerRecords;
 8 import org.apache.kafka.clients.consumer.KafkaConsumer;
 9 
10 public class TestConsumer {
11 
12     public static void main(String[] args) {
13         Properties conf = new Properties();
14         conf.put("bootstrap.servers", "centos1:9092,centos2:9092");
15         conf.put("group.id", "test-group");
16         conf.put("enable.auto.commit", "false");
17         conf.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
18         conf.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
19 
20         final String topic = "test-topic";
21         KafkaConsumer<String, String> consumer = new KafkaConsumer<>(conf);
22         try {
23             consumer.subscribe(Arrays.asList(topic));
24             final int minBatchSize = 200;
25             List<ConsumerRecord<String, String>> buffer = new ArrayList<>();
26             while (true) {
27                 ConsumerRecords<String, String> records = consumer.poll(100);
28                 for (ConsumerRecord<String, String> record : records) {
29                     buffer.add(record);
30                 }
31                 if (buffer.size() >= minBatchSize) {
32                     insertIntoDb(buffer);
33                     consumer.commitSync();
34                     buffer.clear();
35                 }
36             }
37         } finally {
38             consumer.close();
39         }
40     }
41     
42     private static void insertIntoDb(List<ConsumerRecord<String, String>> records) {
43         for (ConsumerRecord<String, String> record : records) {
44             System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
45         }
46     }
47 
48 }

6. Manual partition assignment example.

 1 import java.util.Arrays;
 2 import java.util.Properties;
 3 
 4 import org.apache.kafka.clients.consumer.ConsumerRecord;
 5 import org.apache.kafka.clients.consumer.ConsumerRecords;
 6 import org.apache.kafka.clients.consumer.KafkaConsumer;
 7 import org.apache.kafka.common.TopicPartition;
 8 
 9 public class TestConsumer {
10 
11     public static void main(String[] args) {
12         Properties conf = new Properties();
13         conf.put("bootstrap.servers", "localhost:9092,localhost:9093");
14         conf.put("group.id", "test-group");
15         conf.put("enable.auto.commit", "true");
16         conf.put("auto.commit.interval.ms", "1000");
17         conf.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
18         conf.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
19 
20         final String topic = "test-topic";
21         KafkaConsumer<String, String> consumer = new KafkaConsumer<>(conf);
22         try {
23             TopicPartition partition0 = new TopicPartition(topic, 0);
24 //            TopicPartition partition1 = new TopicPartition(topic, 1);
25             consumer.assign(Arrays.asList(partition0));
26             while (true) {
27                 ConsumerRecords<String, String> records = consumer.poll(100);
28                 for (ConsumerRecord<String, String> record : records) {
29                     System.out.printf("partition = %d, offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value());
30                 }
31             }
32         } finally {
33             consumer.close();
34         }
35     }
36 
37 }

7. Controlling consumer's position example.

 1 import java.util.Arrays;
 2 import java.util.List;
 3 import java.util.Properties;
 4 
 5 import org.apache.kafka.clients.consumer.ConsumerRecord;
 6 import org.apache.kafka.clients.consumer.ConsumerRecords;
 7 import org.apache.kafka.clients.consumer.KafkaConsumer;
 8 import org.apache.kafka.common.TopicPartition;
 9 
10 public class TestConsumer {
11 
12     public static void main(String[] args) {
13         Properties conf = new Properties();
14         conf.put("bootstrap.servers", "localhost:9092,localhost:9093");
15         conf.put("group.id", "test-group");
16         conf.put("enable.auto.commit", "true");
17         conf.put("auto.commit.interval.ms", "1000");
18         conf.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
19         conf.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
20 
21         final String topic = "test-topic";
22         KafkaConsumer<String, String> consumer = new KafkaConsumer<>(conf);
23         try {
24             TopicPartition partition0 = new TopicPartition(topic, 0);
25             TopicPartition partition1 = new TopicPartition(topic, 1);
26             List<TopicPartition> partitions = Arrays.asList(partition0, partition1);
27             consumer.assign(partitions);
28 //            consumer.seekToBeginning(partitions);
29             consumer.seek(partition0, 1000);
30             consumer.seek(partition1, 2000);
31             while (true) {
32                 ConsumerRecords<String, String> records = consumer.poll(100);
33                 for (ConsumerRecord<String, String> record : records) {
34                     System.out.printf("partition = %d, offset = %d, key = %s, value = %s%n", record.partition(), record.offset(), record.key(), record.value());
35                 }
36             }
37         } finally {
38             consumer.close();
39         }
40     }
41 
42 }

Performance tuning

1. JDK: use the latest released version of JDK 1.8.

2. Memory: you need sufficient memory to buffer active readers and writers. You can do a back-of-the-envelope estimate of memory needs by assuming you want to be able to buffer for 30 seconds and compute your memory need as write_throughput*30.

3. Disk:

    a) In general disk throughput is the performance bottleneck, and more disks is better.

    b) You can either RAID these drives together into a single volume or format and mount each drive as its own directory. Since Kafka has replication the redundancy provided by RAID can also be provided at the application level.

4. OS:

    a) File descriptor limits: We recommend at least 100000 allowed file descriptors for the broker processes as a starting point.

    b) Max socket buffer size.

5. Filesystem: EXT4 has had more usage, but recent improvements to the XFS filesystem have shown it to have better performance characteristics for Kafka's workload with no compromise in stability.

 

作者:netoxi
出处:http://www.cnblogs.com/netoxi
本文版权归作者和博客园共有,欢迎转载,未经同意须保留此段声明,且在文章页面明显位置给出原文连接。欢迎指正与交流。

 

posted on 2017-09-04 09:01 netoxi 阅读(...) 评论(...) 编辑 收藏