Let's imagine a problem: I have a REST service, which is implemented using Java/MySQL/Spring and HTTP/JSON technologies. The clients of the REST service are mobile applications. So it's possible that someone will decompile the code and will get the API of the REST service. ( Yes, the code is obfuscated etc, but anyway ).
Problem: there is a POST method to send money to other user of the application. I am worried, that someone can get the API, write a bot and make this POST request 500 or 5,000 or even 50,000 times per second. As a result, he might send more money than he actually has, because if 1000 requests are processed simultaneously then the balance checking might be successful for all 1000 request, however the real amount of money on an account might be enough only for, lets say, 50 requests.
So, basically, it's more like the standard "race" condition with multiple threads. The problem is, that I have multiple servers and they are not related with each other anyhow. So, 300 request can come to server A, 300 requests can come to server B and rest requests can come to server C.
The best idea what I have is to use something like "SELECT ... FOR UPDATE" and synchronize on database level. However, I would like to consider another solutions.
Any ideas or suggestions?
A simple example of a race condition is a light switch. In some homes, there are multiple light switches connected to a common ceiling light. When these types of circuits are used, the switch position becomes irrelevant. If the light is on, moving either switch from its current position turns the light off.
To avoid race conditions, any operation on a shared resource – that is, on a resource that can be shared between threads – must be executed atomically. One way to achieve atomicity is by using critical sections — mutually exclusive parts of the program.
REST is an Architecture, Not a Standard While HTTP is a standard, REST itself is not. Rather, it's an architectural style that provides constraints that guide REST API design. Many APIs do not conform to every element of REST, which has caused some to use the term RESTful to describe the most common types of APIs.
You have a few options:
Rely on ACID implementation of the database (MySQL in your case). Assuming you are using InnoDB engine, you need to choose the right transaction isolation level (SET TRANSACTION syntax) in combination with the right locking reads mechanism (SELECT ... FOR UPDATE and SELECT ... LOCK IN SHARE MODE Locking Reads). You need to understand these concepts well in order to do the right choice. It might be possible that simply using the right isolation level will already prevent the race condition even without the locking reads. The cons are you are trading off consistency for scalability and tying your application to RDBMS database thus it will be more difficult for you to move to NoSQL for example.
Decompose your back end into web tier and service tier (option suggested by atk in the comments). This will allow you to scale the web tier instances independently while keeping a single service tier instance. Having a single service tier instance makes it possible to use Java synchronization mechanisms such as synchronised
blocks or ReadWriteLock
. Although this solution will work I wouldn't recommend it since it reduces the scalability of your service tier.
This is an enhancement of the previous option. You can use a Distributed lock manager instead of built-in java synchronization mechanisms. It will allow you to scale your web tier and service tier independently.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With