Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

psmail's avatar

Scaling with Laravel and Forge

Hi

JW - do you think you might cover how Laravel and Forge scale? I am not an expert on the matter - hence the request - but I imagine it might cover:

  • Separating the database and the web / app / job server
  • Separating the database and the job server away from the web / app server
  • Running multiple web servers
  • Mmmm ... now this one might make no sense at all ... but I'll give it a go; separating the web server from the app server and, related to that, multiple app servers (i.e. breaking a large app into many apps ... perhaps as services)

I accept that most apps would not need to scale beyond the first two bullet points so I'll take those if I can get them!

Thanks.

0 likes
47 replies
Felix's avatar

Definitely worth a lesson or series!

3 likes
equipc's avatar

It would be nice if Jeffrey cover this in the Larabook serie.

2 likes
CraftThatBlock's avatar

This isn't that hard of a topic really. I'd love to do a cast about it @JeffreyWay ;) ?

Database server

Once you have spinned up the DB server on Forge, you don't put any sites on it, you only SSH into it, and setup a new MySQL database. In this case let's call it "myapp".

mysql -uforge -p

This makes you login into your MySQL. Next it will ask you for your MySQL password found in the email from Forge.

create database myapp;

This will create the database.

exit

This will make it leave the MySQL command prompt back into your normal SSH shell.

You already have setup everything you need for the MySQL server!

Web server(s)

Now in your app, if you are doing like Jeff is doing by using getenv() (which you should!), you will need to set the environment variables inside the Forge panel.

Make a new server (this one will host your web app. Simple repeat the following steps to add more web servers!); Make a new Forge server. In this one, setup a git repo (or how ever you app is setup). In the environment variable, set them up BUT use the database information from the DB server that we setup above! This will make it so all the web servers (that is hosting that one app) is sharing the same database information.

Extra: If you'd like (and I would recommend so), make so only one of the server runs the migrations. This can easily be change my going into all of the servers and removing "php artisan migrate" from the deploy script from all the servers except one.

This "Web server(s)" this can be repeated as much as you want!

DNS

Now we need to setup a round-robin DNS setup, to spread the load over your servers. Grab a list of all the IPs of the servers you setup above. Next signup to Cloudflare. It's a great (and free) DNS service, and has some other speed ups for your site. (+ DDoS protection). You can learn more about it at cloudflare.com.

Once you are signed up, setup your domain to use Cloudflare. This is a pretty easy setup, and Cloudflare guides your though. Once everything is done, simply add an A record with the name of "@" (no quotes) for every server IP from the "Web server(s)" part. Example: http://puu.sh/aZqlP/b6046b5ca2.png

This will make cloudflare alternate through every server randomly.

As said in the top of this wall of text, I'd love to do a cast about it if Jeff would like me to. (Jeff: simply email me, you can get my email ;))

42 likes
jimmy.puckett's avatar

@psmail,

We are tackling that with a project that has to support 500,000 transactions within about a 3 hour window, which gives us about 47 transactions a second. These are not just store & go either. We have to do all sorts of domain logic, call different 3rd party web services, store results, notifications, etc.

We don't use forge for this as we use highly tuned servers built with Packer to produce AMI's for AWS and box files for vagrant, so I am going to focus on the non-forge part of your question. Here are some of the things that we have done that you may want to consider...

  • Split our code into "servers" for the web code & for the processing code
  • We are using a queuing architecture to distribute the jobs across all of the nodes
    • The servers are dynamically "stood up" behind load balancer(s) multi-region based on an algorithm that uses factors such as number of items in queue, load on boxes, etc
    • Web severs take the request, light validation, assign unique transaction, and pass it into the command bus, which is placed on a shared queue
    • Processing servers poll the queue & pick the jobs of the queue and deal with the next step in the queue
  • By writing our code into modules, we are able to install parts of them on a box to only deal with a specific part of the command bus allowing us to have additional security on the servers by not even letting the processing servers have any inbound traffic--don't call us, we'll call you
  • We are using AWS' RDS for the database because they handle having read-only slaves & the multi region. Then you can actually have an array of read servers so it distributes the database load
  • Some other issues to consider/overcome...
    • Shared file storage
    • Configuration state at the time of the queued job
    • Centralized logging

I hope that I did not ramble too much & that I helped you have some points to be considering...

12 likes
psmail's avatar

I'd just like to say that I have learnt heaps from this thread and I'd like to thank, in particular, @CraftThatBlock and @jimmy.puckett for taking the time to impart some knowledge.

@CraftThatBlock : That Cloudfare pseudo LB things a bit of a nugget all its own.

@jimmy.puckett : That's a huge site. Two things stood out to me - one your modular use of code. Are you doing this in a Laravel context? I ask because it would be great to know what a truly modular implementation involves - even outside of scale, I'd love to setup authentication a separate authentication ... what ... 'service' (?) that I could call form all of my apps. The next thing I thought was interesting was you write-slaves - have I understood correctly that most databases (in particular MySQL ... if Postgres is the other comparison) support write slaves well but the value add AWS provide is that these are multi-region (as opposed to limited to the same region, which I am sure I have seen elsewhere).

But there is one more thing that nobody mentioned - the Server Network in Forge. What is the advantage of using that? Are there disadvantages? When would you / might you / do you have to use the settings of the Server Network functionality of Forge?

