kafka connect是用于与其他数据系统进行数据交换的工具,它具有可扩展性和可靠性,它可以将其他数据系统的数据通过topic的方式导入到kafka,而kafka的导出功能能将topic导出到其他数据系统使用。kafka connect提供了以下功能:
    1.kafka connect通用框架:它包含了一些主流的数据系统框架集成,可以做到简化连接器的开发、部署和管理。
    2.有分布式和单机部署模式:可以向上扩展到支持整个组织的大型集中管理服务,或者向下扩展到开发、测试和小型生产部署。
    3.提供restful接口:可以使用的REST API提交和管理连接器到Kafka Connect集群。
    4.自动偏移量的管理:Kafka Connect可以自动管理偏移提交过程,所以连接器开发人员不需要担心连接器开发中这个容易出错的部分。
    5.默认情况下是分布式和可伸缩的:Kafka Connect建立在现有的组管理协议上。可以添加更多的worker来扩展Kafka Connect集群。
    6.流及批处理集成:利用Kafka现有的功能,Kafka Connect是桥接流和批处理数据系统的理想解决方案。
kafka connect的运行模式有分布式和单机部署2种模式,单机运行的方式如下:

> bin/connect-standalone.sh config/connect-standalone.properties connector1.properties [connector2.properties ...]


对于本地部署,默认情况下使用config/server.properties就可以了,该文件包含了连接参数,序列化格式以及提交偏移量的频率。但是在用于生产部署的时候,无论是单机还是分布式都需要修改以下可能存在的配置:
    1.bootstrap.servers:用于引导连接到Kafka的Kafka服务器列表。
    2.key.converter:用于将key在Kafka connect格式和写入Kafka的序列化形式之间转换的转换器类。如JSON或Avro。
    3.value.converter:用于将value在Kafka connect格式和写入Kafka的序列化形式之间转换的转换器类。如JSON或Avro。
在单机模式下需要特别的配置:
    offset.storage.file.filename:用于保存偏移量的文件。
该配置的参数是为了让Kafka Connect的生产者和消费者访问配置、偏移量和状态主题。为了区分是生产者还是消费者偏移量,可以加上producer.和consumer.来进行区分。需要注意的是安全集群,它需要额外的参数来允许连接。同时这些参数需要在worker配置中设置三次,一次用于管理访问,一次用于Kafka源,一次用于Kafka下沉接口。
从2.3.0开始,kafka客户端的配置可以通过producer.override.和consumer.override.来单独为每个connector进行配置。在分布式的部署上kafka connect实现了负载均衡、动态扩容、任务执行时的故障转移,以及配置和偏移量提交数据的管理,其分布式的运行方式如下:

> bin/connect-distributed.sh config/connect-distributed.properties


如果在kafka connect连接的时候,如果topic还未创建,那么topic将会被创建为默认的默认的分区数以及复制因子。在开启kafka connect集群下,下面的这些参数是需要配置的:
    1.group.id:默认是connect-cluster,这个在集群中是唯一的,不能和消费者的分组id一样。
    2.config.storage.topic:默认是connect-configs,该topic用来存储连接信息和任务配置的,需要注意的是该topic是一个单独的分区,具有高度复制,及压缩主题,这个需要自己手动创建以避免自动创建时的生成多个分区,或者自动配置为删除而不是压缩。
    3.offset.storage.topic:默认值是connect-offsets,该主题用于存放偏移量,它必须有多个分区、可被复制、以及配置为可被压缩。
    4.status.storage.topic:默认值是connect-status,该主题用于存放状态,它必须有多个分区、可被复制、以及配置为可被压缩。
需要注意的是kafka connect的配置在分布式模式下面是不能通过命令行进行,需要调用rest api才能进行创建、修改和销毁连接。

在kafka connect中大多数的配置都是依赖于具体的connector的,单机模式下直接在connect-standalone.properties文件中配置,而分布式则在命令行中通过json的格式进行配置,我们先看下每个connector都需要配置的参数:
    1.name:每个connector的名称,具有唯一性。
    2.connector.class:用于连接的java类,这个类名称可以用全路径名,或者别名来代替。
    3.tasks.max:可用给connector创建的最大task数量。
    4.key.converter:这个是可选项,用于覆盖worker提供的默认key转换器。
    5.value.converter:这个是可选项,用于覆盖worker提供的默认value转换器。
