Skip to content

Commit 4889cde

Browse files
Merge pull request #2770 from odidev/django-lp
Update Django Arm64 learning path to use GKE Axion with Cloud SQL and Redis
2 parents 1f7cef3 + f45c7b1 commit 4889cde

7 files changed

Lines changed: 654 additions & 105 deletions

File tree

content/learning-paths/servers-and-cloud-computing/django-on-gcp/_index.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@ title: Deploy Django on Google Cloud C4A (Arm-based Axion VMs)
33

44
minutes_to_complete: 30
55

6-
who_is_this_for: This Learning Path is for software developers deploying and optimizing Django-based web applications on Arm64 Linux environments, specifically using Google Cloud C4A virtual machines powered by Axion processors.
6+
who_is_this_for: This Learning Path is designed for DevOps engineers and software developers who want to deploy, operate, and benchmark a production-grade Django REST API on Google Kubernetes Engine (GKE) running on Arm64 Axion processors, integrated with managed Google Cloud data services.
77

88
learning_objectives:
99
- Provision an Arm-based SUSE Linux Enterprise Server (SLES) virtual machine on Google Cloud (C4A with Axion processors)
10-
- Install Django on a SUSE Arm64 (C4A) instance
11-
- Verify Django functionality by running the development server and accessing the default welcome page on the Arm64 VM
12-
- Measure Django application performance by benchmarking request handling throughput and latency using the official ApacheBench (ab) tool with Gunicorn on Arm64 (aarch64)
10+
- Provision Google Axion (Arm64) compute using GKE node pools
11+
- Package a Django REST API into an Arm-native Docker container
12+
- Push container images to Google Artifact Registry
13+
- Deploy Django on GKE using Kubernetes manifests (Deployment, Service, ConfigMap, Secrets)
14+
- Integrate Django with Cloud SQL (PostgreSQL) over private IP
15+
- Integrate Django with Memorystore (Redis) for caching and sessions
16+
- Expose Django using a Kubernetes LoadBalancer
17+
- Validate application connectivity to PostgreSQL and Redis
18+
- Measure throughput and p95 latency using ApacheBench against Gunicorn on Arm
1319

