Skip to content

Commit 354df80

Browse files
committed
Docs: Add docs / guides for AWS Aurora (master + read replica)
1 parent 7afc6bc commit 354df80

3 files changed

Lines changed: 320 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ This project includes step-by-step guides for common datasource configuration sc
2323

2424
**See [docs/guides/README.md](docs/guides/README.md)** for:
2525
- [Creating DataSource pools](docs/guides/create-datasource-pool.md) — basic pools, read-only pools, Kubernetes deployment, AWS Lambda, and configuration reference
26+
- [AWS Aurora with dual DataSources](docs/guides/aws-aurora-read-write-split.md) — read-write endpoint separation with Ebean ORM integration
2627
- Instructions for AI agents to discover and follow these guides
2728

2829
These guides are designed for both developers and AI coding agents (Copilot, Claude, Cursor, etc.) to follow step-by-step instructions for common tasks.

docs/guides/README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@ Step-by-step guides written as instructions for AI agents and developers.
44

55
## Creating DataSource Pools
66

7-
Step-by-step guide covering common scenarios for creating and configuring connection pools.
7+
Step-by-step guides covering common scenarios for creating and configuring connection pools.
88

99
| Guide | Description |
1010
|-------|-------------|
11-
| [Create a DataSource Pool](create-datasource-pool.md) | Basic pool creation, read-only pools, Kubernetes configuration, AWS Lambda setup, and connection validation settings |
11+
| [Create a DataSource Pool](create-datasource-pool.md) | Basic pool creation, read-only pools, Kubernetes configuration, AWS Lambda setup, and configuration reference |
12+
13+
## AWS Aurora
14+
15+
Configuration guides for AWS Aurora database deployments.
16+
17+
| Guide | Description |
18+
|-------|-------------|
19+
| [AWS Aurora with Dual DataSources](aws-aurora-read-write-split.md) | Setup dual DataSource pools for Aurora read-write separation using read and write endpoints; integrate with Ebean ORM for automatic query routing; failover and monitoring |
1220

