Cloud functions work well with stateless APIs, but relational DB connections are stateful. When a serverless cloud function communicates with a relational database, it can quickly exhaust the available number of DB connections from the RDBMS pool. This happens because each instance of a cloud function opens its own DB connection. Therefore, if there are only 10-20 connections available from the RDBMS and more than 20 cloud function instances, the application may not function properly.
To address this problem, an intermediary service should be created to offer an HTTP stateless API that acts as a proxy for handling DB requests from serverless functions.
AWS introduced an RDS proxy service to solve this problem. Is there an analogous service for GCP when using Cloud Functions? Or do programmers need to implement a similar proxy service themselves? How is this issue typically handled on GCP?
It's a usual problem when a service scales out and not the other. There are several ways to mitigate the issue.
Limit the Database connection pool size on each function. If you use Cloud Functions 1st generation, set the pool to 1.
If you use 2nd generation, you have to test the best param according to your concurrency parameter. The safer way is to set a pool size equal to your concurrency value, but you could test a lower value.
Then calculate the max instance of your Cloud Functions according to your database max connexion: max instance = max connexion / pool size
A nicer implementation is to use the graceful period when an instance is killed to release the connections of the instance
If you need to scale higher with your service, you should implement a proxy service. The configuration is the same as described before, but it's used by your main service to perform queries in database.
The main problem with this design is the latency: you add, at least 10ms to call an additional service.
Ultimately, you can scale out your database. Use read replicas on traditional Cloud SQL or AlloyDB database to only be limited by the write operation and not the read.
The killer solution is to use Spanner (compliant with PostgreSQL interface) that scale out for read and write. the cost is expensive, but the technology awesome!