I think the other thing worth raising is separating out the job server form the web server - unless I missed it that didn't come up here.

Anyway, the reason this all came to mind was I caught TO on Three Devs et al and he mentioned the Forge setup was 2 web servers, to job servers and an LB ... and I thought it might be nice to know how that held together in a Forge context.

Thanks again.

2 likes
fideloper's avatar

Sounds like something for me to cover :D

19 likes
stefanbauer's avatar

+1 from my side.

But i don't agree with the DNS Round Robin in the previous posts. Of course you can share your traffic with round robin to more than 1 webserver, but this kind of "loadbalancing" is not the way you should go with. You don't have real balancing based on the performance of the webservers or based on the up-status. So it could be that you get to a server which is totally overloaded, or better: In the worst case, you get to a server which is offline.

So i would be interested in that topic generally, but then with a "real/better" alternative than dns round robin. I know, software LB can not replace a hardware LB, but at least it is better that round robin. So maybe there are some solutions with "pound" for .e.g. I think there are much more solutions outside there.

1 like
psmail's avatar

No argument, @stefanbauer. Interesting, then, that a mob like Heroku only offer random - which to mine is even worse than round robin - as an LB option. Do they know something we don't in regard to the merit lowest load or least recent called LB (my terms aren't quite correct ... But you get the idea)?

I can certainly say that I'd rather round robin - or random for that matter - then no option at all. As long as the cost / ease balance was right.

1 like
Valorin's avatar

I would assume that Heroku offer random because it's simple and easy to set up and wouldn't require much support effort on their part.

For more complicated/robust load balancing, you either need to look at a dedicated hardware options (outside the scope of Heroku), or dedicated software applications (+time and effort to support and manage). Both options would involve a lot of effort to support on Heroku, so it's probably not worth it for them to go down that path.

1 like
richbreton's avatar

Ill throw in my +1 - this would be nice. I personally am more interested in a forge perspective, because even though I have been a sysadmin for years services like forge are convenient and save me a lot of time.

It would be cool to see some of the following things:

  1. Separation of database and web server

  2. Separation of worker code into another server from web code

  3. Session storage in redis

  4. Implementing caching in your code at the page and object level, how/where to store? File? Redis?

  5. Lazy loading and other code level techniques to make less database queries, or speedier queries.

  6. Finding slow queries and optimizing them.

  7. Adding indexing to your database tables.

  8. Should you Mongo, How?

  9. Adding an additional web server and load balancer

  10. Shared file storage

  11. Offloading pics, assets, large file downloads (long web server running processes) to another server

  12. CDN usage

  13. Adding a second read only database

  14. Using APC or other compiler caches

  15. Splitting your code up into services, where and how to use SOA

12 likes
zefman's avatar

Another +1 here. I have recently been experimenting on different multiple server setups using forge, and while I have found it relatively easy to split into multiple instances working off a shared db server, I haven't always seen the performance gains I would expect.

Would love to see something along these lines, and maybe app optimisation in general.

richbreton's avatar

@zefman a lot of times you will see performance decrease moving the database off the web server, because the connection type goes down across a network rather than just using /tmp.sock sort of thing. What the separation really buys you when the time is right is to take those resources off your web server and put them elsewhere, but even on a small 2gb slice I would imagine (it would depend on your code of course) that you could probably get a few hundred users on a single server setup.

zefman's avatar

@getstartify yes I was expecting a slight dip in average response times overall, but didn't really see this with a multi server set up on digital ocean. I was able to handle more requests, but not as many more as I was expecting.

I actually have the results of this testing in a rather messy spreadsheet here if you are interested: https://docs.google.com/spreadsheets/d/14vcovx322FeGwfW8i6G2CctMGaRoeiPiOc2Ya3rmt0w/edit?usp=sharing

I also had a quick play with hhvm and saw some very impressive increases in performance in some areas, but decreases in others.

Interestingly cpu was always the limiting factor.

fideloper's avatar

I think moving your database will "only" (generally) offer the following advantages:

  1. Parts of the stack can fail independently of one another (Also, if you use database replication, you can potentially automatically assign a replica DB to be master if the master fails)
  2. Database servers won't affect the web server if expensive queries are run

Expensive queries are still slow! However, lots of queries (high volume) have more room to play with when the DB is on a separate server, so if you have a lot of queries, that will help as well.

Moving the database off shouldn't show much improvement unless you were already hitting server limits by having both running at the same time.

In general, scaling horizontally to more servers is about:

  1. High(er) Availability
  2. Keeping load times consistent (rather than faster)

Scaling vertically (more CPU/ram) can get you more speed.

4 likes
NoorDeen's avatar

I know this thread is old . but what if I have virtual servers in the same dedicated server can this speed up my application while scaling it horizontally ?

another question is how to use queues to communicate between distributed services ? and what is the best message queue server to use for this propose ? @fideloper @zefman @getstartify @psmail @jimmy.puckett @CraftThatBlock

stefr's avatar

+1 I would also love a video on maintenance on Forge deployed servers like updating and figure out what services are in need of a restart instead of rebooting the entire server every couple of days.

commandantp's avatar

Any Laracast on load balancing around ? Couldn't find it but it says you can do it.

Next

Please or to participate in this conversation.