-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Intercept fetches to R2 and use direct CARPARK pull (#141)
# Goals When we fetch blocks from an R2 CARPark URL, we appear to get TTFB around 400ms. Interestingly, if we instead use Cloudflare Worker's direct R2 access, our TTFB drops to around 200ms. Bandwidth doesn't seem to change much, but this is still an important win. # Implementation - Using a seperate change in blob-fetcher to allow passing a custom fetch implementation, we now write a version of fetch that checks URLs to see if they are CAR Park URLs. if they are, instead of using the fetch API, we use our direct connection to CARPark in the worker to perform the fetch request. - Pass this custom fetch to the batching fetch used by content claims dagula - Also, to assemble a browser like Response object use the existing code in withCarBlockHandler, factored out to utility file - In the process of doing this, I discovered a bug in that code where it was treating the last byte in the range as exclusive to the returned content rather inclusive, and this was undetected as the test was expecting the wrong result. # For Discussion Comparison traces, note the average TTFB of 200 vs 400 on requests to R2 Regular fetch: ![Screenshot 2025-01-03 at 8 42 11 PM](https://github.com/user-attachments/assets/78981630-8614-4060-8a3e-20e6b2868924) With intercepted direct gets to R2: ![Screenshot 2025-01-04 at 3 48 55 PM](https://github.com/user-attachments/assets/52a3857a-f3eb-46e0-85c9-5337ec0491dc)
- Loading branch information
1 parent
241545f
commit 4daf8a3
Showing
9 changed files
with
117 additions
and
18 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import { withSimpleSpan } from '@web3-storage/blob-fetcher/tracing/tracing' | ||
import { createHandler } from '@web3-storage/public-bucket/server' | ||
// eslint-disable-next-line | ||
import * as BucketAPI from '@web3-storage/public-bucket' | ||
|
||
/** @implements {BucketAPI.Bucket} */ | ||
export class TraceBucket { | ||
#bucket | ||
|
||
/** | ||
* | ||
* @param {BucketAPI.Bucket} bucket | ||
*/ | ||
constructor (bucket) { | ||
this.#bucket = bucket | ||
} | ||
|
||
/** @param {string} key */ | ||
head (key) { | ||
return withSimpleSpan('bucket.head', this.#bucket.head, this.#bucket)(key) | ||
} | ||
|
||
/** | ||
* @param {string} key | ||
* @param {BucketAPI.GetOptions} [options] | ||
*/ | ||
get (key, options) { | ||
return withSimpleSpan('bucket.get', this.#bucket.get, this.#bucket)(key, options) | ||
} | ||
} | ||
|
||
/** | ||
* @import { | ||
* Middleware, | ||
* Context as MiddlewareContext | ||
* } from '@web3-storage/gateway-lib' | ||
* @import { | ||
* CarParkFetchContext, | ||
* CarParkFetchEnvironment | ||
* } from './withCarParkFetch.types.js' | ||
*/ | ||
|
||
/** | ||
* 20MiB should allow the worker to process ~4-5 concurrent requests that | ||
* require a batch at the maximum size. | ||
*/ | ||
const MAX_BATCH_SIZE = 20 * 1024 * 1024 | ||
|
||
/** | ||
* Adds {@link CarParkFetchContext.fetch} to the context. This version of fetch | ||
* will pull directly from R2 CARPARK when present | ||
* | ||
* @type {Middleware<CarParkFetchContext, MiddlewareContext, CarParkFetchEnvironment>} | ||
*/ | ||
export function withCarParkFetch (handler) { | ||
return async (request, env, ctx) => { | ||
// if carpark public bucket is not set, just use default | ||
if (!env.CARPARK_PUBLIC_BUCKET_URL) { | ||
return handler(request, env, { ...ctx, fetch: globalThis.fetch }) | ||
} | ||
const bucket = new TraceBucket(/** @type {import('@web3-storage/public-bucket').Bucket} */ (env.CARPARK)) | ||
const bucketHandler = createHandler({ bucket, maxBatchSize: MAX_BATCH_SIZE }) | ||
|
||
/** | ||
* | ||
* @param {globalThis.RequestInfo | URL} input | ||
* @param {globalThis.RequestInit} [init] | ||
* @returns {Promise<globalThis.Response>} | ||
*/ | ||
const fetch = async (input, init) => { | ||
const request = input instanceof Request ? input : new Request(input, init) | ||
// check whether request is going to CARPARK | ||
if (env.CARPARK_PUBLIC_BUCKET_URL && request.url.startsWith(env.CARPARK_PUBLIC_BUCKET_URL)) { | ||
return bucketHandler(request) | ||
} | ||
return globalThis.fetch(input, init) | ||
} | ||
return handler(request, env, { ...ctx, fetch }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { | ||
Environment as MiddlewareEnvironment, | ||
Context as MiddlewareContext, | ||
} from '@web3-storage/gateway-lib' | ||
import { R2Bucket } from '@cloudflare/workers-types' | ||
|
||
export interface CarParkFetchEnvironment extends MiddlewareEnvironment { | ||
CARPARK: R2Bucket | ||
CARPARK_PUBLIC_BUCKET_URL?: string | ||
} | ||
|
||
export interface CarParkFetchContext extends MiddlewareContext { | ||
fetch: typeof globalThis.fetch | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters