Multiple sources in one pipeline
Learn how to ingest from several source databases into one Redis target.
One RDI pipeline can capture changes from several source databases and write them all to the same Redis target. The sources can be of different database types and each has its own collector, its own credentials, and its own set of Redis streams to ensure it is independent of the other sources.
You must use RDI API v2 to manage a pipeline with several sources. RDI API v1 supports only single-source pipelines. See the RDI API migration guide for more information.
Name your sources
Each source is an entry in the sources section of
config.yaml,
with the source name as key:
sources:
mysql: # this source is named 'mysql'
type: cdc
A source name must:
- Start with a lowercase letter.
- Contain only lowercase letters, digits, and dashes.
- End with a letter or a digit.
- Be at most 22 characters long.
The names rdi and target are reserved and cannot be used for sources.
If your pipeline has a source created before RDI supported multiple sources, do not name a new source after any schema or database of that older source. The change data streams of the older source do not contain a source name segment, so a new source named after one of its schemas would claim keys that belong to the older source, and resetting or removing the new source would delete the older source's data. See Existing names are kept after an upgrade.
RDI derives the environment variables that contain the source's credentials from the source
name. For example, the connection section of a source named mysql references ${MYSQL_DB_USERNAME}
and ${MYSQL_DB_PASSWORD}. See
Set secrets
for details of how RDI derives those names and for the full list of secret keys.
The source name also appears in the resources RDI creates for the source. The table below
lists the names derived from a source named mysql.
| Resource | Name |
|---|---|
| Credentials secret | mysql-db |
| TLS secret | mysql-db-ssl |
| Environment variable prefix | MYSQL_DB_ |
| Certificate directory | /etc/certificates/mysql_db/ |
| Collector deployment | collector-mysql |
| Change data streams | data:{rdi}:mysql.<qualified_table_name> |
| Dead-letter queue streams | dlq:data:{rdi}:mysql.<qualified_table_name> |
| Metric collection | collector-mysql_metrics |
| Metrics endpoint path on a VM installation | /collector-mysql/metrics |
In the stream names, <qualified_table_name> is the qualified table name:
<database>.<table> for MySQL and MariaDB, <database>.<collection> for MongoDB,
<schema>.<table> for Oracle, PostgreSQL, Snowflake, and Spanner, and
<database>.<schema>.<table> for SQL Server.
Each source also accepts an optional name property, which is a display name
of up to 100 characters. Unlike the source name, it is not used as an identifier,
so there is no restriction on the characters you can use.
Configure several sources
Add one entry per source in the config.yaml file (see
Pipeline configuration file
for a full description of this file).
redis-di scaffold
generates a configuration with one source, named by its --source-name option, so add any
further sources by editing config.yaml.
Sources of different types can be mixed freely, but a source's collector type and its
connection type have to match. Use cdc, the default, for the relational databases and
MongoDB, flink for a Spanner connection, and riotx for a Snowflake connection. RDI
rejects any other combination when you deploy the pipeline. See
Prepare source databases
to learn how to prepare each source database.
The following example captures from a MySQL database and a PostgreSQL database, each with its own credentials:
sources:
mysql:
type: cdc
connection:
type: mysql
host: <MYSQL_DB_HOST>
port: 3306
user: ${MYSQL_DB_USERNAME}
password: ${MYSQL_DB_PASSWORD}
databases:
- inventory
tables:
inventory.customers: {}
inventory.orders: {}
postgresql:
type: cdc
connection:
type: postgresql
host: <POSTGRESQL_DB_HOST>
port: 5432
database: billing
user: ${POSTGRESQL_DB_USERNAME}
password: ${POSTGRESQL_DB_PASSWORD}
schemas:
- public
tables:
public.clients: {}
targets:
target:
connection:
type: redis
host: <TARGET_DB_HOST>
port: 6379
password: ${TARGET_DB_PASSWORD}
Set secrets for each source
Set a source's credentials with the source name in the --db option:
redis-di set-secret USERNAME --db mysql <username>
redis-di set-secret PASSWORD --db mysql <password>
redis-di set-secret USERNAME --db postgresql <username>
redis-di set-secret PASSWORD --db postgresql <password>
The secret keys used as CLI arguments are the same for every source: USERNAME, PASSWORD, and, for
Transport Layer Security (TLS)
connections, CACERT, CERT, KEY, and KEY_PASSWORD. Use --db target for the
target database: redis-di set-secret PASSWORD --db target <password>.
Each source's connection section then references its own secrets: ${MYSQL_DB_USERNAME} and
${MYSQL_DB_PASSWORD} for mysql, ${POSTGRESQL_DB_USERNAME} and ${POSTGRESQL_DB_PASSWORD}
for postgresql, and ${TARGET_DB_PASSWORD} for the target.
See Set secrets for the full secret reference.
Select sources in jobs
A job
selects the source it processes by setting server_name to the source name:
source:
server_name: mysql
db: inventory
table: customers
When a pipeline has more than one source, every job must set server_name, and the value
must match one of the sources in config.yaml. RDI rejects the pipeline when a job has no
server_name, or when its server_name matches no source. The one exception is the default
job for table: "*": it is a source-agnostic catch-all, so it needs no server_name.
For a source that existed before RDI supported multiple sources, set server_name to rdi
rather than to the name the source has in config.yaml. See
Existing names are kept after an upgrade.
In a pipeline with a single source, server_name is optional. If you omit it, the
job does not filter by source.
No two jobs may select the same records, so make sure the source selectors of your jobs do not overlap. RDI rejects the pipeline when it finds two jobs that intersect.
With the Flink processor,
server_name also accepts a list of source names, and an entry prefixed with regex: selects
all sources that match the regular expression, so one job can process multiple tables,
potentially from different sources, databases, or schemas. See
Job files
for details.
Add or remove a source
To add a source, set its secrets first, then add it to config.yaml and deploy. Adding a
source does not interrupt other sources that are already running.
To remove a source, delete its entry from config.yaml and deploy. RDI removes the source's
collector and deletes that source's data from the RDI database, including its change data streams,
Debezium offsets, schema history, dead-letter queue entries, statistics, deduplication state,
and record counters. The other sources keep their data, and RDI stops the whole pipeline
while the deletion runs and starts it again afterwards. No further action is
needed for this cleanup, but it means that a source you add later under the same name starts
from a new
initial snapshot
rather than from the position it had reached.
The source's secrets are not deleted, so remove them yourself with
redis-di delete-secret
if you no longer need them. The records the pipeline wrote to the target database are not deleted
either.
Adding the same source again is straightforward, unless the source you removed predates RDI's support for multiple sources. For such a source the names from before the upgrade are kept only while it exists, so any source you add under the same name is treated as a new source, for which RDI derives the names instead. Adapt the configuration accordingly:
- Set the source's secrets again, for example
redis-di set-secret PASSWORD --db mysql <password>. - Change the secret references in its
connectionsection from${SOURCE_DB_*}to${MYSQL_DB_*}, for a source namedmysql. - Change
server_namefromrdito the source name in every job associated with it.
See Redeploying a configuration after clearing a pipeline for a before and after example, and Existing names are kept after an upgrade for the full list of names involved.
Note that renaming a source is not supported. Renaming a source in config.yaml is equivalent
to removing the source and adding a new source with the new name. This implies in particular:
- You must create the source's secrets under the new name and update
${...}references in itsconnectionsection. - You must update
server_namefor every job that reads from the source. - The data present in the RDI database under the old name is deleted, as it is for any removed source.
- The source starts with a new initial snapshot.
Start, stop, and reset a single source
Pass --source to act on a single source instead of the whole pipeline:
redis-di stop --source mysql
redis-di start --source mysql
redis-di reset --source mysql
A source runs only while its pipeline runs, so starting one source does not start a stopped
pipeline. Generally, stopping one source leaves the others running, and when one source fails, the other sources keep capturing changes. The only exception to this is a source of type
external. RDI creates no collector for this, so you cannot start or stop it.
Stopping a source scales its collector down to zero replicas and leaves the rest of the source's resources in place. RDI records a captured position for each source, so when you restart a collector, it resumes from where it stopped.
Resetting a single source deletes that source's data from the RDI database, including its change data streams, Debezium offsets, schema history, dead-letter queue entries, statistics, deduplication state, and record counters. A new initial snapshot is then taken for that source, while every other source keeps its data. RDI stops the whole pipeline while the reset runs and starts it again afterwards, exactly as it does for a reset of the whole pipeline.
Monitor each source
Use redis-di describe
to see the state of every source at once.
In its output, the Sources section lists each source with its sync mode and
whether it is connected.
The Components section lists one collector per source. Errors are reported against the
component they came from. See the
redis-di describe
reference page for more details.
Note that while the sources are independent of each other in the data they capture, the
pipeline status is not broken down per source. RDI reports the whole pipeline in an error state when a
single source fails, so you should use the Components section to find out which one has failed.
Each Debezium collector has its own metric collection, named after the collector, such as
collector-mysql_metrics. The Flink and RIOT-X collectors don't have metric collections.
In Prometheus, you can break the per-stream record counters down per source, since the stream
name contains the source name. With the
Flink processor
the counters are reported by
flink_jobmanager_job_operator_coordinator_stream_type_rdiRecords, which has a stream
label; with the classic processor they are reported by rdi_incoming_entries, which has an
equivalent data_source label. See
Flink processor metrics,
Stream processor metrics,
and, for the per-source collector endpoints,
Accessing the metrics.
Dead-letter queue streams have Redis keys containing a
<source>.<qualified_table_name> section.
This makes it easy to attribute rejected records to their source. See
Rejected records for more information.
Existing names are kept after an upgrade
Before RDI supported multiple sources per pipeline, every source-scoped resource had
a name including the word source instead of the actual source name in config.yaml.
For a source that existed before you upgraded to a version that supports multiple sources,
those names are kept unchanged, regardless of what the source is called in config.yaml.
In particular, for such a source:
- Its secret environment variables are still named
SOURCE_DB_*, so itsconnectionsection can keep referencing these secrets. - Its Kubernetes secrets are still named
source-dbandsource-db-ssl. - Its Kubernetes deployment and other resources are still named
collector-source. - Its data streams are still named
data:{rdi}:<qualified_table_name>, and its offset and schema history keys are stillmetadata:debezium:offsetsandmetadata:debezium:schema_history. - Its
server_nameis stillrdi, or, for a Spanner source, its instance ID.
RDI keeps these names in a mapping from the source name in config.yaml to
the internal name the source had before the upgrade. This mapping lasts only as long as the source
does: RDI discards it as soon as the source is removed from the configuration, whether you remove that one
source or
clear the whole pipeline.
A source you add afterwards under the same name is treated as a new source, so
RDI derives its names from the source name. See
Add or remove a source for what you have to change in that case.
For a source you add after the upgrade under any other name, RDI derives all of these names from the source name, as described on this page.
See Upgrading RDI for more information.
Redeploying a configuration after clearing a pipeline
A configuration exported from an upgraded pipeline still references the names from before the upgrade, so deploying it again after clearing the pipeline fails, because the mapping that made those names resolve is gone.
A source and a job of such an upgraded pipeline:
sources:
mysql:
connection:
user: ${SOURCE_DB_USERNAME}
password: ${SOURCE_DB_PASSWORD}
source:
server_name: rdi
db: inventory
table: customers
The same source and job, adapted to deploy as a new source named mysql:
sources:
mysql:
connection:
user: ${MYSQL_DB_USERNAME}
password: ${MYSQL_DB_PASSWORD}
source:
server_name: mysql
db: inventory
table: customers
Set the source's secrets under its actual name before you deploy:
redis-di set-secret USERNAME --db mysql <username>
redis-di set-secret PASSWORD --db mysql <password>
The source then takes a fresh initial snapshot, because the position it had reached was deleted along with the rest of its data. Records the pipeline already wrote to the target database are not deleted, so the snapshot overwrites them.