1321
---
1422

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
# Guide: AWS Aurora with Dual DataSources (Read-Write and Read-Only)
2+
3+
## Purpose
4+
5+
This guide provides step-by-step instructions for configuring ebean-datasource with AWS Aurora using two separate DataSource pools: one for read-write operations (primary endpoint) and one for read-only operations (reader endpoint). This pattern is commonly used to offload read traffic from the primary database.
6+
7+
---
8+
9+
## Prerequisites
10+
11+
- AWS Aurora database cluster (MySQL or PostgreSQL compatible)
12+
- Two Aurora endpoints available:
13+
- **Write endpoint:** For INSERT, UPDATE, DELETE, SELECT and transaction operations
14+
- **Reader endpoint:** For SELECT queries (read replica endpoint)
15+
- A Java project with Maven
16+
- `io.ebean:ebean-datasource` dependency already added
17+
- Ebean ORM configured for secondary datasource support
18+
- Database user credentials for both endpoints (can be same user if both endpoints support it)
19+
20+
---
21+
22+
## What is the Aurora Reader Endpoint?
23+
24+
AWS Aurora provides two types of endpoints:
25+
26+
- **Write endpoint (Cluster endpoint):** `mydb-cluster.123456789.us-east-1.rds.amazonaws.com`
27+
- Routes all write operations to the primary database instance
28+
- Can handle both reads and writes
29+
30+
- **Reader endpoint (Read-only endpoint):** `mydb-cluster-ro.123456789.us-east-1.rds.amazonaws.com`
31+
- Automatically distributes read operations across all read replicas
32+
- Cannot handle write operations
33+
- Better performance for read-heavy workloads
34+
35+
---
36+
37+
## Scenario: Setup Dual DataSources for Aurora
38+
39+
### Step 1 — Create the read-write (primary) DataSource
40+
41+
This pool connects to Aurora's write endpoint and handles all write operations.
42+
43+
```java
44+
DataSourcePool writePool = DataSourcePool.builder()
45+
.name("datasource-write")
46+
.url("jdbc:mysql://mydb-cluster.123456789.us-east-1.rds.amazonaws.com:3306/myapp")
47+
.username(System.getenv("DB_USERNAME"))
48+
.password(System.getenv("DB_PASSWORD"))
49+
.minConnections(3)
50+
.initialConnections(5)
51+
.maxConnections(20)
52+
.build();
53+
```
54+
55+
### Step 2 — Create the read-only DataSource
56+
57+
This pool connects to Aurora's reader endpoint and optimizes for read-only queries.
58+
59+
```java
60+
DataSourcePool readOnlyPool = DataSourcePool.builder()
61+
.name("datasource-read")
62+
.url("jdbc:mysql://mydb-cluster-ro.123456789.us-east-1.rds.amazonaws.com:3306/myapp")
63+
.username(System.getenv("DB_USERNAME"))
64+
.password(System.getenv("DB_PASSWORD"))
65+
.readOnly(true) // Signal read-only mode
66+
.autoCommit(true) // Skip transaction overhead
67+
.minConnections(5)
68+
.initialConnections(10)
69+
.maxConnections(50)
70+
.build();
71+
```
72+
73+
### Step 3 — Configure Ebean with dual datasources
74+
75+
When using Ebean ORM, configure the secondary (read-only) datasource. Ebean will automatically route read queries to the secondary datasource.
76+
77+
```java
78+
Database database = DatabaseBuilder.create()
79+
.datasource(writePool) // Primary write datasource
80+
.secondaryDatasource(readOnlyPool) // Secondary read-only datasource
81+
.name("db")
82+
.build();
83+
```
84+
85+
Or with dependency injection (Avaje):
86+
87+
```java
88+
@Factory
89+
public class DatabaseFactory {
90+
91+
private DataSourceBuider dataSourceBuider() {
92+
var username = System.getenv("DB_USERNAME");
93+
var password = System.getenv("DB_PASSWORD");
94+
95+
return DataSourcePool.builder()
96+
.username(username)
97+
.password(password);
98+
}
99+
100+
@Bean
101+
public Database database() {
102+
103+
var writePool = dataSourceBuider()
104+
.name("datasource-write")
105+
.url("jdbc:mysql://mydb-cluster.123456789.us-east-1.rds.amazonaws.com:3306/myapp")
106+
.minConnections(3)
107+
.initialConnections(5)
108+
.maxConnections(20)
109+
.build();
110+
111+
var readOnlyPool = dataSourceBuider()
112+
.name("datasource-read")
113+
.url("jdbc:mysql://mydb-cluster-ro.123456789.us-east-1.rds.amazonaws.com:3306/myapp")
114+
.readOnly(true)
115+
.autoCommit(true)
116+
.minConnections(5)
117+
.initialConnections(10)
118+
.maxConnections(50)
119+
.build();
120+
121+
return DatabaseBuilder.create()
122+
.name("db")
123+
.datasource(writePool)
124+
.readonlyDatasource(readOnlyPool)
125+
.build();
126+
}
127+
}
128+
```
129+
130+
---
131+
132+
## How Ebean Routes Queries
133+
134+
Once configured with a secondary datasource, Ebean automatically routes queries:
135+
136+
- **Write operations** → Primary DataSource (write endpoint):
137+
- `db.insert(...)`
138+
- `db.update(...)`
139+
- `db.delete(...)`
140+
- `db.execute()` (for arbitrary SQL updates)
141+
- Transactions with writes
142+
143+
- **Read operations** → Secondary DataSource (read endpoint):
144+
- `db.find(User.class).findList()`
145+
- `db.find(User.class).findOne()`
146+
- `db.sqlQuery("SELECT ...").findList()`
147+
- Read-only queries
148+
149+
---
150+
151+
## Configuration Best Practices
152+
153+
### Connection Sizing for Dual DataSources
154+
155+
**Write Pool (Primary Endpoint):**
156+
```java
157+
.minConnections(3) // Fewer needed - mostly from read pool
158+
.initialConnections(5)
159+
.maxConnections(20)
160+
```
161+
162+
**Read Pool (Reader Endpoint):**
163+
```java
164+
.minConnections(5) // More connections for read traffic
165+
.initialConnections(10)
166+
.maxConnections(50)
167+
```
168+
169+
The read pool can have more connections because the reader endpoint is designed to handle distributed read load.
170+
171+
### Using Environment Variables or external configuration
172+
173+
Store database endpoints in environment variables or external configuration (like avaje config):
174+
175+
```java
176+
String writeUrl = System.getenv("DB_WRITE_ENDPOINT");
177+
String readUrl = System.getenv("DB_READ_ENDPOINT");
178+
String user = System.getenv("DB_USERNAME");
179+
String pass = System.getenv("DB_PASSWORD");
180+
181+
DataSourcePool writePool = DataSourcePool.builder()
182+
.name("datasource-write")
183+
.url(writeUrl)
184+
.username(user)
185+
.password(pass)
186+
.minConnections(3)
187+
.initialConnections(5)
188+
.maxConnections(20)
189+
.build();
190+
191+
DataSourcePool readOnlyPool = DataSourcePool.builder()
192+
.name("datasource-read")
193+
.url(readUrl)
194+
.username(user)
195+
.password(pass)
196+
.readOnly(true)
197+
.autoCommit(true)
198+
.minConnections(5)
199+
.initialConnections(10)
200+
.maxConnections(50)
201+
.build();
202+
```
203+
204+
205+
---
206+
207+
## Aurora Failover Behavior
208+
209+
### Write Endpoint Failover
210+
211+
If the primary instance fails, Aurora automatically promotes a read replica to be the new primary:
212+
213+
- Aurora updates the write endpoint to point to the new primary
214+
- The reader endpoint continues to distribute reads across remaining read replicas
215+
- Your application's connection pools will eventually connect to the new primary
216+
- ebean-datasource will reset when it detects the failover
217+
218+
219+
### Reader Endpoint Failover
220+
221+
If a read replica fails:
222+
223+
- Aurora automatically removes it from the reader endpoint pool
224+
- Other read replicas continue serving read traffic
225+
- No action needed from your application
226+
227+
---
228+
229+
## Monitoring and Metrics
230+
231+
### Connection Pool Metrics
232+
233+
Use the connection pool's built-in metrics to monitor pool health:
234+
235+
```java
236+
ConnectionPoolStatistics stats = writePool.getStatus();
237+
System.out.println("Write Pool - Size: " + stats.size());
238+
239+
ConnectionPoolStatistics readStats = readOnlyPool.getStatus();
240+
System.out.println("Read Pool - Size: " + readStats.size());
241+
```
242+
243+
### AWS CloudWatch Metrics
244+
245+
Monitor Aurora metrics in CloudWatch:
246+
- `DatabaseConnections` - Current connections
247+
- `DatabaseCPUUtilization` - CPU usage
248+
- `ReadLatency` / `WriteLatency` - Query latency
249+
- `Connections` - Connection count per instance
250+
251+
---
252+
253+
## Common Issues and Solutions
254+
255+
### Issue: Read queries still hitting the write endpoint
256+
257+
**Cause:** Explicit transactions or transaction context from the write pool.
258+
259+
**Solution:** Ensure read-only queries are executed outside of transaction context:
260+
261+
```java
262+
// This uses the read pool
263+
List<User> users = db.find(User.class).findList();
264+
265+
// This uses the write pool (even for reads within a transaction)
266+
try (var transaction = db.beginTransaction()) {
267+
List<User> users = db.find(User.class).findList(); // Still uses write pool
268+
// ... write operations
269+
transaction.commit();
270+
}
271+
```
272+
273+
### Issue: Latency between write and read
274+
275+
**Cause:** Aurora replication lag - read replicas may not have the latest data immediately.
276+
277+
**Solution:** For critical reads after writes, use the write pool:
278+
279+
```java
280+
// Write on primary
281+
db.insert(user);
282+
283+
// Read on primary to ensure latest data
284+
User updated = db.find(User.class)
285+
.usingMaster(true) // Force primary datasource
286+
.where().idEq(user.getId())
287+
.findOne();
288+
```
289+
290+
### Issue: Too many connections on read pool
291+
292+
**Cause:** Pool not trimming idle connections or application creating excessive load.
293+
294+
**Solution:** Monitor connection usage and adjust `maxConnections` down:
295+
296+
```java
297+
.maxConnections(30) // Reduce from 50
298+
.trimPoolFreqSecs(30) // Trim more aggressively if needed
299+
```
300+
301+
302+
---
303+
304+
## Next Steps
305+
306+
- Read the main [README](../../README.md) for general pool configuration options
307+
- See [Creating a DataSource Pool](create-datasource-pool.md) for basic pool setup
308+
- Check the [Ebean ORM documentation](https://ebean.io) for secondary datasource configuration
309+
- Review [AWS Aurora documentation](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/) for cluster and endpoint details

0 commit comments

Comments
 (0)