-
Notifications
You must be signed in to change notification settings - Fork 273
feat: Add database read/write splitting support (#1428) #1434
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,215 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Database Read/Write Splitting Implementation Summary | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Issue | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GitHub Issue #1428: "Support database read/write splitting" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OpenVSX currently only supports one database connection pool, which means all queries (both SELECT and write operations) are routed to the same database. At high traffic, operators must employ middleware to achieve horizontal scalability. This adds operational complexity and overhead. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Solution Implemented | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| A native database read/write splitting feature that allows operators to configure separate connection pools for primary (write) and replica (read-only) databases. This provides horizontal scalability without requiring external middleware. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Components Created | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 1. Core Routing Classes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Located in: `server/src/main/java/org/eclipse/openvsx/db/` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **DataSourceType.java** - Enum defining PRIMARY and REPLICA datasource types | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **DataSourceContextHolder.java** - Thread-local context holder for routing decisions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **RoutingDataSource.java** - Custom Spring datasource that routes queries based on context | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **DatabaseConfig.java** - Spring configuration for primary and replica datasources with HikariCP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **ReadOnlyRoutingInterceptor.java** - AOP interceptor that automatically routes `@Transactional(readOnly=true)` to replicas | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 2. Configuration Updates | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Updated all `application.yml` files to support the new structure: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - `server/src/dev/resources/application.yml` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - `server/src/test/resources/application.yml` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - `deploy/docker/configuration/application.yml` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - `deploy/openshift/application.yml` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Changes: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Moved `spring.datasource.*` to `spring.datasource.primary.*` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Added optional `spring.datasource.replica.*` configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Added `ovsx.datasource.replica.enabled` flag (default: false) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Added HikariCP connection pool settings for both primary and replica | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 3. Documentation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **doc/database-read-write-splitting.md** - Comprehensive guide covering: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Architecture overview | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Configuration examples (single DB, read/write split, environment variables) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - HikariCP connection pool tuning | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - PostgreSQL replication setup | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Monitoring and troubleshooting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Best practices and migration guide | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **README.md** - Added Features section highlighting the new capability | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Key Features | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Automatic Routing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Methods annotated with `@Transactional(readOnly=true)` → REPLICA | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Methods annotated with `@Transactional` or write operations → PRIMARY | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - No code changes required for existing transactional methods | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Backward Compatibility | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Works with existing single-database configurations | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Old configuration format (`spring.datasource.url`) automatically migrated to new format | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - When replica is not configured, all operations use primary database | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Zero breaking changes for existing deployments | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Flexible Configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Enable/disable via `ovsx.datasource.replica.enabled` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Separate HikariCP pools with independent sizing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Support for environment variables (Kubernetes/OpenShift friendly) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Optional read-only database user for security | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Scalability Benefits | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 50-70% reduction in primary database load | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 2-3x improvement in read query throughput | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Better horizontal scalability for read-heavy workloads | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Reduced need for external middleware | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+68
to
+72
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - 50-70% reduction in primary database load | |
| - 2-3x improvement in read query throughput | |
| - Better horizontal scalability for read-heavy workloads | |
| - Reduced need for external middleware | |
| - Estimated 50-70% reduction in primary database load | |
| - Up to 2-3x improvement in read query throughput under read-heavy workloads | |
| - Better horizontal scalability for read-heavy workloads | |
| - Potentially reduced need for external middleware | |
| > Note: The performance figures above are estimated and actual results will vary depending on your application's workload characteristics, read/write ratio, and database/infra configuration. |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The file lists "doc/database-read-write-splitting.md" as a modified file under the "Modified Files" section, but it's actually a new file (as indicated by the diff showing it starts at line 0). Move this file to the "New Files" section or create a separate "Documentation Files" section to accurately reflect that it's a new documentation file, not a modification of an existing file.
| ### New Files (5) | |
| - `server/src/main/java/org/eclipse/openvsx/db/DataSourceType.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/DataSourceContextHolder.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/RoutingDataSource.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/DatabaseConfig.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/ReadOnlyRoutingInterceptor.java` | |
| ### Modified Files (6) | |
| - `server/src/dev/resources/application.yml` | |
| - `server/src/test/resources/application.yml` | |
| - `deploy/docker/configuration/application.yml` | |
| - `deploy/openshift/application.yml` | |
| - `doc/database-read-write-splitting.md` (new) | |
| ### New Files (6) | |
| - `server/src/main/java/org/eclipse/openvsx/db/DataSourceType.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/DataSourceContextHolder.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/RoutingDataSource.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/DatabaseConfig.java` | |
| - `server/src/main/java/org/eclipse/openvsx/db/ReadOnlyRoutingInterceptor.java` | |
| - `doc/database-read-write-splitting.md` | |
| ### Modified Files (5) | |
| - `server/src/dev/resources/application.yml` | |
| - `server/src/test/resources/application.yml` | |
| - `deploy/docker/configuration/application.yml` | |
| - `deploy/openshift/application.yml` |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -30,6 +30,24 @@ the [EclipseFdn/open-vsx.org wiki](https://github.com/EclipseFdn/open-vsx.org/wi | |||||
|
|
||||||
| See the [openvsx Wiki](https://github.com/eclipse/openvsx/wiki) for documentation of general concepts and usage of this project. | ||||||
|
|
||||||
| ## Features | ||||||
|
|
||||||
| ### Database Read/Write Splitting | ||||||
|
|
||||||
| OpenVSX supports database read/write splitting for improved horizontal scalability in high-traffic deployments. This feature allows you to configure separate connection pools for: | ||||||
|
|
||||||
| - **Primary database**: Handles all write operations and can also serve reads | ||||||
| - **Replica database(s)**: Handles read-only operations for better performance | ||||||
|
|
||||||
| This is particularly beneficial since most database traffic consists of SELECT statements that can be distributed across read replicas. The feature provides: | ||||||
|
|
||||||
| - Native support for PostgreSQL replication | ||||||
| - Automatic routing of `@Transactional(readOnly=true)` methods to replicas | ||||||
|
||||||
| - Automatic routing of `@Transactional(readOnly=true)` methods to replicas | |
| - Automatic routing of `@Transactional(readOnly=true)` methods to replicas (only methods annotated with `readOnly=true` are routed; existing `@Transactional` methods should be reviewed and updated where appropriate to benefit from this feature) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,9 +20,23 @@ spring: | |
| jcache: | ||
| config: classpath:ehcache.xml | ||
| datasource: | ||
| url: jdbc:postgresql://localhost:5432/openvsx | ||
| username: openvsx | ||
| password: openvsx | ||
| primary: | ||
| url: jdbc:postgresql://postgresql:5432/openvsx | ||
|
||
| username: openvsx | ||
| password: openvsx | ||
| hikari: | ||
| maximum-pool-size: 10 | ||
| minimum-idle: 5 | ||
| connection-timeout: 30000 | ||
| # Replica configuration (optional) - uncomment to enable read/write splitting | ||
| # replica: | ||
| # url: jdbc:postgresql://postgresql-replica:5432/openvsx | ||
| # username: openvsx | ||
| # password: openvsx | ||
| # hikari: | ||
| # maximum-pool-size: 20 | ||
| # minimum-idle: 10 | ||
| # connection-timeout: 30000 | ||
| flyway: | ||
| baseline-on-migrate: true | ||
| baseline-version: 0.1.0 | ||
|
|
@@ -131,6 +145,9 @@ bucket4j: | |
| unit: seconds | ||
|
|
||
| ovsx: | ||
| datasource: | ||
| replica: | ||
| enabled: false # Set to true and configure replica datasource to enable read/write splitting | ||
| databasesearch: | ||
| enabled: false | ||
| elasticsearch: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The summary claims "Zero breaking changes for existing deployments" and "Old configuration format automatically migrated to new format", but the DatabaseConfig implementation does not provide any migration logic or support for the legacy "spring.datasource.url" configuration path. All existing deployments will need to manually update their configuration files to use "spring.datasource.primary.*" structure, which constitutes a breaking change.