Mastering Idempotency: Ensure Reliable Operations in Distributed Systems
Idempotency ensures that repeated service calls or user actions produce the same effect without unintended side effects, a critical concern in distributed and microservice architectures; this article explains its principles, SQL examples, HTTP semantics, token strategies, lock handling, and message‑queue solutions.
Idempotency Introduction
In modern distributed or micro‑service architectures, service calls may be retried or invoked multiple times, leading to latency or failure. To guarantee consistent results—especially in scenarios such as payments—business logic must be idempotent.
Definition
Idempotency means that multiple executions of an operation have the same effect on resources as a single execution; the result may differ, but the state does not change after the first successful call.
SQL Examples
Consider the following statements: select * from table where id=1 This SELECT query can be executed any number of times without changing data, thus it is idempotent. insert into table(id,name) values (1,'heima') If id or name has a unique constraint, the statement can insert only one row, making it idempotent; otherwise it is not. update table set score=100 where id=1 Repeated execution always produces the same data change, so it is idempotent.
Design Dimensions
Idempotency is considered from two dimensions:
Space : defines the scope, e.g., an order must not be created twice.
Time : defines the validity period; some operations require permanent idempotency (order, payment), others only for a limited window.
Locks are often introduced to handle concurrent safety.
Business Scenarios
Multiple clicks on a “place order” button should generate only one order.
Payment should be deducted only once regardless of retries.
Inventory deduction must occur once per successful payment.
Shipping should be triggered only once per order.
Implementing idempotency adds complexity and may reduce throughput, so it should be applied based on concrete business needs.
HTTP Protocol Idempotency
RESTful APIs define idempotent semantics for common HTTP methods:
GET : safe and idempotent; multiple calls do not affect resources.
POST : not idempotent; each call may create a new resource.
PUT : idempotent; repeated calls produce the same effect.
DELETE : idempotent; repeated deletions have the same outcome.
Interface Idempotency – Token Mechanism
A common solution is to issue a one‑time token to the client. The server stores the token (e.g., in Redis for distributed systems) and validates it on each request.
@Component
public class FeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
// Pass token
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes != null) {
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
if (request != null) {
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
if ("token".equals(headerName)) {
String headerValue = request.getHeader(headerName);
requestTemplate.header(headerName, headerValue);
}
}
}
}
}
}The server checks the token existence in Redis; if present, it processes the request and then deletes the token. If absent, the request is considered duplicate.
In high‑concurrency scenarios, a race condition may allow two requests to pass before the token is deleted. One remedy is to serialize the operation with a thread lock, at the cost of throughput.
Anti‑Duplicate Table
Another approach is to create a dedicated table with a unique index on fields that identify a request. Insertion into this table succeeds only once; subsequent attempts fail, preventing duplicate processing.
Message Idempotency
When using message queues, retries can cause the same message to be delivered multiple times. Ensuring idempotency at the consumer side is essential.
RabbitMQ Retry and Compensation
RabbitMQ retries messages when the consumer throws an exception. After a configurable number of retries, the message can be moved to a dead‑letter queue for manual compensation.
# Consumer listener configuration
listener:
simple:
retry:
enabled: true
max-attempts: 5
initial-interval: 3000Message Idempotency Solutions
Use a Redis‑backed deduplication key.
Employ a deduplication table similar to the service‑side approach.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
