Building a Production-Ready Event-Driven Fraud Detection System on AWS
Learn how to design a scalable real-time fraud detection platform using AWS, Spring Boot, Kafka, Redis, and MySQL. This article explores event-driven architecture, low-latency risk evaluation, asynchronous processing, security, fault tolerance, observability, and production scalability.
Modern financial systems process thousands of transactions every second. A fraud detection system therefore cannot simply query a database, execute a few rules, and return a response.
The system must make decisions with low latency, remain available during traffic spikes, process large volumes of events, and prevent a failure in one component from bringing down the entire transaction pipeline.
In this article, we will design a real-time fraud detection architecture using AWS, Spring Boot, Kafka, Redis, and MySQL, while focusing on the engineering decisions behind the architecture.
1. Problem Statement
Consider a payment transaction:
1
User → Payment System → Fraud Detection → DecisionFor every transaction, the fraud detection layer may need to evaluate:
- User transaction history
- Blacklisted accounts
- Transaction velocity
- Suspicious IP addresses
- Unusual transaction amounts
- Geographic anomalies
- Previously detected fraud
- Account risk level
A naive implementation might perform multiple database queries for every transaction:
1
2
3
4
5
6
7
8
9
10
11
12
13
Request
↓
Query User
↓
Query Blacklist
↓
Query Transactions
↓
Calculate Risk
↓
Store Result
↓
ResponseThis approach becomes problematic as transaction volume increases.
If every request requires multiple synchronous database operations, database latency eventually becomes part of the transaction latency.
The solution is to separate the critical transaction path from the asynchronous processing path.
2. High-Level Architecture
A production-oriented architecture can be structured as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
┌──────────────────┐
│ Client │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ API Gateway │
└────────┬─────────┘
│
▼
┌────────────────────────┐
│ Spring Boot Fraud API │
│ on ECS/Fargate │
└───────────┬────────────┘
│
┌──────────────┴──────────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Redis │ │ MySQL │
│ ElastiCache │ │ RDS │
└─────────────┘ └─────────────┘
│
│
▼
┌─────────────────┐
│ Amazon MSK │
│ Kafka │
└────────┬────────┘
│
┌───────┴────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Fraud Worker │ │ Audit Worker │
└──────┬───────┘ └──────┬───────┘
│ │
└────────┬─────────┘
▼
┌─────────────────┐
│ Amazon S3 / │
│ CloudWatch │
└─────────────────┘The important architectural decision here is that not every operation has to be synchronous.
3. Why Event-Driven Architecture?
Kafka provides an event streaming layer between producers and consumers.
Instead of directly calling every downstream service:
1
2
3
API → Fraud Service → Audit Service
→ Notification Service
→ Analytics Servicewe can publish an event:
1
2
3
4
5
6
7
8
API
↓
Kafka Topic
↓
├── Fraud Consumer
├── Audit Consumer
├── Analytics Consumer
└── Notification ConsumerThis provides several advantages.
Loose Coupling
The transaction API does not need to know how every downstream service works.
A new consumer can be added without modifying the producer.
Independent Scaling
If fraud processing requires 10 consumers while audit processing requires only 2, they can scale independently.
Fault Isolation
If the audit service temporarily fails, the transaction producer does not necessarily have to fail.
Kafka retains the events so consumers can process them later.
Replayability
Events can be reprocessed when necessary.
This is particularly useful when fraud detection logic changes and historical transactions need to be analyzed again.
4. Designing the Transaction Flow
A transaction request could look like:
1
2
3
4
5
6
7
8
{
"transactionId": "TXN-10001",
"userId": "USER-123",
"amount": 85000,
"currency": "INR",
"merchantId": "MERCHANT-45",
"ipAddress": "192.168.1.10"
}The Spring Boot API validates the request and performs the minimum amount of synchronous processing required.
The first step is to check low-latency information from Redis.
For example:
1
2
3
4
5
6
7
Transaction
↓
Redis
├── Blacklist?
├── Previous risk score?
├── Transaction velocity?
└── Temporary restrictions?If the transaction passes the initial checks, an event can be published to Kafka.
Example event:
1
2
3
4
5
6
7
{
"eventType": "TRANSACTION_CREATED",
"transactionId": "TXN-10001",
"userId": "USER-123",
"amount": 85000,
"timestamp": "2026-10-04T10:30:00Z"
}5. Why Redis?
One of the biggest bottlenecks in real-time systems is repeatedly querying a relational database for information that changes frequently but can be represented as key-value data.
Redis is useful for:
- Blacklists
- Rate limits
- Transaction counters
- Temporary risk scores
- Session information
- Frequently accessed user risk profiles
For example:
1
2
3
4
5
fraud:blacklist:user:123 → true
fraud:velocity:user:123 → 7
fraud:risk:user:123 → 82We can also use TTLs.
For example:
1
2
transaction_count:user:123
TTL = 60 secondsThis allows the system to detect rules such as:
More than 10 transactions from the same account within 60 seconds.
Without Redis, the application might repeatedly execute:
1
2
3
4
SELECT COUNT(*)
FROM transactions
WHERE user_id = ?
AND transaction_time >= NOW() - INTERVAL 60 SECOND;At very high transaction volumes, this can create unnecessary database load.
Redis allows these frequently accessed counters to be maintained in memory.
6. Kafka Partitioning Strategy
Kafka performance depends heavily on partitioning.
Suppose we have:
1
transactionswith 12 partitions.
We can use:
1
userIdas the partition key.
For example:
1
2
3
4
user-101 → Partition 0
user-102 → Partition 4
user-103 → Partition 7
user-101 → Partition 0This provides an important property:
Events for the same user can be routed to the same partition, preserving their order within that partition.
This can matter for fraud detection because transaction order can affect risk calculations.
However, partition keys must be selected carefully.
If one key receives a disproportionate amount of traffic, it can create a hot partition.
Therefore, partitioning is not simply a configuration detail. It is a scalability decision.
7. Consumer Groups
Kafka consumers can be organized into consumer groups.
For example:
1
2
3
4
5
6
Fraud Consumer Group
Consumer 1 → P0 P1 P2
Consumer 2 → P3 P4 P5
Consumer 3 → P6 P7 P8
Consumer 4 → P9 P10 P11If transaction traffic increases, more consumers can be added.
This allows the processing layer to scale horizontally.
However, adding consumers beyond the number of partitions does not provide additional parallelism for that topic.
Therefore:
1
Maximum parallel consumers ≈ Number of partitionsThis is an important capacity-planning consideration.
8. MySQL as the System of Record
Redis is optimized for fast access, but it should not replace the relational database as the primary system of record.
MySQL can store:
1
2
3
4
5
6
users
transactions
fraud_decisions
blacklist_entries
risk_profiles
audit_recordsFor example:
1
2
3
4
5
6
7
CREATE TABLE transactions (
transaction_id VARCHAR(50) PRIMARY KEY,
user_id VARCHAR(50) NOT NULL,
amount DECIMAL(15,2) NOT NULL,
status VARCHAR(20),
created_at TIMESTAMP
);The database provides durable storage and transactional guarantees.
A useful architectural separation is:
1
2
3
4
5
6
7
Redis → Fast temporary state
MySQL → Durable business data
Kafka → Event stream
S3 → Long-term object storageEach technology is therefore used for the problem it is best suited to solve.
9. Running Spring Boot on AWS
The Spring Boot application can be packaged as a Docker container:
1
2
3
4
5
6
7
8
9
Spring Boot Application
↓
Docker
↓
Amazon ECR
↓
Amazon ECS
↓
AWS FargateAmazon ECR stores the container image.
Amazon ECS manages the containers.
AWS Fargate allows the application to run without manually managing EC2 servers.
Multiple ECS tasks can run behind a load balancer:
1
2
3
4
5
Application Load Balancer
/ | \
/ | \
ECS ECS ECS
Task 1 Task 2 Task 3If traffic increases, ECS can increase the number of running tasks.
10. Security Architecture
A financial application cannot treat security as an afterthought.
The architecture should use multiple layers of protection.
IAM
Each AWS component should receive only the permissions it requires.
For example:
1
2
3
4
5
Fraud Service
↓
Read specific secrets
Publish to specific Kafka resources
Read/write specific database resourcesAvoid giving an application broad administrative permissions.
This follows the principle of least privilege.
VPC
Application services should be placed inside a controlled VPC.
A typical design is:
1
2
3
4
5
6
7
8
9
10
Internet
↓
Load Balancer
↓
Public Subnet
↓
Private Subnet
├── ECS
├── Redis
└── DatabaseThe database should not be directly accessible from the public internet.
Secrets
Database passwords, API credentials, and other sensitive values should not be hardcoded into:
1
application.propertiesThey should be managed using services such as:
AWS Secrets Manager
11. Idempotency
Distributed systems can deliver the same event more than once.
Suppose:
1
TXN-10001is processed successfully, but the consumer crashes before acknowledging the Kafka message.
The message may be processed again.
Without idempotency:
1
2
3
4
5
TXN-10001
↓
Fraud Decision
↓
Fraud Decision AGAINThe application should therefore maintain an idempotency mechanism.
For example:
1
2
transaction_id = TXN-10001
processing_status = COMPLETEDBefore processing an event:
1
2
3
4
Does transaction already have a completed decision?
YES → Ignore duplicate
NO → Process transactionThis is an essential concept when designing distributed systems.
12. Handling Failures
Production systems should assume that components will fail.
Possible failures include:
1
2
3
4
5
6
Redis unavailable
Kafka consumer crash
Database connection failure
Network timeout
Application crash
AWS service throttlingThe architecture should therefore implement:
- Retry mechanisms
- Dead-letter topics
- Timeouts
- Circuit breakers
- Idempotent processing
- Health checks
- Monitoring
- Graceful degradation
For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
Kafka
↓
Consumer
↓
Processing Failed
↓
Retry
↓
Retry
↓
Retry
↓
Dead Letter TopicA dead-letter topic prevents permanently failing messages from blocking normal processing.
13. Observability
A distributed architecture without observability becomes extremely difficult to debug.
CloudWatch can be used to monitor:
1
2
3
4
5
6
7
8
API latency
CPU utilization
Memory utilization
Error rate
Kafka consumer lag
Database connections
Redis latency
Request throughputFor example, an increase in Kafka consumer lag could indicate:
1
2
3
4
5
6
7
Incoming events
↓
1000 events/sec
Consumers
↓
600 events/secThe backlog will continuously increase.
This is a signal that the consumer layer needs additional capacity or optimization.
Monitoring should therefore focus not only on infrastructure metrics but also on business and system-level metrics.
14. Scaling Strategy
Suppose the system initially handles:
1
1,000 transactions/secand eventually grows to:
1
10,000 transactions/secScaling cannot simply mean increasing the CPU of one server.
Instead, the architecture should scale horizontally:
1
2
3
4
5
6
7
8
9
10
11
Load Balancer
/ | \
ECS ECS ECS
↓ ↓ ↓
Kafka
/ | \
C1 C2 C3
\ | /
Redis
↓
RDSEach layer can scale independently.
This is one of the major benefits of a decoupled architecture.
15. The Critical Path vs Asynchronous Path
One of the most important architectural decisions is determining what must happen before the transaction response and what can happen later.
Critical path
1
2
3
4
5
6
7
8
9
10
11
Request
↓
Authentication
↓
Basic validation
↓
Redis risk checks
↓
Fraud decision
↓
ResponseAsynchronous path
1
2
3
4
5
6
7
Transaction Event
↓
Kafka
↓
┌─────┼────────┐
↓ ↓ ↓
Audit Analytics NotificationsThis separation prevents non-critical workloads from unnecessarily increasing transaction latency.
16. Why Not Use Only a Database?
A common question is:
Why not simply use MySQL for everything?
MySQL is excellent for durable relational data, but using it for every real-time operation creates unnecessary pressure on the database.
For example, if every transaction performs:
1
2
3
5 database reads
+
2 database writesthen:
1
2
3
4
5
10,000 transactions/sec
×
7 database operations
=
70,000 database operations/secThis can quickly become a bottleneck.
Instead:
1
2
3
4
5
6
7
8
9
10
11
Redis
→ frequently accessed state
Kafka
→ asynchronous event processing
MySQL
→ durable relational data
S3
→ large-scale object storageThis division allows each component to perform the workload it is designed for.
17. Cost Considerations
Scalability should not mean unlimited infrastructure.
AWS architecture should be designed around actual workload requirements.
Potential optimization strategies include:
- Right-sizing ECS tasks
- Configuring appropriate Kafka partitions
- Setting Redis memory policies
- Using S3 lifecycle policies
- Controlling CloudWatch log retention
- Using autoscaling
- Avoiding unnecessary cross-region traffic
- Monitoring database utilization
The objective is not simply to build the most powerful system.
The objective is to build a system that provides the required latency, reliability, scalability, and security at a reasonable cost.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article