Most companies rely heavily on the data stored in their databases. If data isn’t stored in the correct database then business processes can be corrupted and you might make decisions based on outdated or incorrect information. This makes the data and changes made to it an interesting source of events. But getting data from a database into a streaming platform has its challenges. This is part 2 of our blog series and continues to explain how to implement Change Data Capture with PostgreSQL, Debezium on the Axual platform.

Change Data Capture is a pattern where a process identifies and captures changes made to data. It then sends the captured changes to another process or system which can process the changes.
CDC solutions use the internal change tracing features of databases allowing them to capture and produce record deletion events as well as record insertions and updates. A lot of databases also allow transactions and changes to the tables definitions to be captured.
PostgreSQL, or Postgres, is an open source relational database management system and one of the most popular databases to use whose popularity comes from the fact that it can be easily set up as a single machine, but can also be set up for massive scales and for concurrent access by multiple users.
PostgreSQL can be found in big and small companies because of the features, performance and the fact that most cloud providers have a PostgreSQL Database as a Service (DBaaS) offering.
But getting data from PostgreSQL and loading it into Axual Platform, or another Kafka based streaming platform, can be challenging.
Change Data Capture is an approach often considered to be too complex, but has some distinct advantages when compared to other solutions.
There are several solution available to architects and developers to get data from a database into a streaming platform, each with its own advantages and disadvantages.
Change Data Capture is a pattern where a process identifies and captures changes made to data. It then sends the captured changes to another process or system which can process the changes.
CDC solutions use the internal change tracing features of databases allowing them to capture and produce record deletion events as well as record insertions and updates. A lot of databases also allow transactions and changes to the tables definitions to be captured.
Debezium is a CDC tool for Kafka based systems that can connect and process changes from a relatively wide range of databases and is packaged as a Kafka Connect source connector.
An advantage of using CDC is that it can capture inserts, updates and deletes of records, as well as tracking transactions and sometimes datamodel changes.
A disadvantage is that CDC tools often support only a limited number of database vendors, as specific internal knowledge is required to connect and use the internal change tracking features of a database.
Kafka Connect is of course one of the default solutions to investigate to get data from an external system to Kafka and back.
JDBC, or Java Database Connectivity, is an API that allows applications to access a database in a generic way, without requiring knowledge of the native protocols used by the database.
Database vendors often provide JDBC Drivers, which translate the JDBC API calls to the database specific format to handle connections and queries.
There are JDBC Source connectors available for Kafka Connect that can read from tables and that regularly perform SQL queries to determine if there are changes. These changes are then produced to the topics by Kafka Connect.
A major advantage of these connectors is the fact that they are generic. The solution works on most databases, because most database vendors supply JDBC Drivers.
A disadvantage is that the change capture capabilities are limited by the use of SQL statements. Tables need a special column to determine for each record if and when it was changed, and that you cannot catch a deletion of a record in a table without additional logic in the database, such as triggers.
A custom application can be developed that connects to the database, scans the schemas, tables and data inside the tables, and writes the results to one or more Kafka topics.
The greatest advantage of this solution is that since this application is custom made it can be optimised for a specific database and use any database specific feature.
A disadvantage of developing a custom application is that is can become very complex and hard to maintain as it is also very hard to design and implement an application like this to be reusable and scalable.
Another disadvantage of this approach is that it almost impossible to determine if a record was deleted from a table, unless the database offers special features for that.
Most organisations have a process for reporting and processing incident reports and in our use case the incident reports are created and updated by an application that stores the data in a PostgreSQL database.
Change Data Capture will be used to capture the creation, updates and deletion of reports in the database and publish them on the Axual Platform to allow other systems to consume and process the events.

The table IncidentReports from the Incidents schema will be read by the Debezium Connector in Kafka Connect, which will load any new, updated or deleted data entries to the appropriate topic in the Kafka Cluster.
The incident report changes should go to the topic cdc-incident-reports.
The transaction metadata events that are captured from the database should be sent to the topic cdc-transactions.