对应接收的connector,还必须指定下面选项的一个:
    1.topics:用逗号分隔的topic列表,用作此connector的输入。
    2.topics.regex:Java正则表达式格式的topic,用作此连接器的输入。

connect可以通过transformations进行配置,以进行轻量级的一次消息修改。它们可以方便地进行数据传递和事件路由。transformation的配置主要在配置文件中进行配置,主要参数如下:
    1.transforms:用来列出需要transformation的别名,并指定在transformation中的顺序。
    2.transforms.$alias.type:用来transformation的全限定名的class。该$alias就是transforms中列出的别名。
    3.transforms.$alias.$transformationSpecificConfig:设置transformation的配置属性。
我们这里给出一个使用JSON格式的例子,在使用之前,对于单机模式,我们需要把下面2个配置改为false:
    key.converter.schemas.enable
    value.converter.schemas.enable
这个时候文件源connector将会把每一行读取为String,我们将每一行放入一个map,然后添加第二个字段来标识事件的起源。我们使用2种transformations:
    1.HoistField:将输入行放置在map中。
    2.InsertField:添加static字段。在本例中,我们将指出该记录来自文件连接器。
添加了transformations后,connect-file-source.properties就是下面这种样式:

name=local-file-source
connector.class=FileStreamSource
tasks.max=1
file=test.txt
topic=connect-test
transforms=MakeMap, InsertSource
transforms.MakeMap.type=org.apache.kafka.connect.transforms.HoistField$Value
transforms.MakeMap.field=line
transforms.InsertSource.type=org.apache.kafka.connect.transforms.InsertField$Value
transforms.InsertSource.static.field=data_source
transforms.InsertSource.static.value=test-file-source


所有行都是以transforms开头,有MakeMap和InsertSource 2个别名的transformations,HoistField需要一个名为“field”的配置,用于映射中包含文件原始字符串的字段名。InsertField指定字段名和要添加的静态值。test.txt包含foo,bar,hello world这3个分行字符串,通过kafka-console-consumer.sh来消费那么得到的结果是:

"foo"
"bar"
"hello world"


而通过connector来消费得到的结果是

{"line":"foo","data_source":"test-file-source"}
{"line":"bar","data_source":"test-file-source"}
{"line":"hello world","data_source":"test-file-source"}


从上面可以看出每一行数据都组装成了json数据,并且都包含了静态key和value。可以使用的transformations有以下几种:
    1.InsertField:使用静态数据或记录元数据添加字段。
    2.ReplaceField:筛选或重命名字段。
    3.MaskField:为类型(0、空字符串等)或自定义替换(仅为非空字符串或数字值)使用有效的空值替换字段。
    4.ValueToKey:用记录值中字段的子集形成的新键替换记录键。
    5.HoistField:将整个事件包装为Struct或map中的单个字段。
    6.ExtractField:从Struct和Map中提取一个特定的字段,并在结果中只包含这个字段。
    7.SetSchemaMetadata:修改模式名称或版本。
    8.TimestampRouter:根据原始主题和时间戳修改记录的主题。当使用sink时,需要根据时间戳写入不同的表或索引。
    9.RegexRouter:根据原始主题、替换字符串和正则表达式修改记录的主题。
    10.Filter:从所有进一步处理中删除消息。它与predicate一起使用,以选择性地过滤某些消息。
具体的transformations类型的包含字段如下,其字段的配置方式如上面的例子:

1.org.apache.kafka.connect.transforms.InsertField
使用来自记录元数据的属性或配置的静态值插入字段。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.InsertField$Key)或value (org.apache.kafka.connect.transforms.InsertField$Value)。下面所有配置的后缀!表示是必填项,而?表示可选(默认值)。

1).offset.field
Kafka偏移量的字段名称-仅适用于sink connectors。

2).partition.field
Kafka分区的字段名。

