API Maker

The framework for AI era

Level 5 · GlobalArchitecture 12 of 13

Geo-routing: the nearest region

HTTP calls and WebSockets answered by the region nearest to each user, behind one address for the whole world.

Start with one address answered directly by one place, then add regions: GeoDNS sends every user to the nearest one, for HTTP calls and WebSockets alike. Reads stay in the region, while writes and events cross the world in the background.

See it live

Every request is drawn as it travels. Slow it down, pause, go step by step, or open the full canvas and zoom in.

api-maker/architectures/geo-routingLive
  • Request
  • Response
  • Cache hit
  • Write
  • WebSocket event
  • Replication
  • DNS
Regions
3/3serving
Asia users
~10 msround trip
Events
0pushed
Capacity
~8,277req/s

One address: every request travels to Frankfurt. HTTP calls and WebSockets of every user go straight to the servers in Frankfurt. Simple, and fast for users nearby.

How it works

The same steps as the diagram, in more detail.

  1. One address: every request travels to Frankfurt.

    The simplest setup serves everyone from one place: one address, and the servers behind it answer every request and hold every WebSocket directly. Users near Frankfurt get answers in a few milliseconds, but a user in Singapore waits about 170 ms for every round trip, and a secure connection needs several of them.

  2. GeoDNS: every user reaches the nearest region.

    A DNS service with geolocation answers api.example.com with the address of the region nearest to the user. Each region runs its own load balancer and API Maker servers with the same .env, so every region serves every API and accepts every WebSocket. The apps keep the same address.

  3. Reads stay local, writes go home.

    Your MongoDB replica set has a member in every region. With readPreference=nearest, the servers of a region read from the member next to them, while writes go to the primary in Frankfurt, the home region, and replicate to every region within moments. API Maker DB and Redis live in the home region.

  4. Real-time events reach every region.

    Each user keeps a WebSocket to the servers of their own region. When a call raises an event, it is published through Redis, which every API Maker server of every region listens to, and each server pushes it to its own subscribers. A client in Singapore hears about an order placed in Frankfurt within a fraction of a second.

  5. A region fails, its users move to the next one.

    GeoDNS checks every region. When Singapore stops answering, its users get the address of the next region, Frankfurt, and their WebSockets reconnect there. Round trips are longer until Singapore is back, but nothing is lost: the data lives in the replica set and every region serves every API.

Why choose this architecture

Fast everywhere

Users talk to servers a few milliseconds away instead of across an ocean, and a secure connection opens sooner.

WebSockets nearby

Each client keeps its WebSocket in its own region, and events raised anywhere reach it through Redis.

One address

api.example.com stays the same for every user and every app. DNS does the routing.

Local reads

With readPreference=nearest, the servers of each region read from the database member next to them.

Regions back each other up

When a region fails, DNS sends its users to the next one and they keep working.

The same APIs everywhere

Every region reads the same API Maker DB: one git pull and every server in the world reloads.

Server configuration

Plain VPS from any provider, or your own servers, with Ubuntu 22.04 LTS. Sizes are a starting point: measure and adjust.

GeoDNS

×2, or your DNS provider
CPU
1 vCPU
Memory
1 GB
Storage
10 GB SSD

Runs

  • PowerDNS with the GeoIP backend
  • Health checks of every region

Ports

  • 53: from the internet

Load balancer

×1 per region
CPU
2 vCPU
Memory
2 GB
Storage
20 GB SSD

Runs

  • HAProxy: HTTP and WebSocket
  • TLS for api.example.com

Ports

  • 443: from the internet

API servers

×1+ per region
CPU
4 – 8 vCPU
Memory
8 – 16 GB
Storage
40 GB SSD

Runs

  • API Maker, the same .env in every region
  • Two per region to survive a server

Ports

  • 38246 and 38245: from the load balancer of the region

MongoDB members

×1 per region
CPU
4 vCPU
Memory
16 GB
Storage
200 GB NVMe

Runs

  • One replica set: your data and API Maker DB
  • The primary in the home region

Ports

  • 27017: private, through tunnels between regions

Redis Cluster

×3 – 6, home region
CPU
2 vCPU
Memory
8 GB
Storage
20 GB SSD

Runs

  • Events, locks and cache for every region

Ports

  • 6379: private, from the API servers of every region
GeoDNS: the nearest region that answersexample.com zone · PowerDNS
; Frankfurt, New York, Singapore: the closest one whose port 443 answersapi.example.com.  60  IN  LUA  A  "ifportup(443, {'198.51.100.10', '203.0.113.10', '192.0.2.10'}, {selector='pickclosest'})"

pickclosest needs the GeoIP backend of PowerDNS. A DNS provider with geo routing and health checks does the same.

API servers of every region.env
am__serverName="sgp-api-1"   # region and server, to find it in the dashboards# One replica set over the three regions, the primary in Frankfurtam__mongo_db_connection="mongodb://api_maker:***@10.20.1.20:27017,10.20.2.20:27017,10.20.3.20:27017/api_maker_db?authSource=admin&replicaSet=rs0"# Redis of the home region, shared by every regionam__redisInternal='{"nodes": [{host: "10.20.1.21", port: 6379, pass: "***"}, {host: "10.20.1.22", port: 6379, pass: "***"}, {host: "10.20.1.23", port: 6379, pass: "***"}]}'am__redisExternal='{"nodes": [{host: "10.20.1.21", port: 6379, pass: "***"}, {host: "10.20.1.22", port: 6379, pass: "***"}, {host: "10.20.1.23", port: 6379, pass: "***"}]}'
Instance of your data: reads from the member of the regionconnection string
mongodb://app:***@10.20.1.20:27017,10.20.2.20:27017,10.20.3.20:27017/shop?replicaSet=rs0&readPreference=nearest

Good to know

  • Writes travel to the home region: from Singapore, each write waits a round trip to Frankfurt.
  • Nearest reads can lag the primary by a moment. Read from the primary where users must see their own writes at once.
  • Redis lives in the home region: for far regions a cache hit costs a round trip there, often more than a local read.
  • Every region adds servers, tunnels and monitoring. Start with two regions where most of your users are.
When you outgrow itEverything at once: regions, providers, projects and tenants on one platform. Global enterprise platform

Questions

Can one server take HTTP calls and WebSockets directly?

Yes. Every API Maker server answers HTTP on port 38246 and WebSockets on port 38245, directly or behind a load balancer. With one address, one server or one region takes everything; with GeoDNS, each region takes the users nearest to it.

Does a WebSocket client stay in one region?

Yes. A WebSocket stays on the server it connected to, in the region DNS gave it, and events raised in any region reach it through Redis. If its region fails, the client reconnects and DNS gives it the next region.

Do I need a paid GeoDNS service?

No. PowerDNS with its GeoIP backend runs on two small VPS and picks the closest region that answers. A DNS provider with geo routing works the same way.

Why not a Redis in every region?

API Maker clears cached responses and publishes events in the Redis shared by every server. With a Redis per region, the other regions would keep stale responses and never hear the events.