The Debezium connector for PostgreSQL can scan schemas for changes in tables by using the PostgreSQL Logical Decoding feature. This feature makes it possible to extract the data changes from the transaction log and process these changes with a plugin.
PostgreSQL versions 10 and later already have a default plugin installed, called pgoutput.
An alternative approach is using the decoderbufs and wal2json plugins.
The database administrator/operator should be involved in the selection and installation of these plugins, as they can have an operational impact.
For this guide the default pgoutput plugin will be used.
The following resources are needed to prepare the database for the Change Data Capture example:
psql and pg_ctl reloadpsql on the machine running the databaseFor these steps the SQL client is required. The example code will use the psql client on the database server.
psql -U <username> -d <database name> -h <hostname> -p <port number>CREATE SCHEMA INCIDENTS;CREATE TABLE INCIDENTS."IncidentReports" (
"IncidentId" INTEGER PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"Reporter" VARCHAR(100) NOT NULL,
"Description" VARCHAR(255) NOT NULL,
"Report" TEXT NOT NULL,
"Status" VARCHAR(100) NOT NULL DEFAULT 'OPEN' );ALTER TABLE INCIDENTS."IncidentReports" REPLICA IDENTITY FULL;PostgreSQL has specific requirements of the grants, or permissions, needed by a user to perform replication like Debezium uses.
These grants are:
Most of these requirements can be met by granting them to the user, but changing the ownership of a schema or table can disrupt other activities on the database. Groups can be created to prevent that. The group will own those resources, and the new replication user and the original owner will be members of that group. This ensures that there will be no unintended disruptions for other systems.
psql -U <username> -d <database name> -h <hostname> -p <port number>CREATE ROLE "cdcUser" WITH REPLICATION LOGIN PASSWORD 'cdcDemo';CREATE ROLE CDC_REPLICATION_GROUP;GRANT CDC_REPLICATION_GROUP TO "cdcUser";GRANT CDC_REPLICATION_GROUP TO <username>;ALTER SCHEMA INCIDENTS OWNER TO CDC_REPLICATION_GROUP;ALTER TABLE INCIDENTS."IncidentReports" OWNER TO CDC_REPLICATION_GROUP;GRANT CREATE ON DATABASE <database> TO "cdcUser";Several changes are required to the PostgreSQL configuration files to enable the Logical Decoding feature and to allow replication connections.
wal_level=logicalhost replication cdcUser all scram-sha-256pg_ctl -D <path to database directory> reloadcdcUser credentialspsql "dbname=<database_name> replication=database" -c "IDENTIFY_SYSTEM;" -U cdcUser -h <hostname> -p <port_number>cdcDemosystemid | timeline | xlogpos | dbname
---------------------+----------+-----------+---------
7119453166424051742 | 1 | 0/17424D0 | axualdb
(1 row)After completing the steps in this article the database is prepared for connections from Debezium.
The next article will be focussed on using Debezium for PostgreSQL in the Axual Platform.
PostgreSQL, or Postgres, is an open source relational database management system and one of the most popular databases to use whose popularity comes from the fact that it can be easily set up as a single machine, but can also be set up for massive scales and for concurrent access by multiple users.
PostgreSQL can be found in big and small companies because of the features, performance and the fact that most cloud providers have a PostgreSQL Database as a Service (DBaaS) offering
Debezium is a CDC tool for Kafka based systems that can connect and process changes from a relatively wide range of databases and is packaged as a Kafka Connect source connector.
Axual is an all-in-one event stream processing platform for enterprise organizations. The Axual platform is complementary to Apache Kafka and provides additional functionality for data governance, audit trails, security, multi-tenancy and data synchronization, among others. The Axual self-service interface makes it easy for teams to get up and running with Kafka and are able to start producing and/or consuming events in minutes. It’s our mission to make streaming simple.
Now, let’s dive into the good stuff.
Most organisations have a process for reporting and processing incident reports and in our use case the incident reports are created and updated by an application that stores the data in a PostgreSQL database.
Change Data Capture will be used to capture the creation, updates and deletion of reports in the database and publish them on the Axual Platform to allow other systems to consume and process the events.

The table IncidentReports from the Incidents schema will be read by the Debezium Connector in Kafka Connect, which will load any new, updated or deleted data entries to the appropriate topic in the Kafka Cluster.
The incident report changes should go to the topic cdc-incident-reports.
The transaction metadata events that are captured from the database should be sent to the topic cdc-transactions.

The following resources are needed to configure the connector using Axual Self Service
psql on the machine running the database to modify the IncidentReports table.You should contact your local support team for Axual platform to get access to Self Service or to get the connector installed in your deployment.
The support team should also be able to help on the correct procedure to get your certificate signed.
If you don’t have these resources you can contact the support team for your Axual Platform deployment to help you
Most database tables will already contain records. This can be considered the initial state when performing Change Data Capture.
Debezium will read and publish these records on Kafka with an indicator that the record comes from existing data, and was not a captured change.
The IncidentReports table needs to be filled with some data as well to demonstrate this behaviour. The example code will use the psql client on the database server to insert the data.
psql -U <username> -d <database name> -h <hostname> -p <port number>INSERT INTO INCIDENTS."IncidentReports"( "Reporter", "Description", "Report" )
VALUES ('Richard', 'System NP123 offline', 'Non Production System 123 is offline' ),
('Eric', 'System P001 Unreachable', 'Production System 001 is rejecting all connections' );
SELECT * FROM INCIDENTS."IncidentReports"; IncidentId | Reporter | Description | Report | Status
------------+----------+-------------------------+----------------------------------------------------+--------
1 | Richard | System NP123 offline | Non Production System 123 is offline | OPEN
2 | Eric | System P001 Unreachable | Production System 001 is rejecting all connections | OPEN
(2 rows)
The streams, or topics, on the Kafka clusters needed by Debezium need to be created using the Axual Self Service portal since the Axual platform does not allow direct topic creations on a cluster by applications.
Debezium determines the target topic of a change event based on the names of the database, schema and table where the change occurred. In the guide we will override this behaviour to direct the event to correct stream by using a Debezium supplied routing transformation for Connect.
This routing transformation is installed as part of the Debezium connector.
Two streams will be created, cdc-incident-reports for the changed records from the IncidentReports table, and cdc-incident-transactions for the database transaction events that were captured by Debezium.