3).static.field
静态数据字段的名称。

4).static.value
在配置了static.field的时候的static字段值。

5).timestamp.field
记录时间戳字段名。

6).topic.field
kafka主题的字段名称。

2.org.apache.kafka.connect.transforms.ReplaceField
筛选或重命名字段。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.ReplaceField$Key)或value(org.apache.kafka.connect.transforms.ReplaceField$Value)。这个配置值都是list形式的。

1).exclude
排除的字段。这将优先于要包含的字段。

2).include
字段包括。如果指定,将只使用这些字段。

3).renames
字段命名映射。用分号和逗号分隔,如foo:bar,abc:xyz。

3.org.apache.kafka.connect.transforms.MaskField
为类型(0、空字符串等)或自定义替换(仅为非空字符串或数字值)使用有效的空值替换字段。对于数字和字符串字段,可以指定一个可选的替换值,并将其转换为正确的类型。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.MaskField$Key)或value(org.apache.kafka.connect.transforms.MaskField$Value)。

1).fields
要屏蔽的字段名。该值是list形式的。

2).replacement
自定义值替换,这将应用于所有“字段”值(数字或非空字符串值)。

4.org.apache.kafka.connect.transforms.ValueToKey
用记录值中字段的子集形成的新键替换记录键。

1).fields
记录值上要提取的字段名作为记录键。该值是list形式的。

5.org.apache.kafka.connect.transforms.HoistField
将整个事件包装为Struct或map中的单个字段。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.HoistField$Key)或value (org.apache.kafka.connect.transforms.HoistField$Value).

1).field
将在结果Struct或map中创建的单个字段的字段名。

6.org.apache.kafka.connect.transforms.ExtractField
从Struct和Map中提取一个特定的字段,并在结果中只包含这个字段。任何null值都是未经修改的传递。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.ExtractField$Key)或 value(org.apache.kafka.connect.transforms.ExtractField$Value).

1).field
要提取的字段名。

7.org.apache.kafka.connect.transforms.SetSchemaMetadata
修改模式名称或版本,或者2者在记录上key(org.apache.kafka.connect.transforms.SetSchemaMetadata$Key)或value(org.apache.kafka.connect.transforms.SetSchemaMetadata$Value) schema。

1).schema.name
要设置的架构名称。

2).schema.version
要设置的架构版本。

8.org.apache.kafka.connect.transforms.TimestampRouter
根据原始主题和时间戳修改记录的主题。当使用sink时,需要根据时间戳写入不同的表或索引。因为topic字段经常用于确定目标系统中的等效实体名称(例如:数据库表或搜索索引名称)。

1).timestamp.format
通过使用java.text.SimpleDateFormat格式化时间戳格式字符串。默认是yyyyMMdd类型。

2).topic.format
格式字符串,可以分别包含${topic}和${timestamp}作为主题和时间戳的占位符。默认是${topic}-${timestamp}。

9.org.apache.kafka.connect.transforms.RegexRouter
使用配置的正则表达式和替换字符串更新记录主题。在底层是使用java.util.regex.Pattern来实现的,如果模式匹配输入topic,则使用java.util.regex.Matcher#replaceFirst()与替换字符串一起使用,以获得新topic。

1).regex
用于匹配的正则表达式。

2).replacement
替换字符串。

10.org.apache.kafka.connect.transforms.Flatten
Flatten是嵌套的数据结构,通过在每个级别上用一个可配置的分隔符连接字段名,为每个字段生成名称。在存在模式时适用于Struct,在无模式数据时适用于映射。默认分隔符是"."。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.Flatten$Key)或value(org.apache.kafka.connect.transforms.Flatten$Value)。

1).delimiter
当为输出记录生成字段名时,用于在输入记录的字段名之间插入的分隔符。

11.org.apache.kafka.connect.transforms.Cast
将字段或整个键或值转换为特定类型,例如强制一个整数字段的宽度更小。只支持简单的基本类型——整数、浮点数、布尔值和字符串。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.Cast$Key)或value(org.apache.kafka.connect.transforms.Cast$Value)。

