Greenplum agent
Target Greenplum
Greenplum speaks the PostgreSQL wire protocol, so this agent is the PostgreSQL target with Greenplum’s connection defaults, a bulk path built for Greenplum’s segments, and table creation that sets the distribution policy and the storage of the tables.
Prerequisites
To have Gluesync writing into your Greenplum cluster you will need:
-
The host, port and database of the coordinator, and a user that can log in to it from Core Hub: the coordinator’s
pg_hba.confmust allow the Core Hub host; -
A user with these privileges:
-
CREATEon the database, so that the agent creates itsGLUESYNChelper schema (schema of the staging tables of bulk operations). Without it, create the schema yourself and turn on Disable automatic schema creation; -
CREATEon the schema of the tables the agent creates, or, for tables that already exist,SELECT,INSERT,UPDATE,DELETEandTRUNCATEon them; -
The
CREATEEXTTABLErole attribute for readablegpfdistexternal tables, if the bulk path loads throughgpfdist(bulk load methodAUTOorGPFDIST). With theCOPYmethod it is not needed.
-
-
The agent does not need a superuser;
-
Network access from Core Hub to the coordinator and, for the
gpfdistload, from every segment host to Core Hub. See Network requirements of gpfdist.
CREATE ROLE gluesync LOGIN PASSWORD '<password>';
GRANT CONNECT, CREATE ON DATABASE <database> TO gluesync;
GRANT USAGE, CREATE ON SCHEMA <schema> TO gluesync;
-- Only for the gpfdist load. Same syntax on Greenplum 6 and 7.
ALTER ROLE gluesync CREATEEXTTABLE (type='readable', protocol='gpfdist');
Without the attribute, creating a readable gpfdist external table fails with permission denied: no privilege to create a readable gpfdist(s) external table. With the AUTO method the agent then loads with COPY, see Troubleshooting.
Setup via Web UI
-
Hostname / IP Address: DNS record or IP address of the coordinator;
-
Port: Optional, defaults to
5432; -
Database name: Name of your target database, defaults to
postgres; -
Username: User with the privileges above, defaults to
gpadmin; -
Password: Password belonging to the given username;
-
Enable TLS: off by default. See TLS;
-
Trust server certificate: on by default.
Specific configuration
The agent has two groups of settings: the settings of the connection (host-level), which the setup wizard asks for when you connect the agent, and the settings of the agent (agent-level), which apply to every table of the pipeline’s target.
Host-level settings
| Setting | Default | Meaning |
|---|---|---|
Use connection pool ( |
|
Uses a pool of connections to the coordinator. |
Gluesync schema name (necessary for bulk operations) ( |
|
Schema of the staging tables of bulk operations. |
Disable automatic schema creation ( |
|
Turn it on when the connection user must not create schemas, and create the Gluesync schema yourself. |
Bulk load method ( |
|
How the bulk path loads the spool file into the staging table: |
gpfdist port ( |
|
Port of the embedded |
gpfdist bind address ( |
|
Address the embedded |
gpfdist advertised host ( |
empty |
Host name or address the segments use to reach the |
Minimum bytes of a flush loaded through gpfdist by the AUTO method ( |
|
With |
Spool directory of the bulk path ( |
empty |
Directory of the spool files. Empty means |
gpfdist TLS keystore path ( |
empty |
Path of a PKCS12 keystore with the certificate of the |
gpfdist TLS keystore password ( |
empty |
Password of the keystore. Required when the keystore path is set. |
gpfdist TLS truststore path ( |
empty |
Path of a PKCS12 truststore with the CA that signs the client certificates of the segments. When set, every segment must present a client certificate signed by that CA; when empty, the segments are not asked for a certificate. |
gpfdist TLS truststore password ( |
empty |
Password of the truststore. |
gpfdist write timeout in seconds ( |
|
A segment that reads nothing for this long loses its connection to the |
A value that is not valid fails the connection with a message that names the setting. A change of the gpfdist settings applies at the next load.
Agent-level settings
| Setting | Default | Meaning |
|---|---|---|
Storage type of the tables the agent creates ( |
|
|
Compression of the append-optimized tables the agent creates ( |
|
|
Compression level ( |
|
|
Disable truncate on target table before snapshot inserts ( |
|
Keeps the rows of the target table when a snapshot starts. See Target advanced settings. |
State Preservation Table Name Prefix ( |
empty |
Prefix of the state preservation tables. See PostgreSQL target advanced settings. |
The storage settings apply to the tables the agent creates from now on. They do not change tables that exist.
Entity settings
The entities of the pipeline have the PostgreSQL target’s write settings:
| Setting | Default | Meaning |
|---|---|---|
Max Write Batch Size ( |
|
Rows of an |
Max Delete Batch Size ( |
|
Rows of a |
Max Write Bulk Size ( |
|
Rows a snapshot spools before the bulk path loads them. During CDC every call loads what it received. |
SQL Pre-Snapshot start command, SQL Post-Snapshot stop command, SQL Pre-CDC start command, SQL Post-CDC stop command |
empty |
SQL that runs on the target at the start and at the end of the snapshot and of CDC. See Target advanced settings. |
Write paths
Batch path
With bulk operations off, the agent writes the changes with JDBC batches: INSERT batches, DELETE batches, and for an upsert an UPDATE … FROM followed by an INSERT of the keys that were not updated. The statements never use ON CONFLICT or MERGE, so they run on Greenplum 6 and 7.
Whether a duplicate key is rejected, and so whether the On duplicate key strategy of the entity applies, depends on the table: it needs a unique index, which the tables the agent creates have, except the append-optimized tables on Greenplum 6. See Insert conflict strategy.
Bulk path
The bulk path is on per entity: Use bulk operations during Snapshot and Use bulk operations during CDC, which you toggle from the play/pause panel of the entity. It works as follows:
-
The agent encodes each row as a line of tab-delimited text and appends it to a spool file in the spool directory of Core Hub (UTF-8, one row per line);
-
During CDC the spool is flushed on every call. During a snapshot it is flushed when it holds Max Write Bulk Size rows, and when the snapshot ends;
-
The flush loads the spool file into a staging table in the Gluesync schema, in one transaction, by the Bulk load method:
-
GPFDIST: the agent registers the file in its embeddedgpfdistserver under a random path, creates a temporary readable external table overgpfdist://<advertised host>:<port>/<path>and runsINSERT INTO <staging table> SELECT … FROM <external table>. Every primary segment pulls its share of the file in parallel, so the load grows with the number of segments; -
COPY: the agent streams the file throughCOPY … FROM STDINon the coordinator, so every row passes through the coordinator; -
AUTO:GPFDISTwhen the reachability check passed and the flush is at least Minimum bytes of a flush loaded through gpfdist,COPYotherwise.
-
-
The staging table is merged into the target table in the same transaction (
DELETE … USINGthe staging table, thenINSERT … SELECTof the inserted and updated rows), and committed. The spool file is deleted after the commit. If the load fails, the transaction is rolled back, the staging table is truncated and the batch is retried, without writing the rows twice.
The staging table is a heap table in the Gluesync schema, distributed by the old key columns of the staging rows (<key>_OLD), so that the merge joins co-located rows when the target table is distributed by its primary key. A staging table of an entity without a key is distributed randomly.
When the target table has a valid B-tree index that starts with the key columns, the agent turns off hash and merge joins for the transaction of the merge (SET LOCAL), so that the merge uses the key index and its cost follows the size of the flush, not the size of the target table. The setting does not outlive the transaction.
The agent logs each flush at INFO level, with the rows, the bytes, the load method, the load time and the merge time.
Direct copy during snapshot
When bulk operations are on during the snapshot, the agent loads the rows of a flush straight into the target table, without a staging table, when both of these are true:
-
Every row of the flush is a full-row write (an insert, or an upsert under the Snapshot write method), not a delete;
-
The target table has an enforced unique key: a valid unique B-tree index on exactly the key columns of the entity, such as a primary key.
Every row is then written once. The load runs in one transaction with the load method of the flush. A flush that holds a delete goes through the staging table. Append-optimized tables created on Greenplum 6 have no primary key, so their snapshots always go through the staging table.
If the target table already holds a row with the same key, for example when Disable truncate on target table before snapshot inserts is on or when a snapshot resumes, Greenplum rejects the load with a duplicate key error. The agent rolls the transaction back, loads the same rows through the staging table, which replaces the rows of the same key (a delete and an insert), and keeps the entity on the staging table for the rest of the snapshot. It logs this at INFO level.
Network requirements of gpfdist
With the gpfdist load, the segments are the clients: every primary segment host opens a connection to Core Hub, to the advertised host and the gpfdist port (8580 by default). Core Hub does not connect to the segments. A coordinator that reaches Core Hub is not enough.
-
Open the
gpfdistport between every segment host and Core Hub, in both firewalls (host and network); -
The gpfdist advertised host must resolve, from every segment host, to the machine that runs Core Hub. When it is empty, the agent uses the host name of the Core Hub machine, which segment hosts often cannot resolve (a container’s host name never resolves outside it). Set it to a name or address of the Core Hub machine that the segment hosts can reach;
-
The port the segments connect to is the gpfdist port. A mapping that changes the port between the segments and Core Hub does not work;
-
The server listens on gpfdist bind address,
0.0.0.0by default. Narrow it to one interface if the machine has several and only one is reachable from the segments; -
Two Greenplum agents in the same Core Hub with the same bind address and port share one server, each with its own paths.
The server serves only the spool files that a load has registered, each under a random path, and removes the path when the load ends. The traffic of plain gpfdist is not encrypted: on a network you do not trust, use gpfdists.
Docker
Publish the gpfdist port of the Core Hub container, and set gpfdist advertised host to the address of the Docker host that the segment hosts can reach:
services:
core-hub:
ports:
- "8580:8580"
The published port must be the same as the gpfdist port, as the segments connect to the Docker host at that port.
Kubernetes
Expose the gpfdist port of the Core Hub pod with a Service (type LoadBalancer, or NodePort with the same port number as the gpfdist port), or with a hostPort, and set gpfdist advertised host to the address that the segment hosts use to reach it. Allow the port in the network policies between the segment hosts and the pod.
Reachability check
When an entity uses bulk operations and the method is AUTO or GPFDIST, the agent checks at setup that every primary segment can reach the server: it registers a one-row file, reads it through a temporary external table, and requires a request from every primary segment within 30 seconds.
-
With
GPFDIST, a segment that does not reach the server fails the setup with a message that names the advertised host and port; -
With
AUTO, the check ends with a warning and a notification, "gpfdist is not reachable", and the bulk path loads withCOPYuntil the next setup that passes the check.
With COPY the check is skipped.
TLS of gpfdist
To encrypt the load, both sides need certificates signed by the same CA. verify_gpfdists_cert stays at its default (on): the segments verify the server, and the server verifies the segments.
On the segments. In every data directory listed by SELECT datadir FROM gp_segment_configuration, create a gpfdists/ directory owned by gpadmin with these files (the segments read them; the copy in the coordinator’s data directory is harmless):
-
root.crt: the certificate of the CA, in PEM format; -
client.crt: a client certificate signed by that CA, in PEM format; -
client.key: the unencrypted PKCS#8 private key ofclient.crt, in PEM format, with mode0600.
In Gluesync. Set gpfdist TLS keystore path (gpfdistTlsKeystorePath) to a PKCS12 keystore that holds the server certificate and its private key, and gpfdist TLS keystore password (gpfdistTlsKeystorePassword). The certificate must be signed by the same CA, and its CN and SAN must match gpfdist advertised host. The agent then serves gpfdists, and the external tables use a gpfdists:// location. To require the client certificates of the segments, also set gpfdist TLS truststore path (gpfdistTlsTruststorePath) to a PKCS12 truststore that holds the CA, and its password; without a truststore the server does not ask the segments for a certificate.
When the load fails on TLS, the error of the agent names the gpfdists files, the keystore setting and the advertised host.
TLS of the connection
TLS is off by default, as Greenplum clusters often run without SSL. When Enable TLS is off, the connection does not use SSL.
-
With Enable TLS on and Trust server certificate on (default), the JDBC
sslmodeisrequire: the connection is encrypted and the certificate is not checked against a CA; -
With Enable TLS on and Trust server certificate off, the JDBC
sslmodeisverify-ca: the server certificate must be signed by a CA found in the trust store you provide in the connection settings (trust store path and password).
Tables and schemas
Gluesync can create the target tables, as it does for any SQL target (see Target table creation), and writes any table of the database that the connection user can write to. A table you create yourself is written as it is, with the distribution policy and the storage it has.
The schemas that Greenplum keeps for its own tools (gp_toolkit, pg_aoseg, pg_bitmapindex, pg_ext_aux) and the external and foreign tables are not listed in the discovery, and the full-catalog walk of Core Hub (see PII discovery and masking) treats those schemas as system schemas.
Table creation
The statement that Core Hub proposes for a new table has the form:
CREATE TABLE <schema>.<table> (
...,
PRIMARY KEY ("id")
) WITH (appendoptimized=true, orientation=column, compresstype=zstd, compresslevel=1)
DISTRIBUTED BY ("id")
-
Distribution:
DISTRIBUTED BYthe primary key columns, orDISTRIBUTED RANDOMLYfor a table without a primary key. The agent works with whatever distribution policy a table has, including the tables it did not create. To distribute a table by another key, edit the generated statement in the table creation screen before you run it: Core Hub runs the statement as you leave it; -
Storage: the
WITH (…)clause comes from the agent-level settings Storage type, Compression and Compression level. It is left out forHEAPtables. The clause is the same for every table the agent creates; -
Primary key on Greenplum 6: Greenplum 6 does not allow a primary key or a unique index on an append-optimized table. For
AO_ROWandAO_COLUMNthe agent leaves thePRIMARY KEYout of the statement and logs a warning, once per table. It then keeps the keys unique by itself: the bulk path replaces the rows of a key (a delete and an insert), and the batch path updates the row, or inserts it when it is missing. Greenplum 7 takes the primary key on append-optimized tables; -
macaddr8: Greenplum 6 does not have the type, and the agent refuses to create a table with amacaddr8column on it, with a message that suggestsmacaddror a text type.
Data types
The mapping is the PostgreSQL target’s, narrowed to the types Greenplum has. The default is the type the agent creates for a Gluesync type. A column can be mapped to the alternatives:
| Gluesync type | Default Greenplum type | Alternatives |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Arrays of the types above |
-
macaddr8exists on Greenplum 7 only. See Table creation; -
hstoreneeds the extension in the target database: runCREATE EXTENSION hstore;before the pipeline writes the column; -
Greenplum does not have the multirange types,
pg_snapshot,geometry,geography,raster,vectorandtinyint: they are not offered in the mapping.
Updates with bulk operations during CDC
|
When Use bulk operations during CDC ( For the target table this has the following effects:
|
Troubleshooting
| Issue | Solution |
|---|---|
|
The connection reached a PostgreSQL server, or another product. The agent reads |
|
A segment host cannot open a connection to the advertised host and port. Check the firewall between every segment host and Core Hub, that gpfdist advertised host resolves to Core Hub from the segment hosts, and the gpfdist port. In Docker and Kubernetes the port must be published or exposed, see Network requirements of gpfdist. The message ends with the reason: |
|
The same cause. The agent keeps working and loads with |
The probe fails with |
The connection user lacks the external table privilege. Run |
|
You added a primary key or a unique index to an append-optimized table on Greenplum 6. Remove it: the agent works without it. |
|
Map the column to |
|
Install the extension in the target database with |
The connection fails with a message that names |
The value of that setting is not valid, see the ranges in Specific configuration. The message states the expected range. |
Segments reject |
Check, on every segment data directory, the |
The disk of Core Hub fills during a large load |
The spool file holds the rows of a flush as text until the load commits. Point Spool directory of the bulk path to a volume with space for Max Write Bulk Size rows, or lower the setting. The agent deletes the spool files of a run that was interrupted when it starts again. |
Setup via Rest APIs
Here following an example of calling the Core Hub’s Rest API via curl to setup the connection for this Agent.
Connect the agent
curl --location --request PUT 'http://core-hub-ip-address/pipelines/{pipelineId}/agents/{agentId}/config/credentials' \
--header 'Content-Type: application/json' \
--header 'Authorization: ••••••' \
--data '{
"hostCredentials": {
"connectionName": "myAgentNickName",
"host": "greenplum-coordinator-address",
"port": 5432,
"databaseName": "db_name",
"username": "gluesync",
"password": "",
"maxConnectionsCount": 100,
"enableTls": false,
"trustServerCertificate": true
},
"customHostCredentials": {
"bulkLoadMethod": "AUTO",
"gpfdistPort": 8580,
"gpfdistAdvertisedHost": "core-hub.example.com"
}
}'
The keys under customHostCredentials are the host-level settings, named as in parentheses in Specific configuration. A setting you leave out has its default.