Browse Source

aiohttp base nginx setup (#9796)

* aiohttp base nginx setup

* apply review fixes

* tune nginx worker settings

* use linux socket

* use nginx as default aiohttp server

* remove gunicorn from requirements
Sergey Kovalev 4 months ago
parent
commit
7d7f2238ca

+ 1 - 1
frameworks/Python/aiohttp/README.md

@@ -35,7 +35,7 @@ This will switch which database engine the app uses to execute queries with test
 
 
 ### Server
 ### Server
 
 
-gunicorn+uvloop on CPython
+nginx+uvloop on CPython
 
 
 ## Test URLs
 ## Test URLs
 
 

+ 14 - 0
frameworks/Python/aiohttp/aiohttp-gunicorn.dockerfile

@@ -0,0 +1,14 @@
+FROM python:3.13
+
+ADD ./ /aiohttp
+
+WORKDIR aiohttp
+
+RUN pip3 install cython==3.0.11 gunicorn==23.0.0 && \
+    pip3 install -r /aiohttp/requirements.txt
+
+ENV CONNECTION=RAW
+
+EXPOSE 8080
+
+CMD python3 -O -m gunicorn app.gunicorn:app -c gunicorn_conf.py

+ 11 - 3
frameworks/Python/aiohttp/aiohttp-orm.dockerfile

@@ -1,14 +1,22 @@
 FROM python:3.13
 FROM python:3.13
 
 
-ADD ./ /aiohttp
+RUN apt-get update && apt-get install -y nginx
 
 
-WORKDIR aiohttp
+ADD ./requirements.txt /aiohttp/requirements.txt
 
 
 RUN pip3 install cython==3.0.11 && \
 RUN pip3 install cython==3.0.11 && \
     pip3 install -r /aiohttp/requirements.txt
     pip3 install -r /aiohttp/requirements.txt
 
 
+ADD ./ /aiohttp
+
 WORKDIR /aiohttp
 WORKDIR /aiohttp
 
 
+ENV CONNECTION=ORM
+
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD python3 -O -m gunicorn app.gunicorn:app -c gunicorn_conf.py
+RUN chmod +x /aiohttp/nginx-entrypoint.sh
+
+ENTRYPOINT ["/aiohttp/nginx-entrypoint.sh"]
+
+

+ 9 - 3
frameworks/Python/aiohttp/aiohttp.dockerfile

@@ -1,14 +1,20 @@
 FROM python:3.13
 FROM python:3.13
 
 
-ADD ./ /aiohttp
+RUN apt-get update && apt-get install -y nginx
 
 
-WORKDIR aiohttp
+ADD ./requirements.txt /aiohttp/requirements.txt
 
 
 RUN pip3 install cython==3.0.11 && \
 RUN pip3 install cython==3.0.11 && \
     pip3 install -r /aiohttp/requirements.txt
     pip3 install -r /aiohttp/requirements.txt
 
 
+ADD ./ /aiohttp
+
+WORKDIR /aiohttp
+
 ENV CONNECTION=RAW
 ENV CONNECTION=RAW
 
 
 EXPOSE 8080
 EXPOSE 8080
 
 
-CMD python3 -O -m gunicorn app.gunicorn:app -c gunicorn_conf.py
+RUN chmod +x /aiohttp/nginx-entrypoint.sh
+
+ENTRYPOINT ["/aiohttp/nginx-entrypoint.sh"]

+ 14 - 0
frameworks/Python/aiohttp/app/app.py

@@ -0,0 +1,14 @@
+import uvloop
+from aiohttp import web
+import argparse
+from .main import create_app
+
+
+if __name__ == '__main__':
+    uvloop.install()
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--socket', type=str, required=True)
+    args = parser.parse_args()
+
+    app = create_app()
+    web.run_app(app, path=args.socket)

+ 25 - 2
frameworks/Python/aiohttp/benchmark_config.json

@@ -17,12 +17,35 @@
       "flavor": "Python3",
       "flavor": "Python3",
       "orm": "Raw",
       "orm": "Raw",
       "platform": "asyncio",
       "platform": "asyncio",
-      "webserver": "gunicorn",
+      "webserver": "nginx",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "aiohttp",
       "display_name": "aiohttp",
       "notes": "uses asyncpg for database access"
       "notes": "uses asyncpg for database access"
     },
     },
