What do you mean by 1000 databases? Is your 1 app connected to 1000 databases?
Multi-tenancy with database-per-tenant: how to handle lot of migrations efficiently
Hello,
We have a multi-tenancy with database-per-tenant Laravel app with lot databases and we are facing a problem: if a migration take 5 seconds to execute in one database, and we have 1.000 databases, it will take more than 83 minutes to run all migrations (and we need to put the app in maintenance mode for 83 minutes).
So, what’s the best way to minimize the time to run all the migrations?
I found this post that use Queues and Jobs to process the migrations in parallel:
https://medium.com/hackernoon/abstract-upgrade-command-for-multi-tenant-71089b9a838f
So, if we use 10 workers to run the migrations, it will take 8,3 minutes to run all the migrations.
This approach is ok? Or it can take MySQL service down if we run multiple migrations in parallel?
Thanks,
If you can afford any downtime I would experiment with the parallel solution.
If you prefer to try a near zero-downtime solution, follow along.
As you are routing with subdomain you could install a reverse or an application proxy, such as Traefik, that routes traffic to a different server depending of the subdomain.
- Then you deploy the new code version to a second application server.
- Traefik, or even nginx as a reverse proxy, can make the routing decision based on reading from a storage. I guess nginx can't query MySQL or any DBMS directly, but you could update a
.conffile while your migration progresses. - In your tenant table, on your landlord DB, you add a column that holds the version.
- The reverse/application proxy would redirect traffic for each subdomain based on the version on this storage. Current version to current application server, new version to newer application server.
- While migrating a single tenant you could issue a 503 response for that specific subdomain requests. This would be the "near" zero-downtime, as you said the migrations runs for about 5 seconds for each tenant.
- When finishing migrating a tenant you change the version in its landlord record, the proxy will start using the new server for this tenant.
For the 503 reponse while migrating, you could play with how Laravel handles the php artisan down command and customize it to allow traffic matching certain subdomains while responding with a 503 to subdomains being migrated. Current implementation adds a script to the public folder, so you could tweak this generated script.
For tracking when each migration starts or ends, you can listen for the Migration events. Check this docs page for reference: https://laravel.com/docs/9.x/migrations#events
Disclaimers:
- While I worked on doing something similar on the past, it was a Symfony project, not a Laravel one, and some years ago.
- So I am writing from memory this outline, but it is just an outline, if you need implementation details I probably won't remember them all.
- By then we used Traefik to handle dynamic traffic routing between servers. I guess nowadays there might be other solutions than Traefik or using nginx directly.
- We also used this approach to every new version deployment, you can search for blue/green deployment strategy for more info.
Postscript:
- My question about if you already had 1,000 tenants or were planning ahead, was precisely to advise against premature optimization.
- And also to advise you to hire an expert consultant to help you out with this in case you already had 1,000 tenants.
- With close to 1,000 tenants I assume you (as a company) already have enough revenue to afford hiring one.
- I am not offering any services, nor I am an expert on infra-structure. Although in the project I mentioned, I participated actively in implementing the solution, we had an infra-structure expert advising us at the time.
- This is the kind of the problem I usually referred as "a good problem to have" when I used to give classes, as this means you (as a company) seems to be succeeding. Congratulations!
Hope I could make it clear, English is not my native language. Good luck =)
Please or to participate in this conversation.