1).spec
field1:type,field2:type用于转换map或struct的字段的类型。单个类型来强制转换整个值。有效的类型有int8, int16, int32, int64, float32, float64, boolean和string。该值是list形式的,冒号分隔对的列表,例如foo:bar,abc:xyz。

12.org.apache.kafka.connect.transforms.TimestampConverter
在不同格式之间转换时间戳,例如Unix纪元、字符串和连接日期/时间戳类型。适用于单个字段或整个值。使用为记录设计的具体转换类型key(org.apache.kafka.connect.transforms.TimestampConverter$Key)或value(org.apache.kafka.connect.transforms.TimestampConverter$Value)。

1).target.type
所需的时间戳表示:string, unix, Date, Time, or Timestamp

2).field
包含时间戳的字段,如果整个值都是timestamp,则为空。

3).format
与SimpleDateFormat兼容的时间戳格式。当type=string时,用于生成输出;如果输入是字符串,则用于解析输入。

13.org.apache.kafka.connect.transforms.Filter
删除所有记录,从链中的后续转换中过滤它们。这是为了有条件地过滤出匹配(或不匹配)特定谓词的记录。

14.Predicates
可以用Predicates配置转换,以便只将转换应用于满足某些条件的消息。特别是,当与Filter结合使用时,可以使用transformation predicates选择性地过滤掉某些消息。Predicates需要用到的配置如下:

1).predicates:要应用到某些transformations的predicates 的别名集。

2).predicates.$alias.type:predicates的完全限定类名。

3).predicates.$alias.$predicateSpecificConfig:predicates的配置属性。
所有transformations都具有隐式配置属性predicate和negate,predicates用于匹配的解析,而negate则是用于不匹配的解析,在kafka的connector中有以下3个predicates:

1).TopicNameMatches:使用与特定Java正则表达式匹配的名称匹配主题中的记录。

2).HasHeaderKey:匹配具有具有给定键的标题的记录。

3).RecordIsTombstone:匹配tombstone记录,即带有空值的记录。
关于使用的例子可以在官网介绍Predicates的地方查看

15.org.apache.kafka.connect.transforms.predicates.HasHeaderKey
对于具有至少一个具有配置名称的头的记录为真。

1).name
标题名称。

16.org.apache.kafka.connect.transforms.predicates.RecordIsTombstone
于tombstones记录(即具有null值)的谓词为真。

17.org.apache.kafka.connect.transforms.predicates.TopicNameMatches
对于主题名称与配置的正则表达式匹配的记录为真。

1).pattern
一个Java正则表达式,用于匹配记录主题的名称。

因为kafka connect是作为一个服务来运行的,因此它也提供了一些必要的rest API来进行操作connector,我们可以通过配置listeners来监听,配置形式是listeners=protocol://host:port,protocol2://host2:port2,有http和https两种协议可以使用。在未配置listeners的情况下,rest server默认使用http协议及端口号8083。如果使用了https协议,那么默认必须配置相应的ssl.*,但是如果你不想使用默认是https连接rest api,那么你可以使用listeners.https前缀来自定义,同时ssl.*前缀的配置将会被忽略掉。ssl.*的配置有如下:

ssl.keystore.location
ssl.keystore.password
ssl.keystore.type
ssl.key.password
ssl.truststore.location
ssl.truststore.password
ssl.truststore.type
ssl.enabled.protocols
ssl.provider
ssl.protocol
ssl.cipher.suites
ssl.keymanager.algorithm
ssl.secure.random.implementation
ssl.trustmanager.algorithm
ssl.endpoint.identification.algorithm
ssl.client.auth


rest api不仅能监控和管理kafka connect,而且还能用于kafka connect的跨集群通信。在follower节点收到的rest api请求将会被转发到leader节点上进行处理。如果给定主机可达的URI与它监听的URI不同,我们可以通过设置rest.advertised.host.name, rest.advertised.port和rest.advertised.listener来用于改变URI,该URI将被follower节点用于连接leader。当同时使用HTTP和HTTPS监听器时,rest.advertised.listener选项还可以用于定义将用于跨集群通信的哪个侦听器。当节点之间使用HTTPS进行通信时,使用相同的ssl.*或listeners.https选项将用于配置https客户端。我们下面看下有哪些rest api接口:

1.GET /connectors:返回活动连接器的列表。

2.POST /connectors:创建一个新的连接器;请求主体应该是一个JSON对象,其中包含一个字符串名称字段和一个带有连接器配置参数的对象配置字段。

3.GET /connectors/{name}:获取有关特定连接器的信息。

4.GET /connectors/{name}/config:获取特定连接器的配置参数。

5.PUT /connectors/{name}/config:更新特定连接器的配置参数。

6.GET /connectors/{name}/status:获取连接器的当前状态,包括它是否正在运行、失败、暂停等、它被分配给哪个工作器、失败时的错误信息以及它所有任务的状态。

7.GET /connectors/{name}/tasks:获取连接器当前正在运行的任务列表。

8.GET /connectors/{name}/tasks/{taskid}/status:获取任务的当前状态,包括它是否正在运行、失败、暂停等,它被分配给哪个worker,以及失败时的错误信息。

9.PUT /connectors/{name}/pause:暂停连接器及其任务,这将停止消息处理,直到连接器恢复。

10.PUT /connectors/{name}/resume:恢复暂停的连接器(如果连接器没有暂停,则不做任何操作)。

11.POST /connectors/{name}/restart:重新启动连接器(通常是因为它失败了)。

12.POST /connectors/{name}/tasks/{taskId}/restart:重新启动单个任务(通常是因为它失败了)。

13.DELETE /connectors/{name}:删除连接器,停止所有任务并删除其配置。

14.GET /connectors/{name}/topics:获取自创建连接器或发出重置其活动主题集的请求以来,特定连接器正在使用的主题集。

15.PUT /connectors/{name}/topics/reset:发送一个请求以清空连接器的活动主题集。
rest api还提供了获取关于connector插件的api:

1.GET /connector-plugins:返回一个Kafka Connect集群中安装的连接器插件列表。请注意,API只检查处理请求的工作器上的连接器,这意味着您可能会看到不一致的结果,特别是在滚动升级期间,如果您添加了新的连接器jar。

2.PUT /connector-plugins/{connector-type}/config/validate:根据配置定义验证提供的配置值。这个API执行每个配置验证,并在验证过程中返回建议值和错误消息。
下面这个是用于最顶级的connector查询:

1.GET /:返回关于Kafka Connect集群的基本信息,例如服务REST请求的Connect worker的版本(包括git提交的源代码ID)和连接到的Kafka集群ID。
Kafka Connect提供了错误报告来处理在不同处理阶段遇到的错误。默认情况下,在转换期间或转换中遇到的任何错误都将导致连接器失败。每个连接器配置还可以跳过这些错误,并将每个错误和失败操作的详细信息以及有问题的记录(具有不同级别的详细信息)写入Connect应用程序日志。当接收连接器处理来自Kafka主题的消息时,这些机制也会捕获错误,并且所有的错误都可以写入到可配置的“死信队列”(DLQ) Kafka主题。
若要将连接器的转换器、转换或接收器连接器本身内的错误报告到日志,需要设置errors.log.enable=true,以记录每个错误和问题记录的主题、分区和偏移量的详细信息。出于其他调试目的,设置errors.log.include.messages=true也将问题记录的键、值和头记录到日志中。为了将问题记录到DLQ,我们需要通过设置errors.deadletterqueue.topic.name手动定义一个DLQ名称,同时还可以设置errors.deadletterqueue.context.headers.enable=true。经过一些相关配置,我们可以看到处理错误报告的配置大体如下:

# retry for at most 10 minutes times waiting up to 30 seconds between consecutive failures
errors.retry.timeout=600000
errors.retry.delay.max.ms=30000

# log error context along with application logs, but do not include configs and messages
errors.log.enable=true
errors.log.include.messages=false

# produce error context into the Kafka topic
errors.deadletterqueue.topic.name=my-connector-errors

# Tolerate all errors.
errors.tolerance=all

更多的代码细节可以参考:https://github.com/apache/kafka/tree/2.7/connect