+    "gunicorn": {
+      "json_url": "/json",
+      "db_url": "/db",
+      "query_url": "/queries/",
+      "fortune_url": "/fortunes",
+      "update_url": "/updates/",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Micro",
+      "database": "Postgres",
+      "framework": "aiohttp",
+      "language": "Python",
+      "flavor": "Python3",
+      "orm": "Raw",
+      "platform": "asyncio",
+      "webserver": "nginx",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "aiohttp-gunicorn",
+      "notes": "uses gunicorn as proxy server",
+      "versus": "default"
+    },
     "orm": {
     "orm": {
       "db_url": "/db",
       "db_url": "/db",
       "query_url": "/queries/",
       "query_url": "/queries/",
@@ -37,7 +60,7 @@
       "flavor": "Python3",
       "flavor": "Python3",
       "orm": "Full",
       "orm": "Full",
       "platform": "asyncio",
       "platform": "asyncio",
-      "webserver": "gunicorn",
+      "webserver": "nginx",
       "os": "Linux",
       "os": "Linux",
       "database_os": "Linux",
       "database_os": "Linux",
       "display_name": "aiohttp-orm",
       "display_name": "aiohttp-orm",

+ 19 - 2
frameworks/Python/aiohttp/config.toml

@@ -15,9 +15,26 @@ database_os = "Linux"
 os = "Linux"
 os = "Linux"
 orm = "Raw"
 orm = "Raw"
 platform = "asyncio"
 platform = "asyncio"
-webserver = "gunicorn"
+webserver = "nginx"
 versus = "None"
 versus = "None"
 
 
+[gunicorn]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries/"
+urls.update = "/updates/"
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "asyncio"
+webserver = "gunicorn"
+versus = "default"
+
 [orm]
 [orm]
 urls.db = "/db"
 urls.db = "/db"
 urls.query = "/queries/"
 urls.query = "/queries/"
@@ -30,5 +47,5 @@ database_os = "Linux"
 os = "Linux"
 os = "Linux"
 orm = "Full"
 orm = "Full"
 platform = "asyncio"
 platform = "asyncio"
-webserver = "gunicorn"
+webserver = "nginx"
 versus = "default"
 versus = "default"

+ 64 - 0
frameworks/Python/aiohttp/nginx-entrypoint.sh

@@ -0,0 +1,64 @@
+#!/bin/sh
+set -e
+CORES=$(nproc)
+echo "$CORES cores detected, starting $CORES aiohttp workers..."
+
+for i in $(seq 0 $((CORES-1))); do
+  SOCKET="/run/aiohttp-$i.sock"
+  echo "Starting worker on socket $SOCKET"
+  python3 -O -m app.app --socket $SOCKET &
+done
+
+echo "Waiting for all workers to be ready..."
+for i in $(seq 0 $((CORES-1))); do
+  SOCKET="/run/aiohttp-$i.sock"
+  until [ -S "$SOCKET" ]; do
+    echo "Waiting for socket $SOCKET..."
+    sleep 0.2
+  done
+  chown root:www-data "$SOCKET"
+  chmod 660 "$SOCKET"
+done
+
+cat > /aiohttp/nginx.conf <<EOF
+user www-data;
+worker_processes auto;
+
+events {
+    worker_connections 65535;
+}
+
+http {
+    keepalive_requests 10000000;
+
+    upstream aiohttp {
+        least_conn;
+EOF
+
+for i in $(seq 0 $((CORES-1))); do
+  echo "        server unix:/run/aiohttp-$i.sock fail_timeout=0;" >> /aiohttp/nginx.conf
+done
+
+cat >> /aiohttp/nginx.conf <<EOF
+        keepalive 32;
+    }
+
+    server {
+        listen 8080 reuseport;
+
+        access_log off;
+        error_log stderr error;
+
+        location / {
+            proxy_pass http://aiohttp;
+            proxy_http_version 1.1;
+            proxy_set_header Connection "";
+            proxy_redirect off;
+            proxy_buffering off;
+        }
+    }
+}
+EOF
+
+echo "Starting Nginx..."
+nginx -c /aiohttp/nginx.conf -g "daemon off;"

+ 0 - 1
frameworks/Python/aiohttp/requirements.txt

@@ -1,6 +1,5 @@
 aiohttp==3.11.16
 aiohttp==3.11.16
 asyncpg==0.30.0
 asyncpg==0.30.0
-gunicorn==23.0.0
 jinja2==3.1.6
 jinja2==3.1.6
 SQLAlchemy==2.0.40
 SQLAlchemy==2.0.40
 orjson==3.10.16
 orjson==3.10.16