Common Backend Interface Performance Optimization Techniques
This article presents a comprehensive set of backend API performance optimization methods—including batch processing, asynchronous execution, caching, preprocessing, pooling, parallelization, indexing, transaction handling, pagination, SQL tuning, and lock granularity—illustrated with code snippets and diagrams to help developers improve response times and resource efficiency.
1. Background
For an older project, many cost‑reduction and efficiency‑improvement efforts were undertaken last year, and the most frequent issue discovered was excessively long API response times, prompting a focused round of interface performance optimization.
2. Summary of Interface Optimization Solutions
1. Batch Processing
The batch‑processing idea is to perform bulk database operations. In a loop‑insertion scenario, we can collect records and insert or update them in a single batch, avoiding multiple I/O operations.
// for loop single insert
list.stream().forEach(msg -> {
insert();
});
// batch insert
batchInsert();2. Asynchronous Processing
Asynchronous processing means moving time‑consuming, non‑essential logic to background execution, thereby reducing API latency.
For example, in a financial product purchase API, the accounting and file‑writing steps are currently synchronous because the transaction is T+1, but their real‑time results are not required. These steps can be handled asynchronously.
Asynchronous implementation can use thread pools, message queues, or scheduling frameworks.
3. Space‑Time Tradeoff (Caching)
A classic space‑time tradeoff is the proper use of caches. Frequently accessed, rarely changed data can be cached to avoid repeated database queries or recomputation.
Note that caching is a double‑edged sword; one must consider consistency issues.
Caches may be R2M, local caches, Memcached, or simple Maps.
Example: a stock‑tool query where rotation information updates weekly. Instead of querying the database each time, cache the rotation data and the expensive calculation results.
4. Preprocessing
Preprocessing (pre‑fetch) means calculating data in advance and storing it in a cache or a dedicated column, so that API calls can retrieve the ready‑made result quickly.
Example: a financial product’s annualized return rate can be pre‑calculated from the net value and stored, allowing the API to fetch the value directly.
5. Pooling Concept
Database connection pools, thread pools, etc., embody the pooling idea: they avoid repeated creation of objects or connections by reusing them, thus saving time.
The essence of pooling is pre‑allocation and cyclic reuse, which can be applied to many business scenarios.
6. Serial to Parallel
Serial execution waits for each step to finish before starting the next; parallel execution runs independent steps concurrently, reducing overall latency when there are no result dependencies.
Example: a portfolio‑display API that fetches user account info, product info, and banner data. Serial execution adds the latencies; parallel execution runs the fetches simultaneously.
7. Indexes
Adding appropriate indexes can dramatically improve query efficiency; this consideration should be part of API design.
Common scenarios where indexes do not work will be documented later.
8. Avoid Large Transactions
A large transaction is a long‑running transaction that holds database connections, causing contention and performance degradation.
@Transactional(value = "taskTransactionManager", propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = {RuntimeException.class, Exception.class})
public BasicResult purchaseRequest(PurchaseRecord record) {
BasicResult result = new BasicResult();
// insert account task
taskMapper.insert(ManagerParamUtil.buildTask(record, TaskEnum.Task_type.pension_account.type(), TaskEnum.Account_bizType.purchase_request.type()));
// insert sync task
taskMapper.insert(ManagerParamUtil.buildTask(record, TaskEnum.Task_type.pension_sync.type(), TaskEnum.Sync_bizType.purchase.type()));
// insert certificate upload task
taskMapper.insert(ManagerParamUtil.buildTask(record, TaskEnum.Task_type.pension_sync.type(), TaskEnum.Sync_bizType.cert.type()));
result.setInfo(ResultInfoEnum.SUCCESS);
return result;
}To avoid large‑transaction problems, follow these guidelines:
Do not place RPC calls inside a transaction.
Keep read‑only queries outside the transaction.
Avoid processing massive data sets within a single transaction.
9. Optimize Program Structure
Repeated feature additions over many iterations can lead to code bloat, duplicate queries, and unnecessary object creation. Refactor the API code, evaluate each block’s purpose, and reorder execution to improve performance.
10. Deep Pagination Issue
Using LIMIT offset, count with a large offset forces the database to scan many rows before returning the desired page, causing slowness.
select * from purchase_record where productCode = 'PA9044' and status = 4 order by orderTime desc limit 100000,200A common remedy is the “keyset pagination” technique:
select * from purchase_record where productCode = 'PA9044' and status = 4 and id > 100000 limit 200This leverages the primary‑key index, providing consistent performance regardless of page depth, though it requires an auto‑incrementing column.
11. SQL Optimization
SQL tuning can greatly improve API query performance; consider indexes, pagination, and other focal points when optimizing.
12. Lock Granularity
Locks protect shared resources in high‑concurrency scenarios, but overly coarse locks hurt performance.
Correct lock granularity means locking only the critical section of shared resources.
Wrong locking example:
// non‑shared resource
private void notShare() {}
// shared resource
private void share() {}
private int wrong() {
synchronized(this) {
share();
notShare();
}
}Correct locking example:
// non‑shared resource
private void notShare() {}
// shared resource
private void share() {}
private int right() {
notShare();
synchronized(this) {
share();
}
}3. Conclusion
Many API performance problems accumulate over time due to rapid feature delivery and code accumulation. By adopting a higher‑level mindset and designing APIs thoughtfully, developers can avoid these issues and achieve cost‑effective efficiency gains.
---
Note: The original article also contains promotional material for IDE licenses and paid resources, which is not part of the technical content.
Top Architecture Tech Stack
Sharing Java and Python tech insights, with occasional practical development tool tips.
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.