Plugin kafka_cdc_plugin
The kafka_cdc_plugin plugin is designed to register data change events in Firebird database tables and save them in Kafka. This process is also known as Change Data Capture, henceforth CDC.
Each event is a document in JSON format, which is as close as possible to the debezium event format. In the next version it is planned to add the ability to serialize events in AVRO format.
Requirements
The plugin requires the librdkafka and liblz4 libraries. On Windows, they are included in the distribution. On Linux, you must install them manually.
Installation on Debian:
sudo apt install librdkafka1
sudo apt install liblz4-1
fb_streaming + kafka_cdc_plugin files and folders on Windows
fb_streaming.exe- fb_streaming service;fbclient.dll- Firebird client library (version 4.0 and higher);icudt63.dll,icuin63.dll,icuuc63.dll,icudt63l.dat- ICU library files. On some Windows versions, the system ICU library is already installed, in which case these files are optional;fb_streaming.conf- fb_streaming service configuration file;fb_streaming.log- fb_streaming service log (created manually);zlib1.dll,zstd.dll,lz4.dll- data and traffic compression libraries required by thekafka_cdc_pluginplugin;libssl-3-x64.dll,libcrypto-3-x64.dll- OpenSSL encryption libraries for Windows-x64,libssl-3.dll,libcrypto-3.dll, required by thekafka_cdc_pluginplugin;libssl-3.dll,libcrypto-3.dll- OpenSSL encryption libraries for Windows-x86, required by thekafka_cdc_pluginplugin;doc- Documentation folder;stream_plugins- Folder for plugin library files;stream_plugins/kafka_cdc_plugin.dll- Kafka_cdc_plugin plugin library.
[!NOTE] Note: SASL is only supported in the 64-bit build.
How it works
The fb_streaming service (daemon) checks the contents of the directory specified for the task in the fb_streaming.conf configuration file, and if this directory contains unprocessed replication log files, then it analyzes them and generates appropriate events that are processed by the specified plugin. The last replication segment number processed is written to a control file named <database guid>. The location of this file can be specified in the lockDir configuration parameter. If this parameter is not specified, then by default the control file <database guid> will be created in the directory specified as the archive log directory for the task.
[!IMPORTANT] Important: Replication log files must be in an archived state.
The control file is necessary to restore operation after a sudden shutdown of the service (for example, the lights were turned off or the server was rebooted). It contains the following information:
- control information (database GUID, size, etc.);
- number of the last processed segment and position in it;
- the number of the segment with the oldest active transaction (a transaction can start in one segment and end in another);
- a list of all active transactions in the form of pairs
{tnxNumber, segmentNumber}, wheresegmentNumberis the number of the segment in which the transaction began.
If an emergency situation occurs and the fb_streaming service has been stopped, then the next time it starts, it reads the control file and rereads all replication segments, starting with the number of the segment with the oldest active transaction, and ending with the number of the last processed segment. In the process of reading these segments, fb_streaming repeats all events from the list of active transactions, after which it goes into normal operation.
A replication segment file is deleted if its number is less than the segment number with the oldest active transaction.
The kafka_cdc_plugin generates only data change events for the given tables for each of the INSERT, UPDATE and DELETE operations. Each active transaction has its own buffer in which these events accumulate, and they are sent to Kafka only when the transaction completes, after which the buffer is cleared.
Events can enter Kafka in two formats:
- JSON without schema (parameters
key_converter_schemas_enableandvalue_converter_schemas_enableequal tofalse); - JSON with a schema (parameters
key_converter_schemas_enableandvalue_converter_schemas_enableequal totrue).
Future versions also plan to add support for event serialization in AVRO format, as well as support for schema registries.
Topic names
By default, kafka_cdc_plugin writes change events for all INSERT, UPDATE and DELETE operations, in one Apache Kafka theme. kafka_cdc_plugin uses the scheme described in the kafka_topic_cdc_event parameter equal to $[topicPrefix].cdc for the names of data change event topics.
Where $[topicPrefix] is a substitution that is replaced by a prefix for topics. This prefix is set by the kafka_topic_prefix parameter, by default it is fb_streaming. Thus, by default, all data change events are write in the topic fb_streaming.cdc (after applying substitution).
There are other substitutions. The substitution $[tableName] indicates the name of the table for which the event is generated. Thus, by specifying in the configuration
kafka_topic_cdc_event = $[topicPrefix].cdc.$[tableName]
each table has its own topic of data change events.
Examples of topics with data change events:
fb_streaming.cdc.products
fb_streaming.cdc.products_on_hand
fb_streaming.cdc.customers
fb_streaming.cdc.orders
The topic name for the metadata change event is specified in the kafka_topic_transaction parameter. Only the substitution $[topicPrefix] is available in this parameter.
Transaction metadata
The kafka_cdc_plugin can generate events that represent transaction boundaries and that enrich data change event messages. By default, generation of transaction boundary events is disabled. It can be enabled by setting the transaction_metadata_enable parameter to true.
The kafka_cdc_plugin generates transaction boundary events for the BEGIN and END delimiters in every transaction. Transaction boundary events contain the following fields:
status–BEGINorEND;id– Unique transaction identifier;ts_ms– The time of a transaction boundary event (BEGINorENDevent). Since there is no such time in the replication logs, the time when the event is processed by thekafka_cdc_pluginplugin is processed;event_count(forENDevents) – Total number of events emitted by the transaction;data_collections(forENDevents) – An array of pairs ofdata_collectionandevent_countelements that indicates the number of events that thekafka_cdc_pluginemits for changes that originate from a data collection.
Example:
{
"status": "BEGIN",
"id": 901,
"ts_ms": 1713099401529,
"event_count": null,
"data_collections": null
}
{
"status": "END",
"id": 901,
"ts_ms": 1713099404605,
"event_count": 2,
"data_collections": [
{
"data_collection": "fbstreaming.cdc.CUSTOMERS",
"event_count": 2
}
]
}
Unless overridden by the kafka_topic_transaction parameter, kafka_cdc_plugin sends transaction events to the $[topicPrefix].transaction topic.
Change data event enrichment
When transaction metadata is enabled (transaction_metadata_enable = true), the Envelope of the data message is populated with a new transaction field. This field provides information about each event as a collection of fields:
id– Unique transaction identifier;total_order– The absolute position of the event among all events generated by the transaction;data_collection_order– The per-data collection position of the event among all events that were emitted by the transaction.
Example:
{
"before": null,
"after": {
"ID": 20,
"FIRST_NAME": "Anne",
"LAST_NAME": "Kretchmar",
"EMAIL": "[email protected]"
},
"source": {
...
},
"op": "c",
"ts_ms": 1713099401533,
"transaction": {
"id": 901,
"total_order": 1,
"data_collection_order": 1
}
}
Data Change Events
The kafka_cdc_plugin generates a data change event for each INSERT, UPDATE and DELETE operation at the record level. Each event contains a key and a value. The key and value structure depends on the modified table.
The fb_streaming service and the kafka_cdc_plugin plugin are designed for continuous streams of event messages. However, the structure of these events may change over time, which may be difficult for consumers to process. To solve this problem, each event contains a schema for its content or, if you are using a schema registry, a schema identifier that the consumer can use to retrieve the schema from the registry. This makes each event self-contained.
The following JSON skeleton shows the four main parts of a change event. The schema field is only in the change event when you configure the kafka_cdc_plugin plugin to create it. Likewise, the event key and event payload are only found in the change event if you have configured the kafka_cdc_plugin plugin to generate them. If you are using the JSON format and have configured the kafka_cdc_plugin to generate all four main parts of change events, the change events have the following structure:
{
"schema": { // <1>
...
},
"payload": { // <2>
...
}
}
{
"schema": { // <3>
...
},
"payload": { // <4>
...
}
}
Overview of change event basic content:
| Item | Field name | Description |
|---|---|---|
| 1 | schema | The first schema field is part of the event key. It defines a schema that describes what is in the payload portion of the event key. In other words, the first schema field describes the structure of the primary key, or unique key if the table does not have a primary key, for the modified table. This part of the event will only be published if the parameter key_converter_schemas_enable = true. |
| 2 | payload | The first payload field is part of the event key. It has the structure described by the previous schema field and it contains the key for the row that was changed. |
| 3 | schema | The second schema field is part of the event value. It defines a schema that describes what is in the payload of the event value. In other words, the second schema describes the structure of the row that was changed. Typically this schema contains nested schemas. This part of the event will only be published if the parameter value_converter_schemas_enable = true. |
| 4 | payload | The second payload field is part of the event value. It has the structure described by the previous schema field and it contains the actual data for the row that was changed. |
Change event keys
For a given table, the change event key has a structure that contains a field for each column of the table’s primary key at the time the event was created.
Consider the CUSTOMERS table, and an example of a change event key for that table.
CREATE TABLE CUSTOMERS (
ID BIGINT GENERATED BY DEFAULT AS IDENTITY,
FIRST_NAME VARCHAR(255) NOT NULL,
LAST_NAME VARCHAR(255) NOT NULL,
EMAIL VARCHAR(255) NOT NULL,
CONSTRAINT PK_CUSTOMERS PRIMARY KEY(ID)
);
{
"schema": { // <1>
"type": "struct",
"name": "fbstreaming.CUSTOMERS.Key", // <2>
"optional": "false", // <3>
"fields": [ // <4>
{
"type": "int64",
"optional": false,
"field": "ID"
}
]
},
"payload": { // <5>
"ID": 1
}
}
Description of change event key:
| Item | Field name | Description |
|---|---|---|
| 1 | schema |
The schema that describes what is in key’s payload portion. The schema will only be included in the event if the configuration option is set to key_converter_schemas_enable = true. |
| 2 | name |
Name of the schema that defines the structure of the key’s payload. This schema describes the structure of the primary key for the table that was changed. Key schema names have the format fbstreaming.<table_name>.Key. |
| 3 | optional |
Indicates whether the event key must contain a value in its payload field. In this example, a value in the key’s payload is required. A value in the key’s payload field is optional when a table does not have a primary key. |
| 4 | fields |
Specifies each field that is expected in the payload, including each field’s name, type, and whether it is required. |
| 5 | payload |
Contains the key for the row for which this change event was generated. In this example, the key, contains a single ID field whose value is 1. |
Change event values
The value in a change event is a bit more complicated than the key. Like the key, the value has a schema section and a payload section. The schema section contains the schema that describes the Envelope structure of the payload section, including its nested fields. Change events for operations that create, update or delete data all have a value payload with an envelope structure.
Consider the same sample table that was used to show an example of a change event key:
CREATE TABLE CUSTOMERS (
ID BIGINT GENERATED BY DEFAULT AS IDENTITY,
FIRST_NAME VARCHAR(255) NOT NULL,
LAST_NAME VARCHAR(255) NOT NULL,
EMAIL VARCHAR(255) NOT NULL,
CONSTRAINT PK_CUSTOMERS PRIMARY KEY(ID)
);
The value portion of a change event for a change to this table is described for:
- create events
- update events
- delete events
To demonstrate these events, let’s run the following set of SQL queries:
insert into CUSTOMERS (FIRST_NAME, LAST_NAME, EMAIL)
values ('Anne', 'Kretchmar', '[email protected]');
commit;
update CUSTOMERS
set FIRST_NAME = 'Anne Marie';
commit;
delete from CUSTOMERS;
commit;
Create events
The following example shows part of the change event value that fb_streaming generates for an operation that creates data in the CUSTOMERS table:
{
"schema": { // <1>
"type": "struct",
"fields": [
{
"type": "struct",
"fields": [
{
"type": "int64",
"optional": false,
"field": "ID"
},
{
"type": "string",
"optional": false,
"field": "FIRST_NAME"
},
{
"type": "string",
"optional": false,
"field": "LAST_NAME"
},
{
"type": "string",
"optional": false,
"field": "EMAIL"
}
],
"optional": true,
"name": "fbstreaming.CUSTOMERS.Value", // <2>
"field": "before"
},
{
"type": "struct",
"fields": [
{
"type": "int64",
"optional": false,
"field": "ID"
},
{
"type": "string",
"optional": false,
"field": "FIRST_NAME"
},
{
"type": "string",
"optional": false,
"field": "LAST_NAME"
},
{
"type": "string",
"optional": false,
"field": "EMAIL"
}
],
"optional": true,
"name": "fbstreaming.CUSTOMERS.Value",
"field": "after"
},
{
"type": "struct",
"fields": [
{
"type": "string",
"optional": false,
"field": "dbguid"
},
{
"type": "int64",
"optional": false,
"field": "sequence"
},
{
"type": "string",
"optional": false,
"field": "filename"
},
{
"type": "string",
"optional": false,
"field": "table"
},
{
"type": "int64",
"optional": false,
"field": "tnx"
},
{
"type": "int64",
"optional": true,
"field": "ts_ms"
}
],
"optional": false,
"name": "fbstreaming.Source", // <3>
"field": "source"
},
{
"type": "int64",
"optional": false,
"field": "op"
}
],
"optional": false,
"name": "fbstreaming.CUSTOMERS.Envelope" // <4>
},
"payload": { // <5>
"before": null, // <6>
"after": { // <7>
"ID": 1,
"FIRST_NAME": "Anne",
"LAST_NAME": "Kretchmar",
"EMAIL": "[email protected]"
},
"source": { // <8>
"dbguid": "{9D66A972-A8B9-42E0-8542-82D1DA5F1692}",
"sequence": 1,
"filename": "TEST.FDB.journal-000000001",
"table": "CUSTOMERS",
"tnx": 200,
"ts_ms": 1711288254908
},
"op": "c", // <9>
"ts_ms": 1711288255056 // <10>
}
}
Descriptions of create event value fields:
| Item | Field name | Description |
|---|---|---|
| 1 | schema |
The value’s schema, which describes the structure of the value’s payload. A change event’s value schema is the same in every change event that the connector generates for a particular table. The schema will only be included in the event if the configuration option is set to value_converter_schemas_enable = true. |
| 2 | name |
In the schema section, each name field specifies the schema name for the payload part fields.
The schema names for the |
| 3 | name |
fbstreaming.Source is the schema of the payload source field. This scheme is specific to the fbstreaming service and the kafka_cdc_plugin plugin. fbstreaming uses it for all events it generates. |
| 4 | name |
fbstreaming.CUSTOMERS.Envelope is the schema for the overall structure of the payload, where fbstreaming is service name, and CUSTOMERS is table name. |
| 5 | payload |
The value’s actual data. This is the information that the change event is providing. |
| 6 | before |
An optional field that specifies the state of the row before the event occurred. When the op field is c for create, as it is in this example, the before field is null since this change event is for new content. |
| 7 | after |
An optional field that specifies the state of the row after the event occurred. In this example, the after field contains the values of the new row’s ID, FIRST_NAME, LAST_NAME and EMAIL columns. |
| 8 | source |
Mandatory field that describes the source metadata for the event. This field contains information that you can use to compare this event with other events, with regard to the origin of the events, the order in which the events occurred, and whether events were part of the same transaction. The source metadata includes:
|
| 9 | op |
Mandatory string that describes the type of operation that caused the connector to generate the event. In this example, c indicates that the operation created a row. Valid values are:
|
| 10 | ts_ms |
Displays the time at which fbstreaming recorded the event in Kafka. In the |
Update events
The change event value for the update operation in the example table CUSTOMERS has the same schema as the create event for that table. Likewise, the event value payload has the same structure. However, the event value payload contains different values in the update event. Here is an example of the change event value in the event that fb_streaming generates for an update on the CUSTOMERS table:
{
"schema": { ... },
"payload": {
"before": { // <1>
"ID": 1,
"FIRST_NAME": "Anne",
"LAST_NAME": "Kretchmar",
"EMAIL": "[email protected]"
},
"after": { // <2>
"ID": 1,
"FIRST_NAME": "Anne Marie",
"LAST_NAME": "Kretchmar",
"EMAIL": "[email protected]"
},
"source": { // <3>
"dbguid": "{9D66A972-A8B9-42E0-8542-82D1DA5F1692}",
"sequence": 2,
"filename": "TEST.FDB.journal-000000002",
"table": "CUSTOMERS",
"tnx": 219,
"ts_ms": 1711288254908
},
"op": "u", // <4>
"ts_ms": 1711288256121 // <5>
}
}
Descriptions of update event value fields:
| Item | Field name | Description |
|---|---|---|
| 1 | before |
An optional field that specifies the state of the row before the event occurred. In an update event value, the before field contains a field for each table column and the value that was in that column before the database commit. In this example, the FIRST_NAME value is Anne. |
| 2 | after |
An optional field that specifies the state of the row after the event occurred. You can compare the before and after structures to determine what the update to this row was. In the example, the FIRST_NAME value is now Anne Marie. |
| 3 | source |
Mandatory field that describes the source metadata for the event. This field contains information that you can use to compare this event with other events, with regard to the origin of the events, the order in which the events occurred, and whether events were part of the same transaction. The source metadata includes:
|
| 4 | op |
Mandatory string that describes the type of operation. In an update event value, the op field value is u, signifying that this row changed because of an update. |
| 5 | ts_ms |
Displays the time at which fbstreaming recorded the event in Kafka. In the |
Delete events
The value in a delete change event has the same schema portion as create and update events for the same table. The payload portion in a delete event for the sample CUSTOMERS table looks like this:
{
"schema": { ... },
"payload": { // <1>
"before": {
"ID": 1,
"FIRST_NAME": "Anne Marie",
"LAST_NAME": "Kretchmar",
"EMAIL": "[email protected]"
},
"after": null, // <2>
"source": { // <3>
"dbguid": "{9D66A972-A8B9-42E0-8542-82D1DA5F1692}",
"sequence": 3,
"filename": "TEST.FDB.journal-000000003",
"table": "CUSTOMERS",
"tnx": 258,
"ts_ms": 1711288254908
},
"op": "d", // <4>
"ts_ms": 1711288256152 // <5>
}
}
Descriptions of delete event value fields:
| Item | Field name | Description |
|---|---|---|
| 1 | before |
Optional field that specifies the state of the row before the event occurred. In a delete event value, the before field contains the values that were in the row before it was deleted with the database commit. |
| 2 | after |
Optional field that specifies the state of the row after the event occurred. In a delete event value, the after field is null, signifying that the row no longer exists. |
| 3 | source |
Mandatory field that describes the source metadata for the event. This field contains information that you can use to compare this event with other events, with regard to the origin of the events, the order in which the events occurred, and whether events were part of the same transaction. The source metadata includes:
|
| 4 | op |
Mandatory string that describes the type of operation. The op field value is d, signifying that this row was deleted. |
| 5 | ts_ms |
Displays the time at which fbstreaming recorded the event in Kafka. In the |
Data type mappings
| Firebird data type | Literal type | Semantic type |
|---|---|---|
| BOOLEAN | boolean | |
| SMALLINT | int16 | |
| INTEGER | int32 | |
| BIGINT | int64 | |
| INT128 | string | |
| FLOAT | float | |
| DOUBLE PRECISION | double | |
| NUMERIC(N,M) | string | |
| DECIMAL(N,M) | string | |
| DECFLOAT(16) | string | |
| DECFLOAT(34) | string | |
| CHAR(N) | string | |
| VARCHAR(N) | string | |
| BINARY(N) | string | Each byte is encoded with a hexadecimal XX pair. |
| VARBINARY(N) | string | Each byte is encoded with a hexadecimal XX pair. |
| TIME | string | String representation of time in the format HH24:MI:SS.F, where F is ten-thousandths of a second. |
| TIME WITH TIME ZONE | string | String representation of time in the format HH24:MI:SS.F TZ, where F is ten-thousandths of a second, TZ is the name of the time zone. |
| DATE | string | String representation of date in Y-M-D format. |
| TIMESTAMP | string | String representation of the date and time in the format Y-M-D HH24:MI:SS.F, where F is ten-thousandths of a second. |
| TIMESTAMP WITH TIMEZONE | string | String representation of the date and time in the format Y-M-D HH24:MI:SS.F, where F is ten-thousandths of a second, TZ is the name of the time zone. |
| BLOB SUB_TYPE TEXT | string | The before values are always null, since old BLOB field values are not stored in replication segments. |
| BLOB SUB_TYPE 0 | string | The before values are always null, since old BLOB field values are not stored in replication segments. Each byte is encoded with a hexadecimal pair XX. |
Run Change Data Capture
We will describe in detail the steps required to launch Change Data Capture on your database:
- Setting up Kafka
- Setting up Firebird and preparing the database
- Configuring the
fb_streamingservice and thekafka_cdc_pluginplugin - Launch Kafka
- Installation and start of the
fb_streamingservice - Start publishing in the database
Setting up Kafka
To test the kafka_cdc_plugin plugin, a configured Kafka installation in docker is used. To do this, use docker-compose.yml with the following content:
version: "2"
services:
zookeeper:
image: confluentinc/cp-zookeeper:7.2.1
hostname: zookeeper
container_name: zookeeper
ports:
- "2181:2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka:
image: confluentinc/cp-server:7.2.1
hostname: kafka
container_name: kafka
depends_on:
- zookeeper
ports:
- "9092:9092"
- "9997:9997"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
KAFKA_CONFLUENT_LICENSE_TOPIC_REPLICATION_FACTOR: 1
KAFKA_CONFLUENT_BALANCER_TOPIC_REPLICATION_FACTOR: 1
KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
KAFKA_JMX_PORT: 9997
KAFKA_JMX_HOSTNAME: kafka
kafka-ui:
container_name: kafka-ui
image: provectuslabs/kafka-ui:latest
ports:
- 8080:8080
environment:
DYNAMIC_CONFIG_ENABLED: 'true'
volumes:
- "d:\\docker\\kafka\\config.yml:/etc/kafkaui/dynamic_config.yaml"
The included file config.yml contains:
auth:
type: DISABLED
kafka:
clusters:
- bootstrapServers: kafka:29092
name: Kafka CDC Cluster
properties: {}
readOnly: false
rbac:
roles: []
webclient: {}
Setting up Firebird and preparing the database
Now you need to configure asynchronous replication for your database; to do this, you need to add the following lines to the replication.conf file:
database = c:\fbdata\5.0\test.fdb
{
journal_directory = d:\fbdata\5.0\replication\test\journal
journal_archive_directory = d:\fbdata\5.0\replication\test\archive
journal_archive_command = "copy $(pathname) $(archivepathname) && copy $(pathname) d:\fbdata\5.0\replication\test\kafka_source"
journal_archive_timeout = 10
}
Please note: this involves duplicating log archive files so that logical replication and the task of sending events to Kafka can work simultaneously. This is necessary because log archive files are deleted after processing and cannot be used by another task.
If replication logs are not used for replication itself, but are only needed for Change Data Capture, then the configuration can be simplified:
database = c:\fbdata\5.0\test.fdb
{
journal_directory = d:\fbdata\5.0\replication\test\journal
journal_archive_directory = d:\fbdata\5.0\replication\test\kafka_source
journal_archive_timeout = 10
}
Now you need to include the necessary tables in the publication. For the example above, just add the CUSTOMERS table to the publication. This is done with the following statement:
ALTER DATABASE INCLUDE CUSTOMERS TO PUBLICATION;
or you can include all database tables in the publication at once:
ALTER DATABASE INCLUDE ALL TO PUBLICATION;
Configuring the fb_streaming service and the kafka_cdc_plugin plugin
Next, we’ll configure the fb_streaming.conf configuration so that fb_streaming automatically sends data change events to Kafka.
task = d:\fbdata\5.0\replication\test\kafka_source
{
database = inet://localhost:3055/test
username = SYSDBA
password = masterkey
deleteProcessedFile = true
plugin = kafka_cdc_plugin
dumpBlobs = true
kafka_brokers = localhost:9092
kafka_topic_prefix = fb_streaming
kafka_topic_cdc_event = $[topicPrefix].cdc
kafka_topic_transaction = $[topicPrefix].transaction
key_cdc_events_enable = true
key_converter_schemas_enable = true
value_converter_schemas_enable = true
transaction_metadata_enable = true
}
On Linux this configuration would look like this:
task = /mnt/d/fbdata/5.0/replication/test/kafka_source
{
database = inet://localhost:3055/test
username = SYSDBA
password = masterkey
deleteProcessedFile = true
plugin = kafka_cdc_plugin
dumpBlobs = true
kafka_brokers = localhost:9092
kafka_topic_prefix = fb_streaming
kafka_topic_cdc_event = $[topicPrefix].cdc
kafka_topic_transaction = $[topicPrefix].transaction
key_cdc_events_enable = true
key_converter_schemas_enable = true
value_converter_schemas_enable = true
transaction_metadata_enable = true
}
The task parameter describes the task to be performed by the fb_streaming service. It specifies the folder where the replication segment files are located for the plugin to process. There may be several such tasks. This parameter is complex and itself describes the configuration of a specific task. Let’s describe the parameters available for the task performed by the kafka_cdc_plugin plugin:
controlFileDir- the directory in which the control file will be created (by default, the same directory assourceDir);database- database connection string (required);username- user name for connecting to the database;password- password for connecting to the database;plugin- plugin that processes events that occur during the analysis of the replication log (required);deleteProcessedFile- whether to delete the log file after processing (true by default). It is useful to set this parameter tofalsefor debugging, when the same logs need to be processed multiple times without deleting them;warn_tnx_not_found- generate a warning instead of an error if the transaction is not found in the replication segments. If this parameter is set totrue, then an appropriate warning will be written to thefb_streaminglog, the contents of the lost transaction will be ignored, and the plugin will continue to work. Default isfalse;errorTimeout- timeout after an error, in seconds. After this timeout expires, the segments will be re-scanned and the task will be restarted. Default is 60 seconds;include_tables- a regular expression that defines the names of the tables for which events need to be tracked;exclude_tables- a regular expression that defines the names of tables for which events do not need to be tracked;dumpBlobs- whether to publish new BLOB field values (defaultfalse);charset_for_none_fields- character set used for converting data from string fields with the character set typeNONE. Typically, data in string fields with theNONEcharacter set is stored “as is,” meaning in the original encoding used by the application when saving it. Firebird does not re-encode such strings. The JSON format requires all strings to be inUTF-8encoding. To correctly convert strings fromNONEfields toUTF8, the system needs to know the original encoding of the data. This is precisely what thecharset_for_none_fieldsparameter specifies;kafka_brokers- addresses of Kafka brokers. You can specify multiple addresses. Addresses are separated by commas;kafka_topic_prefix– Kafka topic prefix. It specifies a macro substitution$[topicPrefix]that can be used for topic names;kafka_topic_cdc_event– the name of the Kafka topic(s) in which data change events are stored. Macro substitutions$[topicPrefix]and$[tableName]can be used;kafka_topic_transactionis the name of the Kafka topic in which transaction metadata is stored. Macro substitution$[topicPrefix]can be used;async_producer- if you set this parameter totrue, then messages in Kafka will be sent asynchronously, that is,fb_streamingwill not wait for confirmation that the message was successfully sent, but will immediately proceed to processing the next message. Messages are sent asynchronously until the internal buffer of unsent messages is full. By default, the size of this buffer is 500;key_cdc_events_enable- if this option is set totrue, each data change event contains key information, otherwise the event key will be null. This can be useful because Kafka uses the event key for partitioning.key_converter_schemas_enable- whether to include a schema in the data update event key;value_converter_schemas_enable- whether to include the schema in the data update event value;transaction_metadata_enable– whether to send transaction start and end events (transaction metadata).
The following describes the parameters of the LibRdKafka library used by this plugin. Each parameter is prefixed with kafka_. Dots inside the parameter are replaced with underscores _. See: LibRdKafka CONFIGURATION.
kafka_security_protocol- Protocol used to communicate with brokers. Valid values are:plaintext,ssl,sasl_plaintext,sasl_ssl. In theLibRdKafkalibrary, this parameter has the namesecurity.protocol. Default value:plaintext.kafka_ssl_cipher_suites- A list of cipher suites. This is a named combination of authentication, encryption, MAC and key exchange algorithm used to negotiate the security settings for a network connection using TLS or SSL network protocol. By default all the available cipher suites are supported. In theLibRdKafkalibrary, this parameter has the namessl.cipher.suites.kafka_ssl_curves_list- The supported-curves extension in the TLS ClientHello message specifies the curves (standard/named, or explicit GF(2^k) or GF(p)) the client is willing to have the server use. See manual page for SSL_CTX_set1_curves_list(3). OpenSSL >= 1.0.2 required. In theLibRdKafkalibrary, this parameter has the namessl.curves.list.kafka_ssl_sigalgs_list- The client uses the TLS ClientHello signature_algorithms extension to indicate to the server which signature/hash algorithm pairs may be used in digital signatures. See manual page for SSL_CTX_set1_sigalgs_list(3). OpenSSL >= 1.0.2 required. In theLibRdKafkalibrary, this parameter has the namessl.sigalgs.list.kafka_ssl_key_location- Path to client’s private key (PEM) used for authentication. In theLibRdKafkalibrary, this parameter has the namessl.key.location.kafka_ssl_key_password- Private key passphrase (for use withssl.key.locationandset_ssl_cert()). In theLibRdKafkalibrary, this parameter has the namessl.key.password.kafka_ssl_certificate_location- Path to client’s public key (PEM) used for authentication. In theLibRdKafkalibrary, this parameter has the namessl.certificate.location.kafka_ssl_ca_location- File or directory path to CA certificate(s) for verifying the broker’s key. Defaults: On Windows the system’s CA certificates are automatically looked up in the Windows Root certificate store. On Mac OSX this configuration defaults to probe. It is recommended to install openssl using Homebrew, to provide CA certificates. On Linux install the distribution’s ca-certificates package. If OpenSSL is statically linked orssl.ca.locationis set to probe a list of standard paths will be probed and the first one found will be used as the default CA certificate location path. If OpenSSL is dynamically linked the OpenSSL library’s default path will be used (seeOPENSSLDIRin openssl version-a). In theLibRdKafkalibrary, this parameter has the namessl.ca.location.kafka_ssl_ca_certificate_stores- Comma-separated list of Windows Certificate stores to load CA certificates from. Certificates will be loaded in the same order as stores are specified. If no certificates can be loaded from any of the specified stores an error is logged and the OpenSSL library’s default CA location is used instead. Store names are typically one or more of: MY, Root, Trust, CA. In theLibRdKafkalibrary, this parameter has the namessl.ca.certificate.stores. Default value:Root.kafka_ssl_crl_location- Path to CRL for verifying broker’s certificate validity. In theLibRdKafkalibrary, this parameter has the namessl.crl.location.kafka_ssl_keystore_location- Path to client’s keystore (PKCS#12) used for authentication. In theLibRdKafkalibrary, this parameter has the namessl.keystore.location.kafka_ssl_keystore_password- Client’s keystore (PKCS#12) password. In theLibRdKafkalibrary, this parameter has the namessl.keystore.password.kafka_ssl_providers- Comma-separated list of OpenSSL 3.0.x implementation providers. E.g.,default,legacy. In theLibRdKafkalibrary, this parameter has the namessl.providers.kafka_ssl_engine_id- OpenSSL engine id is the name used for loading engine. In theLibRdKafkalibrary, this parameter has the namessl.engine.id. Default value:dynamic.kafka_enable_ssl_certificate_verification- Enable OpenSSL’s builtin broker (server) certificate verification. Valid values are:true,false. In theLibRdKafkalibrary, this parameter has the nameenable.ssl.certificate.verification. Default value:true.kafka_ssl_endpoint_identification_algorithm- Endpoint identification algorithm to validate broker hostname using broker certificate. Valid values are:none,https.https- Server (broker) hostname verification as specified in RFC2818.none- No endpoint verification. OpenSSL >= 1.0.2 required. In theLibRdKafkalibrary, this parameter has the namessl.endpoint.identification.algorithm. Default value:https.kafka_sasl_mechanism- SASL mechanism to use for authentication. Supported:GSSAPI,PLAIN,SCRAM-SHA-256,SCRAM-SHA-512,OAUTHBEARER. NOTE: Despite the name only one mechanism must be configured. In theLibRdKafkalibrary, this parameter has the namesasl.mechanism. Default value:GSSAPI.kafka_sasl_username- SASL username for use with thePLAINandSASL-SCRAM-..mechanisms. In theLibRdKafkalibrary, this parameter has the namesasl.username.kafka_sasl_password- SASL password for use with thePLAINandSASL-SCRAM-..mechanisms. In theLibRdKafkalibrary, this parameter has the namesasl.password.kafka_sasl_kerberos_service_name- Kerberos principal name that Kafka runs as, not including/hostname@REALM. In theLibRdKafkalibrary, this parameter has the namesasl.kerberos.service.name. Default value:kafka.kafka_sasl_kerberos_principal- This client’s Kerberos principal name. (Not supported on Windows, will use the logon user’s principal). In theLibRdKafkalibrary, this parameter has the namesasl.kerberos.principal. Default value:kafkaclient.kafka_sasl_oauthbearer_config- SASL/OAUTHBEARER configuration. The format is implementation-dependent and must be parsed accordingly. The default unsecured token implementation (see https://tools.ietf.org/html/rfc7515#appendix-A.5) recognizes space-separatedname=valuepairs with valid names includingprincipalClaimName,principal,scopeClaimName,scope, andlifeSeconds. The default value forprincipalClaimNameissub, the default value forscopeClaimNameisscope, and the default value forlifeSecondsis3600. The scope value is CSV format with the default value being no/empty scope. For example:principalClaimName=azp principal=admin scopeClaimName=roles scope=role1,role2 lifeSeconds=600. In addition, SASL extensions can be communicated to the broker viaextension_NAME=value. For example:principal=admin extension_traceId=123. In theLibRdKafkalibrary, this parameter has the namesasl.oauthbearer.config.kafka_sasl_oauthbearer_method- Set todefaultoroidcto control which login method to be used. If set tooidc, the following properties must also be be specified:kafka_sasl_oauthbearer_client_id,kafka_sasl_oauthbearer_client_secretandkafka_sasl_oauthbearer_token_endpoint_url(sasl.oauthbearer.client.id,sasl.oauthbearer.client.secret, andsasl.oauthbearer.token.endpoint.url). In theLibRdKafkalibrary, this parameter has the namesasl.oauthbearer.method. Default value:default.kafka_sasl_oauthbearer_client_id- Public identifier for the application. Must be unique across all clients that the authorization server handles. Only used whenkafka_sasl_oauthbearer_method(sasl.oauthbearer.method) is set tooidc. In theLibRdKafkalibrary, this parameter has the namesasl.oauthbearer.client.id.kafka_sasl_oauthbearer_client_secret- Client secret only known to the application and the authorization server. This should be a sufficiently random string that is not guessable. Only used whenkafka_sasl_oauthbearer_method(sasl.oauthbearer.method) is set tooidc. In theLibRdKafkalibrary, this parameter has the namesasl.oauthbearer.client.secret.kafka_sasl_oauthbearer_scope- Client use this to specify the scope of the access request to the broker. Only used whenkafka_sasl_oauthbearer_method(sasl.oauthbearer.method) is set tooidc. In theLibRdKafkalibrary, this parameter has the namesasl.oauthbearer.scope.kafka_sasl_oauthbearer_extensions- Allow additional information to be provided to the broker. Comma-separated list ofkey=valuepairs. E.g.,supportFeatureX=true,organizationId=sales-emea. Only used whenkafka_sasl_oauthbearer_method(sasl.oauthbearer.method) is set tooidc. In theLibRdKafkalibrary, this parameter has the namesasl.oauthbearer.extensions.kafka_sasl_oauthbearer_token_endpoint_url- OAuth/OIDC issuer token endpoint HTTP(S) URI used to retrieve token. Only used whenkafka_sasl_oauthbearer_method(sasl.oauthbearer.method) is set tooidc. In theLibRdKafkalibrary, this parameter has the namesasl.oauthbearer.token.endpoint.url.
Launch Kafka
Now you can run docker with a Kafka container:
docker-compose up -d
To stop docker run:
docker-compose down
Installing and starting the fb_streaming service
The next step is to install and start the fb_streaming service.
In Windows, this is done with the following commands (Administrator privileges are required):
fb_streaming install
fb_streaming start
On Linux:
sudo systemctl enable fb_streaming
sudo systemctl start fb_streaming
[!NOTE] To test how
fb_streamingworks without installing the service, simply type thefb_streamingcommand without any arguments.fb_streamingwill be launched as an application and terminated after pressing Enter.
Start publication in the database
Once you have everything set up and running, you need to enable publishing to your database. This is done with the following SQL query:
ALTER DATABASE ENABLE PUBLICATION;
From this moment on, the fb_streaming service will monitor changes in the specified tables and publish them in the fb_streaming.cdc topic, on the servers specified in kafka_brokers.