Reading and Writing Apache Fluss™
Configure VERA SQL jobs and Java applications to connect to Apache Fluss, write and read its tables, and read tiered tables with each catalog's credentials.
On this page
Applies to: the Fluss connector and the Fluss Java client, with client setups from Docker image registry.ververica.cloud/platform-images/fluss:1.0.0-vv-3
Overview
This manual covers configuring a VERA SQL job or a Java application to connect to Fluss, write to it, read from it, and read the tables Fluss tiers into a lake. Jobs run on Ververica Platform 3. Table kinds, their DDL, startup modes, and other table features are in the Apache Fluss documentation.
Prerequisites
- A running Fluss cluster and its bootstrap address,
<BOOTSTRAP_ADDRESS>. See Connecting to Fluss. - With SASL on the client listener, a client user,
<CLIENT_USERNAME>, and its password. For the server's SASL configuration and its users, see Securing Fluss. - Pull access to
registry.ververica.cloud, to run the setup installer from the Fluss image. See Obtaining Registry Access.
The Apache Fluss Catalog
A VERA SQL job reaches Fluss through a Fluss catalog. The SQL in this manual runs in a SQL draft on Ververica Platform 3: see Creating a Draft and Running Statements in the SQL Editor.
Connecting
Without authentication, the catalog needs the bootstrap address only:
1CREATE CATALOG fluss WITH (
2 'type' = 'fluss',
3 'bootstrap.servers' = '<BOOTSTRAP_ADDRESS>'
4);With SASL on the client listener, the catalog carries the client user's credentials. The password is a secret value, fluss-password here (see Creating Secret Values):
1CREATE CATALOG fluss WITH (
2 'type' = 'fluss',
3 'bootstrap.servers' = '<BOOTSTRAP_ADDRESS>',
4 'client.security.protocol' = 'sasl',
5 'client.security.sasl.mechanism' = 'PLAIN',
6 'client.security.sasl.username' = '<CLIENT_USERNAME>',
7 'client.security.sasl.password' = '${secret_values.fluss-password}'
8);
9
10USE CATALOG fluss;
11USE `<DATABASE>`;Beyond the bootstrap address and its default database, the catalog accepts only client.security.* options and the lake credentials of Lake Credentials, and rejects any other option: the object store's options are set per query instead, as Options by Object Store shows. For the connector's options, see Ververica's Fluss connector page and the upstream Fluss connector options.
Lake Credentials
A read of a tiered table needs the lake catalog's credentials, which the Fluss server does not hand to clients. Add them to the catalog as the Iceberg catalog's own properties, each prefixed with iceberg. and each a secret value. For each tested lake catalog:
A Lakekeeper catalog, on any store:
1CREATE CATALOG `<LAKE_CATALOG_NAME>` WITH (
2 'type' = 'fluss',
3 'bootstrap.servers' = '<BOOTSTRAP_ADDRESS>',
4 'client.security.protocol' = 'sasl',
5 'client.security.sasl.mechanism' = 'PLAIN',
6 'client.security.sasl.username' = '<CLIENT_USERNAME>',
7 'client.security.sasl.password' = '${secret_values.fluss-password}',
8 'iceberg.token' = '${secret_values.iceberg-token}'
9);A Polaris catalog, on Amazon S3:
1CREATE CATALOG `<LAKE_CATALOG_NAME>` WITH (
2 'type' = 'fluss',
3 'bootstrap.servers' = '<BOOTSTRAP_ADDRESS>',
4 'client.security.protocol' = 'sasl',
5 'client.security.sasl.mechanism' = 'PLAIN',
6 'client.security.sasl.username' = '<CLIENT_USERNAME>',
7 'client.security.sasl.password' = '${secret_values.fluss-password}',
8 'iceberg.credential' = '${secret_values.iceberg-credential}',
9 'iceberg.s3.access-key-id' = '${secret_values.s3-access-key-id}',
10 'iceberg.s3.secret-access-key' = '${secret_values.s3-secret-access-key}'
11);A JDBC catalog, on Amazon S3 or an S3-compatible store:
1CREATE CATALOG `<LAKE_CATALOG_NAME>` WITH (
2 'type' = 'fluss',
3 'bootstrap.servers' = '<BOOTSTRAP_ADDRESS>',
4 'client.security.protocol' = 'sasl',
5 'client.security.sasl.mechanism' = 'PLAIN',
6 'client.security.sasl.username' = '<CLIENT_USERNAME>',
7 'client.security.sasl.password' = '${secret_values.fluss-password}',
8 'iceberg.jdbc.password' = '${secret_values.jdbc-password}',
9 'iceberg.s3.access-key-id' = '${secret_values.s3-access-key-id}',
10 'iceberg.s3.secret-access-key' = '${secret_values.s3-secret-access-key}'
11);On an S3-compatible store, a read through a JDBC catalog also sets these JVM options in the job's Flink configuration:
1env.java.opts.all: "-Daws.requestChecksumCalculation=when_required -Daws.responseChecksumValidation=when_required"A JDBC catalog, on Azure Blob Storage:
1CREATE CATALOG `<LAKE_CATALOG_NAME>` WITH (
2 'type' = 'fluss',
3 'bootstrap.servers' = '<BOOTSTRAP_ADDRESS>',
4 'client.security.protocol' = 'sasl',
5 'client.security.sasl.mechanism' = 'PLAIN',
6 'client.security.sasl.username' = '<CLIENT_USERNAME>',
7 'client.security.sasl.password' = '${secret_values.fluss-password}',
8 'iceberg.jdbc.password' = '${secret_values.jdbc-password}',
9 'iceberg.adls.auth.shared-key.account.name' = '<STORAGE_ACCOUNT>',
10 'iceberg.adls.auth.shared-key.account.key' = '${secret_values.adls-account-key}'
11);With a JDBC lake catalog, name the Fluss catalog after the server's datalake.iceberg.name, the name the JDBC catalog files its tables under. For the server's lake catalog, see Configuring Lake Tiering.
Configuring Writes
A writer installs the flink-connector setup (see Installing Fluss Setups):
1docker run --rm -v "$PWD/<LOCAL_DIR>":/output \
2 registry.ververica.cloud/platform-images/fluss:1.0.0-vv-3 \
3 /opt/fluss/bin/setup/install.sh client flink-connector --output-dir /output/flink-connectorIt uploads the JARs, as Uploading the JARs as Artifacts shows. A writer sends its rows to the Fluss server, which handles all object-storage I/O, so a writer needs no store credentials, whatever the cluster's object store.
A streaming SQL deployment then writes through the catalog:
1INSERT INTO <TABLE> SELECT * FROM <SOURCE_TABLE>;Configuring Reads
A VERA SQL read sets its setups and, on some object stores, its store options. Install each setup as Installing Fluss Setups shows.
Dependencies
A reader fetches data from the cluster's object store itself, so it needs the filesystem setup of that store: fs-s3 for Amazon S3 or an S3-compatible store, fs-azure for Azure Blob Storage. Install it, then upload its JARs (see Uploading the JARs as Artifacts):
1docker run --rm -v "$PWD/<LOCAL_DIR>":/output \
2 registry.ververica.cloud/platform-images/fluss:1.0.0-vv-3 \
3 /opt/fluss/bin/setup/install.sh client fs-s3 --output-dir /output/fs-s3A reader of tiered tables installs the lake-iceberg setup instead, and uploads all its JARs. Its --fs option names the object store: s3 on Amazon S3 or an S3-compatible store, abs on Azure Blob Storage. Its --catalog option names the lake catalog: rest for Lakekeeper and Polaris, jdbc-postgres for a JDBC catalog. For example, on Amazon S3 with Lakekeeper:
1docker run --rm -v "$PWD/<LOCAL_DIR>":/output \
2 registry.ververica.cloud/platform-images/fluss:1.0.0-vv-3 \
3 /opt/fluss/bin/setup/install.sh client lake-iceberg --fs s3 --catalog rest --output-dir /output/lake-icebergThe S3 filesystem JAR of 1.0.0-vv-3 has a known issue on the engine version vera-4.5-jdk11-flink-1.20: reading data in remote storage fails with NoSuchMethodError: Configuration.getEnumSet. On Amazon S3 or an S3-compatible store, install the S3 filesystem from the 0.9.1-vv-1 release. Of its JARs, use only fluss-fs-s3-0.9.1-vv-1.jar, in place of the S3 filesystem JAR that fs-s3 or lake-iceberg installs, and keep the Fluss Flink connector of 1.0.0-vv-3.
1docker run --rm -v "$PWD/<LOCAL_DIR>":/output \
2 registry.ververica.cloud/platform-images/fluss:0.9.1-vv-1 \
3 /opt/fluss/bin/setup/install.sh client fs-s3 --output-dir /output/fs-s3Every job uploads the Fluss Flink connector its setups install, even though the VERA engine ships its own Fluss connector: the one a setup installs comes with your Fluss release, so it might be more recent than the engine's, and the engine's built-in Fluss catalog rejects some of the lake credential options of Lake Credentials, such as iceberg.token.
For the union, lake-only, and snapshot queries on a tiered table, see the Quickstart: Fluss on Ververica Platform 3. Any Iceberg-compatible engine, such as Spark, Trino, or StarRocks, also reads a tiered table by attaching to the same Iceberg catalog and warehouse that Fluss tiers into.
Options by Object Store
Lake credentials go in the catalog (see Lake Credentials), but the object store's options are set at read time, as a query hint. What a read adds depends on the cluster's object store (see Configuring Remote Storage):
Amazon S3, and Azure Blob Storage with an OAuth service principal: nothing. The server hands the client short-lived credentials for the store.
An S3-compatible store without STS: the store's endpoint and access key, as client.fs.s3.* options in a query hint on every read. The catalog rejects them, and the read forwards a hint's client.* options to the client. Each credential is a secret value:
1SELECT * FROM <TABLE> /*+ OPTIONS('scan.startup.mode' = 'full',
2 'client.fs.s3.endpoint' = '<S3_ENDPOINT>',
3 'client.fs.s3.access.key' = '${secret_values.store-access-key}',
4 'client.fs.s3.secret.key' = '${secret_values.store-secret-key}',
5 'client.fs.s3.region' = '<S3_REGION>',
6 'client.fs.s3.path-style-access' = 'true') */;A read of a tiered table on such a store carries the same hint.
Azure Blob Storage with an account key only, when the cluster has no OAuth service principal: the account key as client.fs.fs.azure.account.key, in a query hint. The client strips the client.fs. prefix before handing a key to its filesystem, so the filesystem receives fs.azure.account.key:
1SELECT * FROM <TABLE> /*+ OPTIONS('client.fs.fs.azure.account.key' = '${secret_values.adls-account-key}') */;The Java Client
A Java application connects to Fluss through the Fluss Java client.
Connecting
The application passes a client configuration to ConnectionFactory. With SASL on the client listener, the configuration carries the same client.security.* keys as the catalog:
1import org.apache.fluss.client.Connection;
2import org.apache.fluss.client.ConnectionFactory;
3import org.apache.fluss.config.Configuration;
4
5Configuration conf = new Configuration();
6conf.setString("bootstrap.servers", "<BOOTSTRAP_ADDRESS>");
7conf.setString("client.security.protocol", "sasl");
8conf.setString("client.security.sasl.mechanism", "PLAIN");
9conf.setString("client.security.sasl.username", "<CLIENT_USERNAME>");
10conf.setString("client.security.sasl.password", "<CLIENT_PASSWORD>");
11Connection conn = ConnectionFactory.createConnection(conf);Without SASL, set bootstrap.servers only. Writing needs nothing more. For the client API, see the Apache Fluss documentation.
Reading
A reading application fetches data from the cluster's object store itself, so it puts that store's filesystem setup on its classpath, next to the application and its Fluss client: fs-s3 for Amazon S3 or an S3-compatible store, fs-azure for Azure Blob Storage. Install the setup with --output-dir, as in Dependencies, then:
1java -cp "<APP_DIR>/*:<LOCAL_DIR>/fs-s3/*" <MAIN_CLASS>On an S3-compatible store without STS, the application sets the store's client.fs.s3.* keys on its configuration:
1conf.setString("client.fs.s3.endpoint", "<S3_ENDPOINT>");
2conf.setString("client.fs.s3.access.key", "<ACCESS_KEY_ID>");
3conf.setString("client.fs.s3.secret.key", "<SECRET_ACCESS_KEY>");
4conf.setString("client.fs.s3.region", "<S3_REGION>");
5conf.setString("client.fs.s3.path-style-access", "true");On an Azure Blob Storage cluster with an account key only, it sets client.fs.fs.azure.account.key instead.
Troubleshooting
Connection refused or a DNS resolution error
The client cannot reach the bootstrap address. Check that the client runs on a network that resolves the services of the Fluss namespace, that the coordinator pod is ready, and that no NetworkPolicy blocks the bootstrap port.
ClassNotFoundException for FlussCatalogFactory or filesystem classes
The job lacks a setup: FlussCatalogFactory comes with the Fluss connector, and the filesystem classes with the fs-s3 or fs-azure setup, needed once a read reaches remote data. Add the setup's JARs, as Dependencies shows.
Authentication fails
The cluster has SASL on its client listener, and the client does not send a listed user's credentials. Add the client.security.* options to the catalog, as Connecting shows, or the same keys to the Java client's configuration.
IllegalStateException: Dynamic session credentials for Fluss on Azure Blob Storage
The cluster authenticates to Azure Blob Storage with an account key only, so the server has no delegation tokens to hand out. Pass the account key as client.fs.fs.azure.account.key, as Options by Object Store shows.
Reads fail on an S3-compatible store without STS
A read on such a store carries the store's endpoint and access key: in a query hint for a VERA SQL read, as Options by Object Store shows, or as client.fs.s3.* keys for the Java client, as Reading shows.
Further Reading
- Obtaining Registry Access: pull access to the Fluss image
- Deploying Fluss on Kubernetes: the bootstrap address
- Securing Fluss: the server's SASL configuration and its client users
- Installing Fluss Setups: installing a setup's client JARs
- Configuring Remote Storage: the cluster's object store
- Configuring Lake Tiering: the server's lake catalog and the tiering service
- Running Fluss Jobs on Ververica Platform 3: each console step
- Quickstart: Fluss on Ververica Platform 3: an end-to-end walkthrough, with the lake queries
- https://fluss.apache.org/docs/: upstream reference
- Apache Fluss connector: the Fluss connector on Ververica Platform 3
- https://fluss.apache.org/docs/engine-flink/options/: the Fluss connector's options
- https://fluss.apache.org/docs/maintenance/configuration/: configuration keys
- https://fluss.apache.org/docs/security/overview/: security and SASL
- Ververica Platform 3 getting started: Ververica Platform 3 onboarding
- Ververica Platform 3 reference: Ververica Platform 3 reference
- Ververica Platform 3 secret values: secret values