Exemplo do Kafka Connect com MQTT e MongoDB
1. Visão geral
Ema previous article, tivemos uma introdução rápida ao Kafka Connect, incluindo os diferentes tipos de conectores, recursos básicos do Connect, bem como a API REST.
Neste tutorial, usaremos conectores Kafka para construir um exemplo mais do "mundo real".
Usaremos um conector para coletar dados via MQTT e gravaremos os dados coletados no MongoDB.
2. Configuração usando Docker
UsaremosDocker Compose para configurar a infraestrutura. Isso inclui um broker MQTT como fonte, Zookeeper, um broker Kafka e o Kafka Connect como middleware e, finalmente, uma instância do MongoDB incluindo uma ferramenta GUI como coletor.
2.1. Instalação do conector
Os conectores necessários para o nosso exemplo, uma fonte MQTT e um conector coletor MongoDB, não estão incluídos no Kafka comum ou na Plataforma Confluent.
Como discutimos no artigo anterior, podemos baixar os conectores (MQTT, bem comoMongoDB) do hub Confluent. Depois disso, temos que descompactar os frascos em uma pasta, que montaremos no contêiner Kafka Connect na seção seguinte.
Vamos usar a pasta/tmp/custom/jars para isso. Temos que mover os frascos para lá antes de iniciar a pilha de composição na seção a seguir, pois o Kafka Connect carrega conectores online durante a inicialização.
2.2. Arquivo Docker Compose
Descrevemos nossa configuração como um simples arquivo de composição do Docker, que consiste em seis contêineres:
version: '3.3'
services:
mosquitto:
image: eclipse-mosquitto:1.5.5
hostname: mosquitto
container_name: mosquitto
expose:
- "1883"
ports:
- "1883:1883"
zookeeper:
image: zookeeper:3.4.9
restart: unless-stopped
hostname: zookeeper
container_name: zookeeper
ports:
- "2181:2181"
environment:
ZOO_MY_ID: 1
ZOO_PORT: 2181
ZOO_SERVERS: server.1=zookeeper:2888:3888
volumes:
- ./zookeeper/data:/data
- ./zookeeper/datalog:/datalog
kafka:
image: confluentinc/cp-kafka:5.1.0
hostname: kafka
container_name: kafka
ports:
- "9092:9092"
environment:
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181"
KAFKA_BROKER_ID: 1
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
volumes:
- ./kafka/data:/var/lib/kafka/data
depends_on:
- zookeeper
kafka-connect:
image: confluentinc/cp-kafka-connect:5.1.0
hostname: kafka-connect
container_name: kafka-connect
ports:
- "8083:8083"
environment:
CONNECT_BOOTSTRAP_SERVERS: "kafka:9092"
CONNECT_REST_ADVERTISED_HOST_NAME: connect
CONNECT_REST_PORT: 8083
CONNECT_GROUP_ID: compose-connect-group
CONNECT_CONFIG_STORAGE_TOPIC: docker-connect-configs
CONNECT_OFFSET_STORAGE_TOPIC: docker-connect-offsets
CONNECT_STATUS_STORAGE_TOPIC: docker-connect-status
CONNECT_KEY_CONVERTER: org.apache.kafka.connect.json.JsonConverter
CONNECT_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter
CONNECT_INTERNAL_KEY_CONVERTER: "org.apache.kafka.connect.json.JsonConverter"
CONNECT_INTERNAL_VALUE_CONVERTER: "org.apache.kafka.connect.json.JsonConverter"
CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR: "1"
CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR: "1"
CONNECT_STATUS_STORAGE_REPLICATION_FACTOR: "1"
CONNECT_PLUGIN_PATH: '/usr/share/java,/etc/kafka-connect/jars'
CONNECT_CONFLUENT_TOPIC_REPLICATION_FACTOR: 1
volumes:
- /tmp/custom/jars:/etc/kafka-connect/jars
depends_on:
- zookeeper
- kafka
- mosquitto
mongo-db:
image: mongo:4.0.5
hostname: mongo-db
container_name: mongo-db
expose:
- "27017"
ports:
- "27017:27017"
command: --bind_ip_all --smallfiles
volumes:
- ./mongo-db:/data
mongoclient:
image: mongoclient/mongoclient:2.2.0
container_name: mongoclient
hostname: mongoclient
depends_on:
- mongo-db
ports:
- 3000:3000
environment:
MONGO_URL: "mongodb://mongo-db:27017"
PORT: 3000
expose:
- "3000"
O contêinermosquitto fornece um broker MQTT simples baseado no Eclipse Mosquitto.
Os contêinereszookeeperekafka definem um cluster Kafka de nó único.
kafka-connect define nosso aplicativo Connect no modo distribuído.
Por fim,mongo-db define nosso banco de dados coletor, assim como omongoclient baseado na web, que nos ajuda a verificar se os dados enviados chegaram corretamente ao banco de dados.
Podemos iniciar a pilha usando o seguinte comando:
docker-compose up
3. Configuração do Conector
Como o Kafka Connect agora está em funcionamento, agora podemos configurar os conectores.
3.1. Configurar Conector de Origem
Vamos configurar o conector de origem usando a API REST:
curl -d @/connect-mqtt-source.json -H "Content-Type: application/json" -X POST http://localhost:8083/connectors
Nosso arquivoconnect-mqtt-source.json tem a seguinte aparência:
{
"name": "mqtt-source",
"config": {
"connector.class": "io.confluent.connect.mqtt.MqttSourceConnector",
"tasks.max": 1,
"mqtt.server.uri": "tcp://mosquitto:1883",
"mqtt.topics": "example",
"kafka.topic": "connect-custom",
"value.converter": "org.apache.kafka.connect.converters.ByteArrayConverter",
"confluent.topic.bootstrap.servers": "kafka:9092",
"confluent.topic.replication.factor": 1
}
}
Existem algumas propriedades que não usamos antes:
-
mqtt.server.uri é o ponto final ao qual nosso conector se conectará
-
mqtt.topics é o tópico MQTT que nosso conector assinará
-
kafka.topic define o tópico Kafka para o qual o conector enviará os dados recebidos
-
value.converter define um conversor que será aplicado à carga recebida. Precisamos doByteArrayConverter, pois o Conector MQTT usa Base64 por padrão, enquanto queremos usar texto simples
-
confluent.topic.bootstrap.servers é exigido pela versão mais recente do conector
-
O mesmo se aplica aconfluent.topic.replication.factor: ele define o fator de replicação para um tópico interno do Confluente - como temos apenas um nó em nosso cluster, temos que definir esse valor para 1
3.2. Conector de fonte de teste
Vamos fazer um teste rápido publicando uma mensagem curta para o corretor MQTT:
docker run \
-it --rm --name mqtt-publisher --network 04_custom_default \
efrecon/mqtt-client \
pub -h mosquitto -t "example" -m "{\"id\":1234,\"message\":\"This is a test\"}"
E se ouvirmos o tópico,connect-custom:
docker run \
--rm \
confluentinc/cp-kafka:5.1.0 \
kafka-console-consumer --network 04_custom_default --bootstrap-server kafka:9092 --topic connect-custom --from-beginning
então devemos ver nossa mensagem de teste.
3.3. Configuração do conector coletor
Em seguida, precisamos do nosso conector de coletor. Vamos usar novamente a API REST:
curl -d @/connect-mongodb-sink.json -H "Content-Type: application/json" -X POST http://localhost:8083/connectors
Nosso arquivoconnect-mongodb-sink.json tem a seguinte aparência:
{
"name": "mongodb-sink",
"config": {
"connector.class": "at.grahsl.kafka.connect.mongodb.MongoDbSinkConnector",
"tasks.max": 1,
"topics": "connect-custom",
"mongodb.connection.uri": "mongodb://mongo-db/test?retryWrites=true",
"mongodb.collection": "MyCollection",
"key.converter": "org.apache.kafka.connect.json.JsonConverter",
"key.converter.schemas.enable": false,
"value.converter": "org.apache.kafka.connect.json.JsonConverter",
"value.converter.schemas.enable": false
}
}
Temos as seguintes propriedades específicas do MongoDB aqui:
-
mongodb.connection.uri contém a string de conexão para nossa instância do MongoDB
-
mongodb.collection define a coleção
-
Como o conector MongoDB está esperando JSON, temos que definirJsonConverter parakey.converterevalue.converter
-
E também precisamos de JSON sem esquema para MongoDB, então temos que definirkey.converter.schemas.enable evalue.converter.schemas.enable parafalse
3.4. Conector de coletor de teste
Como nosso tópicoconnect-custom já contém mensagens do teste do conector MQTT,the MongoDB connector should have fetched them directly after creation.
Portanto, devemos encontrá-los imediatamente em nosso MongoDB. We can use the web interface for that, by opening the URL http://localhost:3000/. Após o login, podemos selecionar nossoMyCollection à esquerda, pressionarExecute, e nossa mensagem de teste deve ser exibida.
3.5. Teste ponta a ponta
Agora, podemos enviar qualquer estrutura JSON usando o cliente MQTT:
{
"firstName": "John",
"lastName": "Smith",
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "New York",
"state": "NY",
"postalCode": "10021"
},
"phoneNumber": [{
"type": "home",
"number": "212 555-1234"
}, {
"type": "fax",
"number": "646 555-4567"
}],
"gender": {
"type": "male"
}
}
O MongoDB suporta documentos JSON sem esquema e, como desabilitamos os esquemas para o nosso conversor, qualquer estrutura é imediatamente passada através da nossa cadeia de conectores e armazenada no banco de dados.
Novamente, podemos usar a interface da web emhttp://localhost:3000/.
3.6. Limpar
Assim que terminarmos, podemos limpar nosso experimento e remover os dois conectores:
curl -X DELETE http://localhost:8083/connectors/mqtt-source
curl -X DELETE http://localhost:8083/connectors/mongodb-sink
Depois disso, podemos encerrar a pilha Compose comCtrl + C.
4. Conclusão
Neste tutorial, criamos um exemplo usando o Kafka Connect, para coletar dados via MQTT e gravar os dados coletados no MongoDB.
Como sempre, os arquivos de configuração podem ser encontrados emon GitHub.