We want to use fly to migrate our Elixir application.
We were able to configure our application as a cluster but we want to do the same for the Postgres application.
I created Postgres Cluster on two regions but the application are really slow.
❯ fly status -a brandkit-pg-st
App
Name = brandkit-pg-st
Owner = brandkit
Version = 4
Status = running
Hostname = brandkit-pg-st.fly.dev
Deployment Status
ID = e20569c0-f788-c5c1-ddcb-26aea1dfe55c
Version = v4
Status = successful
Description = Deployment completed successfully
Instances = 3 desired, 3 placed, 3 healthy, 0 unhealthy
Instances
ID TASK VERSION REGION DESIRED STATUS HEALTH CHECKS RESTARTS CREATED
ede4b9e2 app 4 gru run running (replica) 3 total, 3 passing 0 2h29m ago
cc6ceb2b app 4 iad run running (replica) 3 total, 3 passing 0 2h30m ago
a192ee2e app 4 iad run running (leader) 3 total, 3 passing 0 2h31m ago
On the board we see that the replication delay increases all the time.
When you run a database multi region, you need to do some work to make sure your app connects to the nearest. Your app instance in São Paulo is probably connecting to the database in Virginia.
This will get easier, but here are docs for connecting to postgres in the same region: Multi-region PostgreSQL
Your best bet is probably to run app and database in a single region at first, and then add regions when you’re comfortable with performance. We’ll have a hex package to automate what you need in Elixir soon.
The strategy we used was to create 2 ecto repo, one for the leader (read / write) and one for the replicas (read only). If the node is in the same region as the leader, both repositories will have the same database url.
More generally, querying a Postgres in Virginia from São Paulo will always be slow. If you’re doing async writes for something like LiveView that might be ok. If you’re doing it within an HTTP request, though, it will break. You are much, much better off using the fly-replay header when you need your code to work with the primary database.
Option one is probably better. It’s better to have the code that does a write close to the database instance. For HTTP requests, I would do all reads from Brazil and replay all write requests to Virginia.
Yes! I’m hoping to share the code as a library soon-ish here in the community. It’s an approach that helps move all the writes to the primary and let the reads happen on the replica. Many typical apps are read-heavy, so for those it makes a lot of sense. If that model fits well with your app then I think it will be a really great solution. I’m also presenting on it at Elixir Conf in October. So I’m really working to finish it up!!