apache / apache/apisix

help request: Evaluating the reasonableness of APISIX’s performance overhead through load testing

Open
#13,188 1 comment 0 reactions 0 assignees View on GitHub
question
Dominant language
Lua
Stars
17.1k
Forks
2.9k
Avg merge
3d 16h
Merged PRs (30d)
63

Description

### Description

Evaluating the reasonableness of APISIX’s performance overhead through load testing

Hello, recently I ran load tests on APISIX and wanted to measure the performance overhead introduced by its Lua framework. Below is my load-testing approach.

### Configuration:
single process, single worker enabled.

### Goal:
mainly to evaluate the overhead in the access_by_lua_block phase.

Load-test comparison:

### Comment out the access_by_lua_block phase.

In the content phase, use the ngx.say API to return “hello”.

Remove proxy_pass, and eliminate overhead from SSL and other phases such as header_filter, body_filter, log_filter, etc.

### Keep the access_by_lua_block phase.

In the content phase, use the ngx.say API to return “hello”.

Remove proxy_pass, and eliminate overhead from SSL and other phases such as header_filter, body_filter, log_filter, etc.

Config file: as follows.
```

master_process on;

worker_processes 1;

# main configuration snippet starts

# main configuration snippet ends

error_log logs/error.log warn;
pid logs/nginx.pid;

worker_rlimit_nofile 20480;

events {
accept_mutex off;
worker_connections 10620;
}

worker_rlimit_core 16G;

worker_shutdown_timeout 240s;

env APISIX_PROFILE;
env PATH; # for searching external plugin runner's binary

# reserved environment variables for configuration
env APISIX_DEPLOYMENT_ETCD_HOST;
env GCP_SERVICE_ACCOUNT;


thread_pool grpc-client-nginx-module threads=1;

lua {
lua_shared_dict prometheus-cache 10m;
lua_shared_dict nacos 10m;
}

http {
....;

server {
http2 on;
listen 0.0.0.0:9080 default_server reuseport;
listen 0.0.0.0:9443 ssl default_server reuseport;

server_name _;

ssl_certificate cert/ssl_PLACE_HOLDER.crt;
ssl_certificate_key cert/ssl_PLACE_HOLDER.key;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 10m;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_session_tickets off;

proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;

# opentelemetry_set_ngx_var starts
set $opentelemetry_context_traceparent '';
set $opentelemetry_trace_id '';
set $opentelemetry_span_id '';
# opentelemetry_set_ngx_var ends

# zipkin_set_ngx_var starts
# zipkin_set_ngx_var ends

# http server configuration snippet starts

# http server configuration snippet ends

access_log off;

location = /apisix/nginx_status {
allow 127.0.0.0/24;
deny all;
access_log off;
stub_status;
}

# ssl_client_hello_by_lua_block {
# apisix.ssl_client_hello_phase()
# }
#
# ssl_certificate_by_lua_block {
# apisix.ssl_phase()
# }

proxy_ssl_name $upstream_host;
proxy_ssl_server_name on;
location / {
set $upstream_mirror_host '';
set $upstream_mirror_uri '';
set $upstream_upgrade '';
set $upstream_connection '';

set $upstream_scheme 'http';
set $upstream_host $http_host;
set $upstream_uri '';
set $ctx_ref '';

# http server location configuration snippet starts

# http server location configuration snippet ends

set $llm_content_risk_level '';
set $apisix_upstream_response_time $upstream_response_time;
set $request_type 'traditional_http';
set $request_llm_model '';

set $llm_time_to_first_token '0';
set $llm_model '';
set $llm_prompt_tokens '0';
set $llm_completion_tokens '0';

set $apisix_request_id $request_id;
lua_error_log_request_id $apisix_request_id;

# access_by_lua_block {
# apisix.http_access_phase()
# }

proxy_http_version 1.1;
proxy_set_header Host $upstream_host;
proxy_set_header Upgrade $upstream_upgrade;
proxy_set_header Connection $upstream_connection;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass_header Date;

### the following x-forwarded-* headers is to send to upstream server

set $var_x_forwarded_proto $scheme;
set $var_x_forwarded_host $host;
set $var_x_forwarded_port $server_port;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $var_x_forwarded_proto;
proxy_set_header X-Forwarded-Host $var_x_forwarded_host;
proxy_set_header X-Forwarded-Port $var_x_forwarded_port;

### the following configuration is to cache response content from upstream server

set $upstream_cache_zone off;
set $upstream_cache_key '';
set $upstream_cache_bypass '';
set $upstream_no_cache '';

proxy_cache $upstream_cache_zone;
proxy_cache_valid any 10s;
proxy_cache_min_uses 1;
proxy_cache_methods GET HEAD POST;
proxy_cache_lock_timeout 5s;
proxy_cache_use_stale off;
proxy_cache_key $upstream_cache_key;
proxy_no_cache $upstream_no_cache;
proxy_cache_bypass $upstream_cache_bypass;

content_by_lua_block {
ngx.say("benchmark")
}
#proxy_pass $upstream_scheme://apisix_backend$upstream_uri;

# mirror /proxy_mirror;

# header_filter_by_lua_block {
# apisix.http_header_filter_phase()
# }
#
# body_filter_by_lua_block {
# apisix.http_body_filter_phase()
# }
#
# log_by_lua_block {
# apisix.http_log_phase()
# }
}
}

```

