8000 Evaluate YugabyteDB as a PostgreSQL database in tests by ahus1 · Pull Request #54731 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content

Evaluate YugabyteDB as a PostgreSQL database in tests - #54731

Draft
ahus1 wants to merge 4 commits into
keycloak:mainfrom
ahus1:is-54726-yugabyte
Draft

ahus1 wants to merge 4 commits into
keycloak:mainfrom
ahus1:is-54726-yugabyte

Conversation

@ahus1
@ahus1 ahus1 commented Nov 5, 2026 •
Copy link
Copy Markdown
Member

Closes #54726

Spike to evaluate Keycloak on YugabyteDB, used as a plain PostgreSQL database (--db=postgres, no dedicated Keycloak database vendor).

Test wiring

  • New test framework module test-framework/db-yugabyte, selected with KC_TEST_DATABASE=yugabyte. The test database is created non-colocated, as colocated tables would hide the multi-tablet behavior.
  • New CI job in ci.yml running the store tests against YugabyteDB. It runs nightly, on manual dispatch, or when a commit message contains [yugabyte ci].

Changes needed for YugabyteDB

  • Liquibase runs in auto-commit mode (YugabyteDatabase), as DDL inside a transaction fails with schema version mismatch. Indexes are created with NONCONCURRENTLY (YugabyteCreateIndexGenerator), as a plain CREATE INDEX waits for the idle-in-transaction lock connection. Auto-commit is not atomic, so a failed migration leaves a partial schema that needs to be dropped manually.
  • Concurrent INSERT ... ON CONFLICT statements for the same new key deadlock when the table has a secondary index, and YugabyteDB can't retry the aborted READ COMMITTED transaction. JpaUtils.lockForUpsert takes a transaction-scoped advisory lock on the entity name and key before the upsert, and does nothing on other databases. This can be removed once [YSQL] Concurrent INSERT ... ON CONFLICT DO NOTHING for the same new key fails with "deadlock detected" when the table has a secondary index yugabyte/yugabyte-db#37250 is fixed. It is used for root authentication sessions, login failures, revoked tokens and single-use objects. YugabyteDB is detected once at startup (JpaUtils.detectDatabaseProduct) from the version string.
  • DatabaseIndexChecker: strips NONCONCURRENTLY from the generated statements and quotes identifiers.

Test duration

The YugabyteDB job took 59 minutes in CI run 42361058279, compared to 17 to 22 minutes for the PostgreSQL, MySQL, SQL Server and Oracle jobs. The summed time per test class was 3,452 s on YugabyteDB against 1,235 s on PostgreSQL, a median per-class ratio of about 2x.

Most classes are 2 to 3 times slower, and the ones that create and delete many realms are 3 to 5 times slower, for example AccountRestServiceLightweightTokenTest (335 s against 94 s), LightWeightAccessTokenTest (228 s against 64 s) and OrganizationMemberTest (148 s against 38 s). The assumed culprit is realm creation and deletion: each touches many tables, and every commit is a distributed transaction across the tablets of the non-colocated tables. This has not been profiled.

Two further fixed costs add up: a fresh non-colocated schema takes about 400 s (240 s when colocated), and the job starts a new container for each of its two Maven runs. PreserveSchemaCaseLiquibaseTest and CaseSensitiveSchemaTest create their own schemas and take 191 s and 180 s, against 24 s and 34 s on PostgreSQL.

The test database is deliberately not colocated. During the migration on a colocated database, the transaction holding Keycloak's database lock was aborted and the release failed, and the exact trigger was not identified. Colocation might speed up the suite, but this has not been measured. A production database will never be colocated as it will not scale.

ahus1 and others added 4 commits November 12, 2026 10:24
[yugabyte ci]

Closes keycloak#54726

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
Quote the database name in the colocated database creation, allow a
configurable server start timeout (900s for Yugabyte), fall back to
DROP INDEX without CONCURRENTLY in the index checker, and tolerate
Yugabyte's duplicate key error and stale schema version in the index test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
Closes keycloak#54726

YugabyteDB bumps the catalog version on every DDL statement, and a session using an older cached version fails with "schema version mismatch" on its next statement in the same transaction. Run Liquibase in auto-commit mode on YugabyteDB to avoid this, while keeping Keycloak's database lock in a transaction.

As auto-commit would make index builds wait for the lock transaction, create indexes with NONCONCURRENTLY, and strip it again in the DatabaseIndexChecker. Create the test database non-colocated, as a colocated database aborted the lock transaction during the migration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
Concurrent INSERT ... ON CONFLICT statements for the same new key deadlock
on YugabyteDB when the table has a secondary index, and the query layer
can't retry the aborted READ COMMITTED transaction. Take a transaction-scoped
advisory lock on the key before the upsert.

Also log the full exception of failed transactions in ConcurrentUpsertTest.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Alexander Schwartz <alexander.schwartz@ibm.com>
@ahus1
ahus1 force-pushed the is-54726-yugabyte branch from 5b1b24a to fb900cd Compare November 12, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evaluate current compatibility with YugabyteDB

1 participant

0