Skip to content

Commit 0e70d96

Browse files
committed
PM edits
1 parent 50ffa22 commit 0e70d96

File tree

4 files changed

+69
-55
lines changed

4 files changed

+69
-55
lines changed

src/content/docs/d1/best-practices/read-replication.mdx

Lines changed: 52 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,20 @@ sidebar:
88

99
import { GlossaryTooltip, Details, GitHubCode, APIRequest, Tabs, TabItem, TypeScriptExample } from "~/components"
1010

11-
D1 read replication scales read throughput and lowers latency for read queries by adding almost up-to-date, read-only database copies (read replicas) across global regions closer to clients.
11+
D1 read replication can lower latency for read queries and scale read throughput by adding read-only database copies, called read replicas, across global regions closer to clients.
1212

13-
You can use D1 read replication by using D1 Sessions API. A Session encapsulates all the queries from one logical session for your application. For example, a Session may correspond to all queries coming from a particular web browser session.
14-
15-
By using Sessions API for read replication, all of your queries from a single Session read from a database instance which is as up-to-date as your query needs it to be. This ensures that the version of the database you are reading from is logically consistent with your queries when using read replicas.
13+
Your application uses read replicas with D1 [Sessions API](/d1/worker-api/d1-database/#withsession). A Session encapsulates all the queries from one logical session for your application. For example, a Session may correspond to all queries coming from a particular web browser session. All queries within a Session read from a database instance which is as up-to-date as your query needs it to be. Sessions API ensures [sequential consistency](/d1/best-practices/read-replication/#replica-lag-and-consistency-model) for all queries in a Session.
1614

1715
To use read replication with the following Worker code and Sessions API:
1816

19-
1. [Enable read replication](/d1/best-practices/read-replication/#enable-read-replication)
17+
1. Enable read replication on a D1 database
18+
19+
```curl
20+
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{database_id}" \
21+
-H "Authorization: Bearer $TOKEN" \
22+
-H "Content-Type: application/json" \
23+
-d "{"read_replication": {"mode": "auto"}}"
24+
```
2025
2. Select `Deploy to Workers`.
2126

2227
{/* Deploy to Workers button */}
@@ -158,15 +163,13 @@ async function resetTables(session: D1DatabaseSession) {
158163

159164
![D1 read replication concept](/images/d1/d1-read-replication-concept.png)
160165

161-
When using D1 without read replication, D1 routes all queries (both read and write) to a specific database instance in [one location in the world](/d1/configuration/data-location/), known as the primary database instance. D1 request latency is dependent on the physical closeness of a user to the primary database instance. Users located further away from the primary database instance experience longer request latency due to [network round-trip time](https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/).
166+
When using D1 without read replication, D1 routes all queries (both read and write) to a specific database instance in [one location in the world](/d1/configuration/data-location/), known as the <GlossaryTooltip term="primary database instance"> primary database instance </GlossaryTooltip>. D1 request latency is dependent on the physical closeness of a user to the primary database instance. Users located further away from the primary database instance experience longer request latency due to [network round-trip time](https://www.cloudflare.com/learning/cdn/glossary/round-trip-time-rtt/).
162167

163-
When using read replication, D1 introduces multiple “almost up-to-date” copies of the primary database instance which only serve read requests, called <GlossaryTooltip term="read replica"> read replicas </GlossaryTooltip>. D1 creates the read replicas in multiple regions throughout the world [across the Cloudflare network](/d1/best-practices/read-replication/#read-replica-locations).
168+
When using read replication, D1 introduces multiple, asynchronously replicated copies of the primary database instance which only serve read requests, called <GlossaryTooltip term="read replica"> read replicas </GlossaryTooltip>. D1 creates the read replicas in multiple regions throughout the world [across the Cloudflare network](/d1/best-practices/read-replication/#read-replica-locations).
164169

165170
A user may be located far away from the primary database instance but close to a read replica. When D1 routes read requests to the read replica instead of the primary database instance, the user enjoys shorter read request response times.
166171

167-
D1 asynchronously replicates changes from the primary database instance to all read replicas. This means that at any given time, a read replica may be arbitrarily out of date. The time it takes for the latest committed data in the primary database instance to be replicated to the read replica is known as the <GlossaryTooltip term="replica lag"> replica lag </GlossaryTooltip>.
168-
169-
It is replica lag and non-deterministic routing to individual replicas that can lead to application data consistency issues, which Sessions API help handle by ensuring sequential consistency. For more information refer to [Replica lag and consistency model](/d1/best-practices/read-replication/#replica-lag-and-consistency-model).
172+
D1 asynchronously replicates changes from the primary database instance to all read replicas. This means that at any given time, a read replica may be arbitrarily out of date. The time it takes for the latest committed data in the primary database instance to be replicated to the read replica is known as the <GlossaryTooltip term="replica lag"> replica lag </GlossaryTooltip>. It is replica lag and non-deterministic routing to individual replicas that can lead to application data consistency issues, which Sessions API helps handle by ensuring sequential consistency. For more information, refer to [replica lag and consistency model](/d1/best-practices/read-replication/#replica-lag-and-consistency-model).
170173

171174
:::note
172175
All write queries are still forwarded to the primary database instance. Read replication only improves the query response time for read requests.
@@ -185,17 +188,17 @@ D1 read replication achieves this by attaching a <GlossaryTooltip term="bookmark
185188

186189
### Enable read replication
187190

188-
Use REST API to enable read replication on your D1 database.
191+
With REST API, set `"read_replication": "mode":"auto"` to enable read replication on a D1 database.
189192

190-
Set `"mode":"auto"` to enable read replication.
193+
For REST API, use a [API token](/fundamentals/api/get-started/create-token/) with `D1:Edit` [permission](/fundamentals/api/reference/permissions/#account-permissions).
191194

192195
<Tabs>
193196
<TabItem label="cURL">
194197
```curl
195198
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{database_id}" \
196199
-H "Authorization: Bearer $TOKEN" \
197200
-H "Content-Type: application/json" \
198-
-d '{"read_replication": {"mode": "auto"}}'
201+
-d "{"read_replication": {"mode": "auto"}}"
199202
```
200203
</TabItem><TabItem label="TypeScript">
201204
```ts
@@ -217,17 +220,17 @@ await fetch ("/v4/accounts/{account_id}/d1/database/{database_id}", {
217220

218221
### Disable read replication
219222

220-
Use REST API to disable read replication on your D1 database. If this is your first time using REST API, create an API token. Refer to [Create API token](/fundamentals/api/get-started/create-token/).
223+
With REST API, set `"read_replication": "mode":"disable"` to disable read replication on a D1 database.
221224

222-
Set `"mode":"disable"` to disable read replication.
225+
For REST API, use a [API token](/fundamentals/api/get-started/create-token/) with `D1:Edit` [permission](/fundamentals/api/reference/permissions/#account-permissions).
223226

224227
<Tabs>
225228
<TabItem label="cURL">
226229
```curl
227230
curl -X PUT "https://api.cloudflare.com/client/v4/accounts/{account_id}/d1/database/{database_id}" \
228231
-H "Authorization: Bearer $TOKEN" \
229232
-H "Content-Type: application/json" \
230-
-d '{"read_replication": {"mode": "disable"}}'
233+
-d "{"read_replication": {"mode": "disable"}}"
231234
```
232235
</TabItem><TabItem label="TypeScript">
233236
```ts
@@ -249,7 +252,9 @@ await fetch ("/v4/accounts/{account_id}/d1/database/{database_id}", {
249252

250253
### Check if read replication is enabled
251254

252-
The following code uses REST API to check if read replication is enabled / disabled.
255+
`GET` D1 database REST endpoint returns if read replication is enabled or disabled.
256+
257+
For REST API, use a [API token](/fundamentals/api/get-started/create-token/) with `D1:Read` [permission](/fundamentals/api/reference/permissions/#account-permissions).
253258

254259
<Tabs>
255260
<TabItem label="cURL">
@@ -275,20 +280,19 @@ console.log(data.read_replication.mode);
275280
</TabItem>
276281
</Tabs>
277282

278-
- If the output is `auto`, read replication is enabled.
279-
- If the output is `disabled`, read replication is disabled.
283+
- Check the `read_replication` property of the `result` object
284+
- `"mode": "auto"` indicates read replication is enabled
285+
- `"mode": "disable"` indicates read replication is disabled
280286

281287
### Start a Session without constraints
282288

283289
To create a Session from any database version, use `withSession()` without any parameters, which will route the first query to any database instance, either the primary database instance or a read replica.
284290

285291
```ts
286-
// synchronous
287-
let session = env.DB_D1.withSession()
288-
const stmt = session
289-
.prepare(`SELECT * FROM Customers WHERE CompanyName = 'Bs Beverages'`)
290-
// wait for Session condition, queries within batch have casual consistency
291-
const result = await session.run()
292+
const session = env.DB.withSession() // synchronous
293+
const result = await session // query executes on either primary database or a read replica
294+
.prepare(`SELECT * FROM Customers WHERE CompanyName = 'Bs Beverages'`)
295+
.run()
292296
```
293297

294298
- `withSession()` is the same as `withSession("first-unconstrained")`
@@ -322,11 +326,10 @@ To create a Session from the latest database version, use `withSession(first-pri
322326

323327
```ts
324328
// synchronous
325-
let session = env.DB_D1.withSession('first-primary')
326-
const stmt = session
327-
.prepare(`SELECT * FROM Customers WHERE CompanyName = 'Bs Beverages'`)
328-
// wait for Session condition, queries within batch have casual consistency
329-
const result = await session.run()
329+
const session = env.DB.withSession('first-primary') // synchronous
330+
const result = await session // query executes on primary database
331+
.prepare(`SELECT * FROM Customers WHERE CompanyName = 'Bs Beverages'`)
332+
.run()
330333
```
331334

332335
- This approach is best when your application requires the latest database version. All queries in a Session ensure sequential consistency.
@@ -363,15 +366,17 @@ async function getBillStatement(accountId: string, billId: string, bookmark: str
363366

364367
### Start a Session from previous context (bookmark)
365368

366-
To create a new Session from the context of a previous Session, pass a `bookmark` parameter to guarantee that the Session starts with database state as of or later than the provided `bookmark`.
369+
To create a new Session from the context of a previous Session, pass a `bookmark` parameter to guarantee that the Session starts with database state as of or later than the provided `bookmark`. `bookmark` could be saved in HTTP header from previous Session.
367370

368371
```ts
369-
// synchronous
370-
let session = env.DB_D1.withSession('bookmark_string')
371-
const stmt = session
372-
.prepare(`SELECT * FROM Customers WHERE CompanyName = 'Bs Beverages'`)
373-
// wait for Session condition, queries within batch have casual consistency
374-
const result = await session.run()
372+
const bookmark = request.headers.get('x-d1-bookmark') ?? 'first-unconstrained';
373+
374+
const session = env.DB.withSession(bookmark)
375+
const result = await session
376+
.prepare(`SELECT * FROM Customers WHERE CompanyName = 'Bs Beverages'`)
377+
.run()
378+
// store bookmark for a future Session
379+
response.headers.set('x-d1-bookmark', session.getBookmark() ?? "")
375380
```
376381

377382
- Starting a Session with a `bookmark` ensures the new Session has all the same context as the previous Session.
@@ -470,14 +475,14 @@ export default {
470475
} satisfies ExportedHandler<Env>;
471476
``` */}
472477

473-
### Inspect `meta` fields
478+
### Check where D1 request was processed
474479

475-
To see how D1 requests are processed by the additional database instances, return `served_by_region` and `served_by_primary` fields from the `meta` object. You can also manually calculate the query latency using `Date.now()` before and after your query.
480+
To see how D1 requests are processed by the addition of read replicas, `served_by_region` and `served_by_primary` fields are returned by the `meta` object in a [D1 Result](/d1/worker-api/return-object/#d1result).
476481

477482
```ts
478-
function buildResponse(session: D1DatabaseSession, res: D1Result, tsStart: number) {
483+
function buildResponse(session: D1DatabaseSession, res: D1Result, startTimestamp: number) {
479484
return {
480-
d1Latency: Date.now() - tsStart,
485+
d1Latency: Date.now() - startTimestamp,
481486

482487
results: res.results,
483488
servedByRegion: res.meta.served_by_region ?? "",
@@ -489,6 +494,9 @@ function buildResponse(session: D1DatabaseSession, res: D1Result, tsStart: numbe
489494
}
490495
```
491496

497+
- `served_by_region` and `served_by_primary` fields are present for all D1 remote requests, regardless of whether read replication is enabled. On local development, `npx wrangler dev`, these fields are `null`.
498+
- You can also manually calculate the query latency using `Date.now()` before and after your query.
499+
492500
## Read replica locations
493501

494502
Currently, D1 automatically creates a read replica in [every supported region](/d1/configuration/data-location/#available-location-hints), including the region where the primary database instance is located. These regions are:
@@ -506,12 +514,12 @@ Read replica locations are subject to change at Cloudflare's discretion.
506514

507515
## Observability
508516

509-
To see the impact of read replication, check the how D1 requests are processed by additional database instances. You can use:
517+
To see the impact of read replication and check the how D1 requests are processed by additional database instances, you can use:
510518

511519
- The `meta` object within the [`D1Result`](/d1/worker-api/return-object/#d1result) return object, which includes new fields:
512520
- `served_By_Region`
513521
- `served_By_Primary`
514-
- The [Cloudflare dashboard](https://dash.cloudflare.com/), where you can view your metrics breakdown by region.
522+
- The [Cloudflare dashboard](https://dash.cloudflare.com/), where you can view your metrics breakdown by region that processed D1 requests.
515523

516524
## Known limitations
517525

@@ -546,7 +554,7 @@ A system with multiple read replicas located around the world improves the perfo
546554

547555
You may wish to refer to the following resources:
548556

549-
- Blog: TBC
557+
- Blog: [Beta announcement & technical deep dive](https://blog.cloudflare.com/d1-read-replication-beta)
550558
- Blog: [Building D1: a Global Database](https://blog.cloudflare.com/building-d1-a-global-database/)
551559
- [D1 Sessions API documentation](/d1/worker-api/d1-database#withsession)
552560
- [Demo application]

src/content/docs/d1/reference/time-travel.mdx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ To understand which storage subsystem your database uses, run `wrangler d1 info
2323

2424
## Bookmarks
2525

26-
Time Travel introduces the concept of a "bookmark" to D1. A bookmark represents the state of a database at a specific point in time, and is effectively an append-only log.
26+
Time Travel leverages D1's concept of a <GlossaryTooltip term="bookmark"> bookmark </GlossaryTooltip> to restore to a point in time.
2727

28-
- Bookmarks are lexicographically sortable. Sorting orders a list of bookmarks from oldest-to-newest.
2928
- Bookmarks older than 30 days are invalid and cannot be used as a restore point.
3029
- Restoring a database to a specific bookmark does not remove or delete older bookmarks. For example, if you restore to a bookmark representing the state of your database 10 minutes ago, and determine that you needed to restore to an earlier point in time, you can still do so.
30+
- Bookmarks are lexicographically sortable. Sorting orders a list of bookmarks from oldest-to-newest.
31+
- Bookmarks can be derived from a [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time) (seconds since Jan 1st, 1970), and conversion between a specific timestamp and a bookmark is deterministic (stable).
3132

32-
Bookmarks can be derived from a [Unix timestamp](https://en.wikipedia.org/wiki/Unix_time) (seconds since Jan 1st, 1970), and conversion between a specific timestamp and a bookmark is deterministic (stable).
33+
Bookmarks are also leveraged by [Sessions API](/d1/best-practices/read-replication/#sessions-api-examples) to ensure sequential consistency within a Session.
3334

3435
## Timestamps
3536

src/content/docs/d1/worker-api/d1-database.mdx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@ return new Response(dump, {
243243

244244
- None.
245245

246-
### `withSession`
246+
### `withSession()`
247247

248-
Starts a D1 Session which maintains sequential consistency among queries executed on the returned session object.
248+
Starts a D1 Session which maintains sequential consistency among queries executed on the returned `D1DatabaseSession` object.
249249

250250
```ts
251251
const session = env.DB.withSession("<parameter>");
@@ -261,10 +261,10 @@ const session = env.DB.withSession("<parameter>");
261261
- <code>first-unconstrained</code>: <Type text="String"/><MetaInfo text="Optional"/>
262262
- Directs the first query in the Session (whether read or write) to any database instance. Use this option if you do not need to start the Session with the most up-to-date data, and wish to prioritize minimizing query latency from the very start of the Session.
263263
- Subsequent queries in the Session have sequential consistency.
264-
- This is the default behavior when no parameters are provided.
264+
- This is the default behavior when no parameter is provided.
265265

266266
- <code>bookmark</code>: <Type text="String"/><MetaInfo text="Optional"/>
267-
- A [`bookmark`](/d1/reference/time-travel/#bookmarks) from an existing D1 Session. This allows you to continue the existing Session using the `bookmark` as a reference point.
267+
- A [`bookmark`](/d1/reference/time-travel/#bookmarks) from a previous D1 Session. This allows you to start a new Session from at least the provided `bookmark`.
268268
- Subsequent queries in the Session have sequential consistency.
269269

270270
#### Return values
@@ -276,14 +276,17 @@ const session = env.DB.withSession("<parameter>");
276276

277277
You can return the last encountered `bookmark` for a given Session using [`session.getBookmark()`](/d1/worker-api/d1-database/#getbookmark).
278278

279-
## Session methods
279+
## `D1DatabaseSession` methods
280280

281281
### `getBookmark`
282282

283283
Retrieves the latest `bookmark` from the D1 Session.
284284

285285
```ts
286-
const session = db.withSession("first-primary");
286+
const session = env.DB.withSession("first-primary");
287+
const result = await session
288+
.prepare(`SELECT * FROM Customers WHERE CompanyName = 'Bs Beverages'`)
289+
.run()
287290
return { bookmark } = session.getBookmark();
288291
```
289292

@@ -294,4 +297,5 @@ return { bookmark } = session.getBookmark();
294297
#### Return values
295298

296299
- <code>bookmark</code>: <Type text="String | null"/>
297-
- A [`bookmark`](/d1/reference/time-travel/#bookmarks) which identifies the latest version of the database seen by all queries executed within the Session.
300+
- A [`bookmark`](/d1/reference/time-travel/#bookmarks) which identifies the latest version of the database seen by the last query executed within the Session.
301+
- Returns `null` if no query is executed within a Session.

src/content/glossary/d1.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ entries:
1818
a Session encapsulates all the queries from one logical session for your application. For example, a Session may correspond to all queries coming from a particular web browser session.
1919
- term: bookmark
2020
general_definition: |-
21-
a bookmark represents the state of a database at a specific point in time.
21+
a bookmark represents the state of a database at a specific point in time.
22+
- Bookmarks are lexicographically sortable. Sorting orders a list of bookmarks from oldest-to-newest.

0 commit comments

Comments
 (0)