Load-test results:

With access_by_lua_block commented out:
```
root@885e85bad68d:/usr/local/apisix/wrk# ./wrk -t4 -c200 -d30s -H "Host: test2.abc.com" http://127.0.0.1:9080/get --latency
Running 30s test @ http://127.0.0.1:9080/get
4 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.17ms 6.78ms 298.00ms 99.35%
Req/Sec 10.39k 846.65 22.23k 83.33%
Latency Distribution
50% 4.76ms
75% 5.01ms
90% 5.22ms
99% 6.59ms
1241296 requests in 30.01s, 222.55MB read
Requests/sec: 41363.43
Transfer/sec: 7.42MB

```

With access_by_lua_block kept:

```
root@885e85bad68d:/usr/local/apisix/wrk# ./wrk -t4 -c200 -d30s -H "Host: test2.abc.com" http://127.0.0.1:9080/get --latency
Running 30s test @ http://127.0.0.1:9080/get
4 threads and 200 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 18.97ms 45.68ms 977.12ms 98.01%
Req/Sec 3.66k 537.12 7.75k 78.33%
Latency Distribution
50% 12.77ms
75% 14.30ms
90% 18.52ms
99% 265.48ms
437710 requests in 30.08s, 78.48MB read
Requests/sec: 14549.67
Transfer/sec: 2.61MB

```

Preliminary conclusion: QPS drops by about `65%.`

I’d like to ask whether this level of performance overhead is considered reasonable, and whether it falls within the normal framework overhead behavior.

### Environment

- APISIX version (run `apisix version`):
```
- root@885e85bad68d:/usr/local/apisix/wrk# apisix version
/usr/local/openresty//luajit/bin/luajit /usr/local/apisix/apisix/cli/apisix.lua version
3.15.0
```
- Operating system (run `uname -a`):
```
Linux 885e85bad68d 4.18.0-553.80.1.el8_10.x86_64 #1 SMP Fri Oct 24 09:31:30 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
```
- OpenResty / Nginx version (run `openresty -V` or `nginx -V`):
```
root@885e85bad68d:/usr/local/apisix/wrk# openresty -v
nginx version: openresty/1.27.1.2
```
- etcd version, if relevant (run `curl http://127.0.0.1:9090/v1/server_info`):
- APISIX Dashboard version, if relevant:
- Plugin runner version, for issues related to plugin runners:
- LuaRocks version, for installation issues (run `luarocks --version`):

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the two configurations around access_by_lua_block and apisix.http_access_phase() with the provided wrk command and APISIX 3.15.0 environment. Compare the latency and request-rate results, then inspect the access-phase entry point and its documented execution path. Done means establishing whether the measured overhead is expected or identifying a specific, reproducible performance problem with supporting measurements.

Written by the indexing model from the issue text.

Assessment

Tech stack
lua, nginx
Domain
backend, performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.