# Performance Overview

EntryTarget is designed for high-throughput financial workloads. The batch processing engine is the key to its performance — it accumulates multiple transactions and commits them in a single database transaction.

## How the Batch Engine Works

Instead of committing each transaction individually (which would be limited by Postgres commit latency), the batch engine:

1. Accumulates incoming transactions in a queue
2. Flushes them as a single batch when either:
   * The configured `BATCH_SIZE` is reached, **or**
   * The configured `BATCH_TIMEOUT_MS` has elapsed
3. Processes all transactions in the batch within one database transaction
4. Commits once, returns all responses

This means an account touched by 150 transactions in one batch is written to the database exactly **once** — a single row update, one WAL write, one COMMIT.

## Performance Results

All results measured with authentication and metrics middleware active:

| Scenario                                    | Client TPS | p50    | p99     |
| ------------------------------------------- | ---------- | ------ | ------- |
| 10K tx, 10K accounts, 1 instance            | \~16,000   | \~10ms | \~42ms  |
| 1M tx, 1M accounts, 1 instance              | \~11,600   | \~11ms | \~45ms  |
| 1M tx, 15K accounts, 3 instances (66 conc.) | \~7,400    | \~18ms | \~113ms |

### Understanding TPS Numbers

* **Client TPS** counts all transactions including rejected ones (e.g., `INSUFFICIENT_FUNDS`)
* **DB TPS** counts only committed writes
* The difference (\~15-18%) reflects rejected transactions that consumed no database resources
* To measure true server throughput, use `rate(ledger_transactions_total[1m])` in Prometheus

## Optimal Client Concurrency

The optimal number of concurrent requests from your client is approximately equal to `BATCH_SIZE`. More concurrent requests increase queue depth without increasing throughput.

| Batch Size | Recommended Client Concurrency |
| ---------- | ------------------------------ |
| 150        | \~150 concurrent requests      |
| 200        | \~200 concurrent requests      |
| 300        | \~300 concurrent requests      |

## Latency Breakdown

A typical transaction's lifecycle:

```
Client sends request
    |  ~0ms   (nanoseconds)
    v
Idempotency check (in-memory)
    |  0-15ms (waits for batch to fill or timeout)
    v
Batch processing (validation + SQL)
    |  5-15ms (Postgres COMMIT)
    v
Response sent to client
```

The majority of latency comes from:

1. **Batch wait time** — up to `BATCH_TIMEOUT_MS` if the batch doesn't fill
2. **Postgres COMMIT** — the actual database write

## Performance Cost of Security Features

| Feature              | Cost per Batch                   | Impact     |
| -------------------- | -------------------------------- | ---------- |
| Authentication cache | \~0 (cached after first request) | Negligible |
| Row-level integrity  | \~150μs for 150 transactions     | Negligible |
| Metrics recording    | \~0 (atomic counters in memory)  | Negligible |

All security and observability features add negligible overhead compared to the Postgres COMMIT time.

## Scaling

The system scales primarily through:

1. **Vertical scaling** — larger RDS instances handle larger batches
2. **Batch tuning** — larger batches amortize commit overhead over more transactions
3. **Connection pool sizing** — more connections support more concurrent batches

See [Tuning Guide](/docs/performance/tuning.md) and [Performance Tiers](/docs/performance/tiers.md) for specific recommendations.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://entrytarget.gitbook.io/docs/performance/overview.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