1420
prerequisites:
1521
- A [Google Cloud Platform (GCP)](https://cloud.google.com/free) account with billing enabled
@@ -27,9 +33,11 @@ armips:
2733

2834
tools_software_languages:
2935
- Django
30-
- Python
31-
- Gunicorn
32-
- Apache Bench
36+
- Docker
37+
- Kubernetes
38+
- Google Artifact Registry
39+
- Cloud SQL (PostgreSQL)
40+
- Memorystore (Redis)
3341

3442
operatingsystems:
3543
- Linux
@@ -47,6 +55,15 @@ further_reading:
4755
title: Django documentation
4856
link: https://docs.djangoproject.com/
4957
type: documentation
58+
- resource:
59+
title: Cloud SQL for PostgreSQL
60+
link: https://cloud.google.com/sql/docs/postgres
61+
type: documentation
62+
63+
- resource:
64+
title: Memorystore for Redis
65+
link: https://cloud.google.com/memorystore/docs/redis
66+
type: documentation
5067

5168
- resource:
5269
title: Apache-bench documentation
Lines changed: 80 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Benchmark Django application performance on Arm
3-
weight: 7
3+
weight: 10
44

55
### FIXED, DO NOT MODIFY
66
layout: learningpathall
@@ -19,8 +19,8 @@ ApacheBench (`ab`) is a command-line tool that simulates multiple HTTP requests
1919
```console
2020
sudo zypper install -y apache2-utils
2121
```
22-
## Verify installation
2322

23+
### Verify installation
2424
This command confirms ApacheBench is correctly installed and available system-wide:
2525

2626
```console
@@ -29,161 +29,145 @@ ab -V
2929

3030
The output displays the ApacheBench version, confirming successful installation.
3131

32-
## Install and configure Gunicorn
32+
### Install and configure Gunicorn
3333

3434
Before benchmarking your Django application, you need to install Gunicorn, a production-grade WSGI HTTP server. Gunicorn provides better performance characteristics than Django's development server and more accurately represents real-world deployment scenarios.
3535

36-
Install both Django and Gunicorn using pip:
36+
### Install both Django and Gunicorn using pip:
3737

3838
```console
3939
python3 -m pip install django gunicorn
4040
```
41-
4241
This command installs two essential packages. Django is the Python web framework you're benchmarking, while Gunicorn serves as a high-performance WSGI HTTP server that handles multiple concurrent requests efficiently. Unlike Django's built-in development server, Gunicorn is designed for production workloads and provides the multi-worker architecture needed for accurate performance testing.
4342

43+
### Run Django with Gunicorn
44+
Start your Django application using Gunicorn (already running inside GKE):
4445

45-
## Run Django with Gunicorn
46-
47-
Start your Django application using Gunicorn:
48-
49-
```console
50-
gunicorn myproject.wsgi:application --bind 0.0.0.0:8000 --workers 4 &
51-
```
52-
53-
This command starts Gunicorn with four worker processes to handle concurrent requests. Replace `myproject` with your Django project's actual name. The `--bind 0.0.0.0:8000` flag makes the server accessible on port 8000 from any network interface, while the `&` runs the process in the background so you can continue using your terminal.
46+
Gunicorn is deployed inside your Kubernetes Pods and exposed via a Kubernetes Service and LoadBalancer.
47+
The benchmark is executed against the **external IP of the GKE service**.
5448

5549
{{% notice Note %}}
5650
Ensure your VM's firewall allows inbound traffic on port 8000. See the firewall setup section if you haven't already configured this.
5751
{{% /notice %}}
5852

59-
## Run the benchmark
53+
### Run the benchmark
54+
6055
Use ApacheBench to test your Django server with simulated traffic:
6156

6257
```console
63-
ab -n 1000 -c 10 http://127.0.0.1:8000/
58+
ab -n 5000 -c 100 http://<external_IP_of_the_GKE_service>/healthz/
6459
```
65-
66-
This sends 1000 requests using 10 concurrent connections to your local server's root URL. The `-n` flag sets the total number of requests, while `-c` controls how many run simultaneously.
67-
68-
The output is similar to:
60+
This sends 5000 requests using 100 concurrent connections to your Django REST endpoint exposed through the GKE LoadBalancer.
6961

7062
```output
7163
This is ApacheBench, Version 2.3
72-
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
73-
Licensed to The Apache Software Foundation, http://www.apache.org/
74-
75-
Benchmarking 127.0.0.1 (be patient)
76-
Completed 100 requests
77-
Completed 200 requests
78-
Completed 300 requests
79-
Completed 400 requests
80-
Completed 500 requests
81-
Completed 600 requests
82-
Completed 700 requests
83-
Completed 800 requests
84-
Completed 900 requests
85-
Completed 1000 requests
86-
Finished 1000 requests
64+
Benchmarking 34.132.110.81 (be patient)
8765
8866
Server Software: gunicorn
89-
Server Hostname: 127.0.0.1
90-
Server Port: 8000
67+
Server Hostname: 34.132.110.81
68+
Server Port: 80
9169
92-
Document Path: /
93-
Document Length: 41 bytes
70+
Document Path: /healthz/
71+
Document Length: 15 bytes
9472
95-
Concurrency Level: 10
96-
Time taken for tests: 0.104 seconds
97-
Complete requests: 1000
73+
Concurrency Level: 100
74+
Time taken for tests: 0.357 seconds
75+
Complete requests: 5000
9876
Failed requests: 0
99-
Total transferred: 280000 bytes
100-
HTML transferred: 41000 bytes
101-
Requests per second: 9651.21 [#/sec] (mean)
102-
Time per request: 1.036 [ms] (mean)
103-
Time per request: 0.104 [ms] (mean, across all concurrent requests)
104-
Transfer rate: 2639.00 [Kbytes/sec] received
77+
Total transferred: 1650000 bytes
78+
HTML transferred: 75000 bytes
79+
Requests per second: 14001.88 [#/sec] (mean)
80+
Time per request: 7.142 [ms] (mean)
81+
Time per request: 0.071 [ms] (mean, across all concurrent requests)
82+
Transfer rate: 4512.32 [Kbytes/sec] received
10583
10684
Connection Times (ms)
10785
min mean[+/-sd] median max
108-
Connect: 0 0 0.1 0 1
109-
Processing: 0 1 0.3 1 4
110-
Waiting: 0 1 0.3 1 3
111-
Total: 0 1 0.4 1 5
86+
Connect: 0 0 0.2 0 2
87+
Processing: 1 6 4.7 6 32
88+
Waiting: 0 6 4.7 6 32
89+
Total: 1 7 4.8 6 34
11290
11391
Percentage of the requests served within a certain time (ms)
114-
50% 1
115-
66% 1
116-
75% 1
117-
80% 1
118-
90% 1
119-
95% 2
120-
98% 2
121-
99% 3
122-
100% 5 (longest request)
92+
50% 6
93+
66% 9
94+
75% 10
95+
80% 11
96+
90% 11
97+
95% 11
98+
98% 16
99+
99% 28
100+
100% 34 (longest request)
123101
```
102+
124103
## Stop the Gunicorn server
125104

126105
After reviewing the benchmark results, stop the Gunicorn server running in the background:
127106

128107
```bash
129108
fg
130109
```
131-
132110
This brings the background Gunicorn process to the foreground. Then press `Ctrl+C` to stop it.
133111

134112
## Interpret your benchmark results
135113

136-
The ApacheBench output provides key performance metrics that help you evaluate your Django application's capabilities on Arm. Here's what each metric tells you:
114+
The ApacheBench output provides key performance metrics that help you evaluate your Django application's capabilities on Google Axion (Arm64) GKE. Here's what each metric tells you:
137115
### Request handling metrics
138-
- Concurrency Level: number of simultaneous requests the benchmark sent (10 in this example)
139-
- Complete Requests: total successful requests processed (1000 in this test)
140-
- Failed Requests: number of errors or timeouts (0 indicates stable performance)
116+
- Concurrency Level: number of simultaneous requests the benchmark sent (100 in this test)
117+
- Complete Requests: total successful requests processed (5000 in this test)
118+
- Failed Requests: number of errors or timeouts (0, indicating stable production-grade performance)
141119

142120
### Performance metrics
143-
- Requests per Second: how many requests your server handles per second - higher values indicate better throughput
144-
- Time per Request (mean): average time to complete a single request - lower values mean faster responses
145-
- Time per Request (across concurrent): average latency when factoring in concurrent processing, this shows how well your app handles parallel requests
121+
- Requests per Second: how many requests your server handles per second higher values indicate better throughput (14,001.88 req/sec)
122+
- Time per Request (mean): average time to complete a single request (7.142 ms)
123+
- Time per Request (across concurrent): average latency when factoring in concurrent processing (0.071 ms), showing excellent parallel execution on Axion Arm cores
146124

147125
### Data transfer metrics
148-
- Total Transferred: all data sent and received, including HTTP headers
149-
- HTML Transferred: actual response content size
150-
- Transfer Rate: network throughput in KB/sec—indicates data handling efficiency
126+
- Total Transferred: all data sent and received, including HTTP headers (1,650,000 bytes)
127+
- HTML Transferred: actual response payload size (75,000 bytes)
128+
- Transfer Rate: network throughput in KB/sec (4512.32 KB/sec), indicating efficient networking through GKE LoadBalancer
129+
151130
### Timing breakdown
152-
- Time Taken for Tests: total benchmark duration
131+
- Time Taken for Tests: total benchmark duration (0.357 seconds)
153132
- Connection Times: shows minimum, mean, median, and maximum times for connecting, processing, and waiting
154133

155-
These metrics provide a performance baseline for your Django application on Arm. You can use them to compare different configurations, identify bottlenecks, or validate optimizations.
134+
These metrics establish a real production-grade performance baseline for your Django REST API running on GKE Axion (Arm64) with Gunicorn, Cloud SQL, and Redis.
156135

157136
## Benchmark summary
158137

159-
The table below summarizes the key performance indicators from the benchmark test. These results demonstrate the capabilities of your Django application running on a Google Cloud C4A Arm-based VM with Gunicorn.
138+
The table below summarizes the key performance indicators from your real benchmark run on the Axion Arm64 GKE cluster.
160139

161-
Results from the earlier run on the `c4a-standard-4` (4 vCPU, 16 GB memory) Arm64 VM in GCP (SUSE):
140+
Results from the run on the `Axion (C4A) Arm64 GKE nodes`:
162141

163142
| **Parameter** | **Description** | **Value** |
164-
|----------------|------------------|-----------|
143+
|--------------|------------------|-----------|
165144
| **Server Software** | Web server used for serving Django | gunicorn |
166-
| **Server Hostname** | Host address tested | 127.0.0.1 |
167-
| **Server Port** | Port number for benchmark | 8000 |
168-
| **Document Path** | Endpoint used for testing | / |
169-
| **Document Length** | Size of each response | 41 bytes |
170-
| **Concurrency Level** | Number of concurrent requests | 10 |
171-
| **Time Taken for Tests** | Total time to complete all requests | 0.104 seconds |
172-
| **Complete Requests** | Total number of successful requests | 1000 |
145+
| **Server Hostname** | External LoadBalancer IP | 34.132.110.81 |
146+
| **Server Port** | Port number for benchmark | 80 |
147+
| **Document Path** | Endpoint used for testing | /healthz/ |
148+
| **Document Length** | Size of each response | 15 bytes |
149+
| **Concurrency Level** | Number of concurrent requests | 100 |
150+
| **Time Taken for Tests** | Total time to complete all requests | 0.357 seconds |
151+
| **Complete Requests** | Total number of successful requests | 5000 |
173152
| **Failed Requests** | Number of failed requests | 0 |
174-
| **Total Transferred** | Total bytes transferred (including headers) | 280000 bytes |
175-
| **HTML Transferred** | Total HTML body bytes transferred | 41000 bytes |
176-
| **Requests per Second (mean)** | Throughput — higher is better | **9651.21 req/sec** |
177-
| **Time per Request (mean)** | Average time for each request | **1.036 ms** |
178-
| **Time per Request (across all concurrent requests)** | Average latency considering concurrency | **0.104 ms** |
179-
| **Transfer Rate** | Network throughput rate | **2639.00 KB/sec** |
153+
| **Total Transferred** | Total bytes transferred (including headers) | 1,650,000 bytes |
154+
| **HTML Transferred** | Total response body bytes | 75,000 bytes |
155+
| **Requests per Second (mean)** | Throughput — higher is better | **14,001.88 req/sec** |
156+
| **Time per Request (mean)** | Average time for each request | **7.142 ms** |
157+
| **Time per Request (across all concurrent requests)** | Average latency considering concurrency | **0.071 ms** |
158+
| **Transfer Rate** | Network throughput rate | **4512.32 KB/sec** |
159+
| **p50 (Median Latency)** | 50% of requests completed within | **6 ms** |
160+
| **p90 Latency** | 90% of requests completed within | **11 ms** |
161+
| **p95 Latency** | 95% of requests completed within | **11 ms** |
162+
| **p99 Latency** | 99% of requests completed within | **28 ms** |
163+
| **Max Latency** | Longest request observed | **34 ms** |
180164

181165
## Key performance insights
182166

183-
The benchmark results reveal several important characteristics of running Django on Arm-based infrastructure:
167+
The benchmark results demonstrate the strength of running Django on Google Axion (Arm64) GKE:
184168

185-
- Exceptional Throughput: the Arm64 VM efficiently handled nearly 10K requests per second, showcasing excellent concurrency handling.
186-
- Low Latency: average response time stayed around 1 ms, indicating rapid request processing even under load.
187-
- High Efficiency: zero failed requests demonstrate stable and reliable performance under benchmark conditions.
188-
- Optimized Networking: strong data transfer rate highlights Arm64's efficient network I/O capabilities.
189-
- Ideal for Scalable Apps: the consistent and predictable response times make Arm64 VMs well-suited for high-performance web workloads.
169+
- Extreme Throughput: The cluster sustained 14,000+ requests per second through a public LoadBalancer → GKE → Gunicorn → Django → Cloud SQL → Redis stack.
170+
- Ultra-Low p95 Latency: Even at 100 concurrent users, 95% of all requests completed within 11 ms, proving excellent tail-latency control.
171+
- Production Stability: Zero failed requests confirms the platform is resilient under heavy parallel load.
172+
- Efficient Networking: Over 4.4 MB/sec of data transfer through the GKE LoadBalancer shows Arm-based networking is highly optimized.
173+
- Cloud-native Scalability: These results validate that Axion Arm64 nodes are well-suited for high-performance, horizontally scalable REST APIs in production.

0 commit comments

Comments
 (0)