Effective way to count the API calls in an API service

Viewed 4633

I am asking this question in the context of DRF but this can be generalized too. We are maintaining an API service where we are serving 1K+ real-time requests. In the current scenario, we are counting the API calls in real-time, i.e. we are updating the database column of API calls count against the user for each API call.

But is there an effective method? For example, logging the API calls somewhere else and then updating the database after a few minutes? Or is this fine what we are doing at the moment? How large-scale API services might be handling this? No specific content is available on the web for this problem.

4 Answers

Redis is an in-memory key-value data store, so it can retrieve data very quickly. It’s also pretty straightforward to implement rate limiting with Redis and validate number of API calls. i.e.

  1. Store a key like a user’s IP address
  2. Increment the number of calls made from that IP

Redis Link

Redis Labs Link

If your application is writing its log to stdout you can easily connect it to a log database, like Elasticsearch, and then count the number of requests. You can also create very detailed dashboards that show your users are using your API.

You don't even need to read the output of your application server if you use a web server like NGINX to serve your API. You can pipe its stdout log into the database. Whatever the source, having an external process read directly from stdout will be more performant than any write operation you do on the application layer.

Treating your logs as event streams is one of the 12 factors described on the "Twelve-Factor App" methodology. You can find more information regarding this methodology on its website:

https://12factor.net/

I do not recommend you to implement this at the application level, instead, use network middleware to do this.

Like @guzmonne said, you can read Nginx logs directly or with the help of some tools like Filebeat/Logstash.

In my company, we are using Filebeat to collect logs (not only API calls) from containers (300+ nodes in several Kubernetes clusters) and other standalone services, all of them go to an Elasticsearch cluster where logs are analyzed.

We do not count API calls, but we do care about the fail rate, there are some Prometheus rules to send alerts when there are too many non-200 HTTP requests.

It seems you are using Django, so my advice would be to leverage Memcached here: https://docs.djangoproject.com/en/3.2/topics/cache/

Memcached is an in-memory storage that works very well with Django and that is simpler (but also has less features) than Redis. Memcached makes sure your counter is synchronized across all your Python processes, which is crucial for a Django server.

You could increment counters that track API calls using cache.incr(), and for each user request check the counters with cache.get().

As Memcached is "in-memory", data are not going to stay forever, so additionally you could increment a counter in DB asynchronously (you don't want to block your user requests for that). In order to make DB counter incrementation more efficient you should use F() expressions (https://docs.djangoproject.com/en/3.2/ref/models/expressions/#f-expressions).

Related