The two streams are now configured on you Kafka Cluster, but no application is registered yet to produce or consume data from these streams.




database.dbname = <database name>
databasse.hostname = <hostname where to reach the database>
database.port = <port number where database is listening>
database.server.name = incidentdb
database.user = cdcUser
database.password = cdcDemoschema.include.list = INCIDENTSplugin.name = pgoutput
publication.autocreate.mode = filtered
publication.name = incidents_publication
slot.name = incidents_slot
snapshot.mode = initial
tombstones.on.delete = false
transaction.topic = cdc-incident-transactionsheader.converter = org.apache.kafka.connect.storage.SimpleHeaderConverter
key.converter = org.apache.kafka.connect.json.JsonConverter
value.converter = org.apache.kafka.connect.json.JsonConverter
tasks.max = 1
transforms = Routing
transforms.Routing.type = io.debezium.transforms.ByLogicalTableRouter
transforms.Routing.topic.regex = .*
transforms.Routing.topic.replacement = cdc-incident-reports


The Debezium connector has created the initial records on the topic for data that is already in the database.
The new Kafka records can be shown with Axual Self Service


The IncidentReports table is filled with some from a previous step.
In this step new records will be created, and existing records will be altered and deleted in a single transaction. The example code will use the psql client on the database server to insert the data.
psql -U <username> -d <database name> -h <hostname> -p <port number>SELECT * FROM INCIDENTS."IncidentReports"; IncidentId | Reporter | Description | Report | Status
------------+----------+-------------------------+----------------------------------------------------+--------
1 | Richard | System NP123 offline | Non Production System 123 is offline | OPEN
2 | Eric | System P001 Unreachable | Production System 001 is rejecting all connections | OPEN
(2 rows)
START TRANSACTION;
INSERT INTO INCIDENTS."IncidentReports"( "Reporter", "Description", "Report" )
VALUES ('Ruth', 'Switch SW-P-12 rejects connections', 'The switch SW-P-12 is rejecting all connections' );
UPDATE INCIDENTS."IncidentReports"
SET "Status" = 'CLOSED' WHERE "Reporter" = 'Eric';
DELETE FROM INCIDENTS."IncidentReports"
WHERE "Reporter" = 'Richard';
COMMIT;
SELECT * FROM INCIDENTS."IncidentReports"; IncidentId | Reporter | Description | Report | Status
------------+----------+------------------------------------+----------------------------------------------------+--------
5 | Ruth | Switch SW-P-12 rejects connections | The switch SW-P-12 is rejecting all connections | OPEN
2 | Eric | System P001 Unreachable | Production System 001 is rejecting all connections | CLOSED
(2 rows)
The changes made in the previous steps have been captured by the Debezium connector as well, and can be viewed using Self Service.
The data format of the changes will be explained separately in a separate section.


The two main Debezium formats are for the Data Change Event and the Transaction Event.
{
"IncidentId" : 2,
"__dbz__physicalTableIdentifier": "incidentsdb.incidents.IncidentReports"
}
The key of a record consists of the primary key fields of the captured table containing the relevant values plus a special field:
This will always provide a unique record for a record in the database, and allows tombstone records to be set for Kafka compaction topics.
{
"before" : {
"IncidentId" : 2,
"Reporter" : "Eric",
"Description": "System P001 Unreachable",
"Report" : "Production System 001 is rejecting all connections",
"Status" : "OPEN"
},
"after" : {
"IncidentId" : 2,
"Reporter" : "Eric",
"Description": "System P001 Unreachable",
"Report" : "Production System 001 is rejecting all connections",
"Status" : "CLOSED"
},
"source":{
"version" : "1.9.2.Final",
"connector" : "postgresql",
"name" : "incidentsdb",
"ts_ms" : 1659955180497,
"snapshot" : "false",
"db" : "axualdb",
"sequence" : "[null,"24455872"]",
"schema" : "incidents",
"table" : "IncidentReports",
"txId" : 801,
"lsn" : 24455872,
"xmin" : null,
},
"op" : "u",
"ts_ms" : 1659955181012,
"transaction":{
"id" : "801",
"total_order" : 2,
"data_collection_order" : 2
}
}
The value of a record has the following fields:
{
"id": "801"
}
The key of a transaction record consists of just one field named “id”, the transaction identifier as string
{
"status" : "END",
"id" : "801",
"event_count" : 3,
"data_collections" :[
{
"data_collection" : "incidents.IncidentReports",
"event_count" : 3
}
]
}
The value of a transaction record has the following fields:
This blog is meant as a starting point for working with Debezium and PostgreSQL.
Both Debezium and PostgreSQL offer more advanced settings to capture changes made to a database, and their websites contain a lot of documentation on how to do this.
Are you excited about Axual and would you like to try our product yourself? You can get started here.