How to write the high-performance application in PHP?

We coded Product Kits app and it worked pretty well. Peak hits were 5000 hits per seconds. Read Story of Product Kits from 100 to 100000 hits per minute. We had a lot of issues, but issues with PHP wasn’t scalability. We were able to handle everything but the problem came when we had to know what other workers were doing.

The first question that might come to your mind is if you have chosen the write tech stack? Since we are aware of the fact that PHP doesn’t support multi-threading. However, there is a trade-off between the speed of development and the performance. PHP is not very fast, in fact, it is slow – but it is fast enough. As long as you don’t want individual PHP scripts to know the state of each other, you are in a pretty good shape – most of the time.

Trade-Off – Scalable VS Speed

While using PHP, our major concern was RAM, it was much easier to get high RAM usage and CPU. We had to deal with a lot of data and data most of the time either stays in RAM or required us to increase the HIT if we wanted to keep it outside. If your PHP codes are using a lot of RAM, you will have to solve a scalability problem. However, if your app doesn’t require a lot of RAM, better is to optimize it for speed.

Writing the Right Codes:

  1. Rely on always running PHP codes – If a worker is written in PHP, tie the worker in an infinite loop which will wait for an event (A Queue, MySQL entry) instead of invoking PHP every second or so.
  2. Cache sooner – Although there are a couple of cache options in PHP – OPcache and Memcache. However, Redis is favourite which can further help you scaling by having multiple master or other topology. Combination of opcache and redis will be best.
  3. Load fewer classes – Ensure that you are not loading a lot of classes, rely on dynamic loading. This will increase the speed and reduce the memory.
  4. Keep over-writing variables – This is a pretty bad practice but it ensures that your memory is limited.
  5. Make smaller blocks – A heavy code or multiple functional calls under the loop are your sworn enemy. It is better to write multiple loops few smaller blocks than to have one large block.
  6. Use JSON instead of XML – JSON is a new standard and takes lesser memory.
  7. Use classes – Obvious but – having functions inside class will make it less memory hogger as long as you are loading classes when needed.

Micro Optimization of your codes:

These optimizations are not something you should do after the development as it has a very little effect. However, right from the beginning, a good practice is to follow it.

  1. Promote ‘static’ – This alone can increase the execution speed by 3X.
  2. Use single quotes – ‘ – As long as there is variable inside.
  3. Use str_replace instead of preg_replace_all
  4. Use ‘===’ instead of ‘==’
  5. Use ‘isset’ instead of count/size

Tell your network!

How to make app ready for scalability?

Most apps are built to fail – meaning that you develop an app with half-heartedly and not architect it well to make it scalable. Ask yourself, did you make an app to fail? The problem with success is scalability. If you can’t scale, you are bound to fail.

1. Divide Everything

I have a list of following things which you can divide. If you have more, please put that in comments:

  1. Multiple users can have separate database assigned.
  2. Credential are authenticated by a separate service.
  3. Outsource the background jobs to a different server.
  4. Have multiple queues.
  5. Have at least two masters.

2. Isolate and backup every service.

Putting small services on their own small servers can help you prevent a death from hardware failure. Consider an email sending service, you can easily have two or three service provider and if one is down, immediately switch to the second one. Similarly, if your backups are relying on one slave, make it work with the other one if it gets down.

3. Don’t just switch, resurrect the services.

We had three geolocation services on three separate servers. One day, none of them were working. In the log, we found that two were crashed weeks ago because of RAM usage as one of our developers used a nasty bulk check for 20M records. It only needed a service start command. So ensuring that it remains started can actually solve “fools’ development problem”

4. Proxy is new God

There are a lot of proxy solutions for every kind of services, place them ahead of everything you are running. These proxies serve two purposes:

  1. Switching the services when dead!
  2. Limiting the number of connections

Proxies have their own pool of connections and hence, despite you are hitting database by creating 200 connections, if it is going through a proxy service, it will be as low as 20. Some of the proxy solutions we have used:

5. Monitoring Services

We are a big fan of Prometheus and Grafana. While Prometheus exporters export different data, Grafana can be used to see it beautifully and send the alert.

6. (Bonus) – Attitude

Every app must be developed with a TDD/BDD approach and attempts must be made to tune everything you have. It is far better to run an optimized query than to throw a hardware on a database. The attitude of your development team matters most. So, the first step of scalability is in fact, make sure you hire the Good and fire the Bad.

Tell your network!