2025 OEM 網站開發筆記 [最後一篇] - 從 Django 開發伺服器轉成 uWSGI (Production Deployment)正式運營應用伺服器

用 uWSGI 取代 python manage.py runserver

Posted by Young on 2025-05-06
Estimated Reading Time 5 Minutes
Words 1.4k In Total

前言

本篇著重在從開發環境切換至 uWSGI 正式環境需改動的地方,而不是從0開始,所以會更精簡,詳細從開始部署以及更詳細的參數解釋可參考

透過 Nginx 部署 Django 至私有主機

Django 開發伺服器轉向 uWSGI 的優點

Django 的 python manage.py runserver 是一個開發伺服器,而 uWSGI 是生產級別(Production Deployment)的應用伺服器

使用 uWSGI 而不是開發伺服器的原因:

  1. 性能優化:uWSGI 可生成多個工作進程來將傳入的請求並行化到多個 CPU 核心,才能處理高流量網站。
  2. 安全性更高:Django 開發伺服器未經過安全審核或性能測試,不適合在生產環境中使用
  3. 處理並行請求:uWSGI 運行在客戶端-伺服器模型上,網絡伺服器(如 nginx、Apache)與 django-uwsgi "工作進程"通信以提供動態內容,能更處理多個同時請求。
  4. 可配置性:uWSGI 支持多種配置選項,包括主從模式、進程數量控制、優雅重啟、資源限制等 Django 專案,適合不同的部署需求。
  5. 資源管理:使用 uWSGI 可以控制內存洩漏、物理內存問題和響應時間問題,有效管理系統資源。

簡而言之,開發伺服器是單線程的,而 uWSGI 可以使用多進程多線程,處理高流量或同時多個請求時性能更好

更改網頁伺服器 Nginx 的配置

編輯 /etc/nginx/sites-available 底下的對應 kostec.conf 檔案,在 /api//admin/ 路徑下需要進行相同的變更

將開發環境的配置註釋掉或移除,改成 uWSGI 的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
location /api/ {
# 註釋或移除開發環境配置
# proxy_pass http://127.0.0.1:8000;
# proxy_set_header Host $host;
# ...其他 proxy 配置...

# 取消註釋 uWSGI 配置
include /home/httpd/kostec/uwsgi_params;
uwsgi_pass unix:/home/httpd/kostec/kostec.sock;
uwsgi_read_timeout 30;
uwsgi_send_timeout 30;
uwsgi_param SCRIPT_NAME "";
uwsgi_modifier1 30;
}

創建 uwsgi_params 檔案

在專案目錄下 /home/httpd/kostec/ 確保有 uwsgi_params 檔案以及內容包含:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;

uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;

uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;

更新 uWSGI 配置檔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[uwsgi]
# Django 相關配置
chdir = /home/httpd/kostec/backend
module = kostec.wsgi:application
env = DJANGO_SETTINGS_MODULE=kostec.settings

# 使用者和群組權限
uid = www-data
gid = www-data

# 連接選項
socket = /home/httpd/kostec/kostec.sock
chmod-socket = 666
vacuum = true

# 進程選項
master = true
processes = 4
threads = 2

# 效能優化
harakiri = 30
max-requests = 5000
buffer-size = 32768

# 日誌
logto = /var/log/uwsgi/kostec.log
log-reopen = true
log-slow = 1000

# 自動重啟
touch-reload = /home/httpd/kostec/backend/kostec/wsgi.py

# 啟動選項
daemonize = /var/log/uwsgi/kostec.log
pidfile = /tmp/kostec-master.pid

這邊我自己會把「使用者和群組權限」及 「日誌」的部分刪除,因為我習慣直接在終端機上查看錯誤

因此我的最終版本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[uwsgi]
# Django 相關配置
chdir = /home/httpd/kostec/backend
# 確保這裡指向 Django 的 wsgi.py
module = backend.wsgi:application
virtualenv = /home/httpd/kostec/venv
env = DJANGO_SETTINGS_MODULE=backend.settings

# 連接配置
socket = /home/httpd/kostec/kostec.sock
chmod-socket = 666
vacuum = true
die-on-term = true
enable-threads = true

# 進程選項
master = true
processes = 5
threads = 2

# 效能優化
harakiri = 30
max-requests = 5000
buffer-size = 32768

# 自動重啟
touch-reload = /home/httpd/kostec/backend/backend/wsgi.py

# 日誌配置,uWSGI 將自動在背景運行,同時也會將輸出日誌寫入指定文件,並將進程 ID 保存到 pidfile 中,便於之後管理
daemonize = /home/httpd/kostec/uwsgi.log
pidfile = /home/httpd/kostec/uwsgi.pid

設置 systemd 服務管理 uWSGI

/etc/systemd/system 目錄下創建 kostec-uwsgi.service,並添加以下內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=uWSGI instance to serve Kostec
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/home/httpd/kostec/backend
ExecStart=/usr/local/bin/uwsgi --ini /home/httpd/kostec/kostec_uwsgi.ini
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

然後試試啟用並啟動服務:

1
2
sudo systemctl enable kostec-uwsgi
sudo systemctl start kostec-uwsgi

成功

若一切順利,執行 sudo systemctl start kostec-uwsgi 應會看到以下的輸出,表示 uWSGI 服務已經成功啟動並運行中

service_active

然後網站也能正常接收到後端的請求,正常運行了。

常見錯誤 - 模組名稱導入錯誤

sudo systemctl start kostec-uwsgi 啟動 uWSGI 服務時,若出現以下錯誤:

no_module_error

一般就是 uwsgi.ini 檔案中的 moduleenv 參數設置錯誤,要確保它指向正確的 Django 應用程式模組

因為我的 Django 專案項目的主文件夾名稱是 backend,所以應該改成:

wsgi_dir

1
2
3
4
# 原本會導致錯的情況:
# env = DJANGO_SETTINGS_MODULE=kostec.settings

env = DJANGO_SETTINGS_MODULE=backend.settings

預部署檢查清單

從開發環境轉向生產環境部署完成後,可以執行 Django 的部署檢查,他會印出一些建議的配置和注意事項,確保 Django 在正式運營環境中正常運作

1
python manage.py check --deploy

手動創建存放錯誤訊息的日誌目錄和檔案(非必要)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 創建日誌目錄
sudo mkdir -p /var/log/uwsgi

# 創建日誌檔案
sudo touch /var/log/uwsgi/kostec.log

# 假設 uWSGI 以 www-data 用戶運行
sudo chown -R www-data:www-data /var/log/uwsgi
sudo chmod 755 /var/log/uwsgi
sudo chmod 644 /var/log/uwsgi/kostec.log

# 設置目錄和檔案的擁有者和權限,確保 uWSGI 進程可以寫入
sudo chown -R $(whoami):$(whoami) /var/log/uwsgi

停止 uWSGI 服務

systemctl 停止 uWSGI 服務時可能很慢,這是因為 systemd 預設會嘗試優雅地關閉服務,給程序時間完成當前請求並清理資源。以下是一些更快速停止 uWSGI 的方法

1
sudo systemctl stop kostec-uwsgi

暴力停止 uWSGI 服務,直接使用 Linux SIGTERM 信號

1
sudo pkill -f uwsgi

若您覺得這篇文章對您有幫助,歡迎分享出去讓更多人看到⊂◉‿◉つ~


留言版