Hubble is a mirror for public AT Protocol data. It consumes atproto sync, and produces atproto CARs. It's working, and will be officially released veeerrrry soon. but first, this!

Hubble's purpose is to mirror the whole Atmosphere, but another very interesting (smaller!) use-case came up.

Ryan's avatar

sadly no, we're still trying to optimize our getRepo for cost, it's still way too expensive for us to serve, so it's largely disabled right now. 😢 we need to figure out a better answer here. cc @quillmatiq.com

Bridgy Fed bridges the Atmosphere and the Fediverse. You can follow friends on Mastodon from your Bluesky account, and seamlessly jump into in conversations that span protocols. It's very cool! So what's a getRepo and what does it have to do with Hubble?

Atmosphere sync

getRepo (legal name com.atproto.sync.getRepo) is one of two core methods to sync from PDSes to the network. The other is the firehose (or com.atproto.sync.subscribeRepos), and they compliment each other:

  • Firehose: a stream of verifiable data changes.

  • getRepo: a snapshot of verifiable data state.

Atmosphere sync is a careful coordination of these: fetching initial account data (getRepo, "backfill"), tracking changes (firehose), and recovering from errors by resetting (getRepo, "resync").

Without getRepo, there was a Bridgy-shaped hole in the Atmosphere. Bridgy Fed emitted changes on the firehose, but you couldn't backfill initial state or reset after errors for bridged Fediverse accounts.

It's one endpoint, Micheal. What could getRepo cost?

A lot, actually!

getRepo produces a complete archive of all public data for one account, structured as a Merkle Search Tree (MST), serialized into a Content-Addressable aRchive (CAR). Collecting all this content-addressed content, from a tree with up to millions of pieces of content, adds up to a lot of random reads.

Bridgy Fed stores atproto content in Google Cloud Datastore, which is highly scalable and pretty efficient for producing verifiable data changes for the firehose. But with pay-per-entity-read pricing and an entity-per-piece-of-content-stored design, the cost to serve getRepo can approach $1 in datastore reads alone for a single export of a very large account.

With many apps syncing the Atmosphere these days, serving getRepo like this would be unsustainable for Bridgy Fed.

Mirror for a PDS

Hubble is an alternate place you can make getRepo requests. It's kind of like how apps subscribe to one relay for the global firehose instead of subscribing to each and every PDS themselves, but the subscription endpoint is the exact same shape for both,

a whole-Atmosphere Hubble instance is one place you can call getRepo, with the exact same shape as if you were talking to a PDS. Atmosphere interop! (more about this if you're curious).

This same-shape thing means the reverse works too, of course! You can listen directly to any PDS "firehose" with any firehose tool. Behold, the Eurosky PDS firehose: pdsls.dev/firehose?instance=wss://eurosky.social

screenshot of pdsls's firehose page, subscribed to wss://eurosky.social. only the top summary is shown, with uptime (2m57s), total events (965), events/sec (5.0), and top collections (bsky like, post, repost, follow, postgate).

So… what if you ran Hubble, but subscribed it directly to Bridgy Fed, instead of the whole network? We tried it, and

it pretty much just worked?!

It took about 5 mins over a call with the wonderful Bridgy Fed folks for us to figure out how to set it up:

  • Bridgy Fed added an auth check to getRepo.

  • The Hubble mirror makes auth'd getRepo requests, so it can backfill from Bridgy Fed and stay in sync.

  • Bridgy Fed serves everyone else a redirect, sending their getRepos over to the mirror!

We've been live with this in production for a bit over a week now. The Hubble mirror has served terabytes of archives, billions of records, for millions of getRepo requests already.

For the Atmosphere, Bridgy Fed can now be synchronized. 65,000 accounts, now truly part of the network!

For Bridgy Fed, it only has one downstream getRepo consumer, at negligible cost after initial backfill.

For microcosm it's one little USD$10/mo VPS1, the chance to load-test Hubble under real backfill demand, and a way to help keep the network healthier for everyone 😌

If you have a full-network Tap instance, a lightrail server, or have been playing with the JetstreamV2 pre-release, you are probably already finally synchronized with Bridgy Fed!

Bridgy Fed stays in control

So microcosm is serving requests for data that Bridgy Fed holds. What happens if this microcosm ╳ Bridgy Fed collab falls apart?2

The microcosm threat is actually pretty limited:

  1. 1.

    The archives are signed (that's the A for Authenticated in AT Protocol). Whatever Hubble serves is verifiable. Hubble can't tamper undetected.

  2. 2.

    Bridgy Fed serves a 302 Found redirect to the mirror, a non-permanent redirect. Bridgy Fed is always in the loop for every getRepo request, and can turn it off instantly.

And of course, they could switch to self-hosting the mirror. Like all microcosm projects, Hubble is open-source:

microcosm.blue/hubble
A public mirror for the whole atmosphere
https://tangled.org/microcosm.blue/hubble

Hubble's getRepo and what's next

Hubble is built to serve a lot of getRepo3. It's doing well on the Bridgy Fed-sized mirror, and looking good so far at whole-network scale too.

fig (aka:[phil])'s avatar

The Paul Test hubble exports @pfrazee.com 2.4x faster than bluesky's reference pds deployment cold cache, no compression, bad laptop wifi

annotated terminal output: two curl commands, one to morel.us-east.host.bsky.network (bsky.network underlined), the other to hubble.microcosm.blue (also underlined), both making the same `com.atproto.sync.getRepo` request for pfrazee's DID

bsky's export took 22 seconds; hubble's 9s. a "2.4x" hand-written annotation is on the right.

raw terminal text:

code » curl -o /dev/null 'https://morel.us-east.host.bsky.network/xrpc/com.atproto.sync.getRepo?did=did:plc:ragtjsm2j2vknwkz3zp4oxrd'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 75.5M    0 75.5M    0     0  3496k      0 --:--:--  0:00:22 --:--:-- 3586k
code » curl -o /dev/null 'https://hubble.microcosm.blue/xrpc/com.atproto.sync.getRepo?did=did:plc:ragtjsm2j2vknwkz3zp4oxrd'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 75.5M    0 75.5M    0     0  8033k      0 --:--:--  0:00:09 --:--:--  9.8M

I'll write more about how Hubble works soon. But it's basically cheaper because it doesn't have to be a full PDS implementation. It gets away with no content-addressing internally, no stored Merkle Search Tree at all, and no pay-per-read cloud storage.

Next up for microcosm is to officially, publicly, properly, for real announce the whole-network Hubble mirror launch. I'm busy wrapping up details, it's really almost finally there!

(it has been a journey, but we got a sync1.1 library out of it, which will hopefully be the next post-announce post!)


This is one of a series of posts about building Hubble! In case you missed the original announcement:

Introducing Hubble: A Public Mirror for the Whole Atmosphere

New atproto infrastructure for network resilience, supported by a grant from Bluesky

microcosm: atproto building blocks
Mar 20

Microcosm runs on community support! If you liked this article, if you like community infra, or if you like when the whole Atmosphere can be synchronized:

Support phil
https://ko-fi.com/bad_example
Sponsor @uniphil on GitHub Sponsors
currently hacking on and hosting atproto projects: https://microcosm.blue art and transistors, small things that are nice
https://github.com/sponsors/uniphil/

more footnotes:

  • clickbait4

  • the bluesky thing 👀5