聊聊Django應用的部署和效能的那些事兒

畫星星高手發表於2020-07-26

隨著工作的深入,我越來越發現Python Web開發中有很多坑,也一直在羨慕AspNetCore和Go等的可執行檔案部署和高效能,以及Spring生態的豐富,不過因為工作用了Django,生活還是要繼續的嘛,這Django好歹也是有很大份額的Web框架,也沒那麼不堪,至少開發速度上就吊打一眾框架了~

在之前的文章裡我介紹過使用Docker部署Django應用的方法,不過那種部署方式只適合上線除錯的場景,直接使用Django內建的Web伺服器提供服務,單執行緒,效能很低,真正上線服務,還是要uwsgi配合nginx部署。

理清思路

以前我寫過文章介紹了Django應用使用uwsgi+nginx在Linux伺服器上直接的部署方法,現在我們為了方便管理,使用Docker來部署Django應用。

我看到網上很多方案都是把nginx也一起用了docker,感覺有些不妥,我們伺服器上可能有很多個專案,一個專案一個nginx,多佔用的資源不說,就配置而言,也要麻煩不少。

一個裝在系統裡的nginx是完全足夠的,也方便配置,就我們團隊而言,公司的網安做得比較嚴格,對伺服器開放的埠和申請的域名有限制,沒辦法一個應用開一個埠,只能用nginx監聽一個埠並且配置反向代理來實現多個專案的服務,所以一個nginx就很方便了。

我們的思路是django和uwsgi放在docker裡,老辦法,使用docker-compose編排相關依賴的資料庫、快取、監控服務,然後使用nginx做反向代理和提供靜態檔案服務,為了靜態檔案和程式碼熱更新,還要做volume對映。

接下來一步步介紹構建一個方便的uwsgi+django映象的方法。

Dockerfile編寫

首先是我們的映象檔案,相比起之前的開發映象,多了一個uwsgi模組,其他的不變。

FROM python:3.7

# 設定 python 環境變數
ENV PYTHONUNBUFFERED 1

# 建立 code 資料夾並將其設定為工作目錄
RUN mkdir /code
WORKDIR /code

# 更新 pip
RUN pip install -i https://mirrors.aliyun.com/pypi/simple pip -U
# 設定國內源
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple

# 將 requirements.txt 複製到容器的 code 目錄
ADD requirements.txt /code/

# 安裝庫
RUN pip install -r requirements.txt

# 將當前目錄複製到容器的 code 目錄
ADD . /code

# 安裝uwsgi
RUN pip install uwsgi

uwsgi的ini配置

uwsgi的配置我選擇ini的形式,檔案內容如下:

[uwsgi]
socket = :8000

# the base directory (full path)
chdir = /code

# Django s wsgi file
module = config.wsgi

# 啟用主程式,當程式掛掉會再spawn一個(以下三個指標,實現“併發”)
master = true
# 程式個數
processes = 4
# 每個程式中的執行緒個數/workers
threads = 2
# 一個工作程式最大請求數
max-requests = 5000

vacuum = true

# pid檔案,用於指令碼啟動、停止該程式
pidfile = /code/uwsgi.pid

# 當檔案改變時,優雅的重啟uWSGI
touch-reload = /code/readme.md

注意一點,在之前的配置中,我們是用daemonize = log/uwsgi.log來配置日誌檔案路徑實現uwsgi輸出日誌的,但是如果docker這樣做的話,會導致docker-compose啟動這個容器的時候直接執行完成自動退出,所以權宜之計只能不輸出日誌檔案,輸出到控制檯,這樣保持容器不被關閉(以後有更好的方法我會更新文章進行記錄)

還有我用了touch-reload來監控檔案修改自動重啟uwsgi,這樣就可以實現程式碼的熱更新了(嚴格來說不算真的熱更新哈哈哈。但夠用了)每次更新程式碼的同時修改一下readme檔案,可以記錄一下更新內容,又自動重啟了服務,多方便~

不過這樣的熱更新會帶來短暫的 bad request ,所以儘量選擇流量少的時段進行服務更新~

目前的系統還比較簡單,所以我的方案是在測試伺服器測試沒問題就會同步程式碼到線上伺服器~ 由於前端是小程式且使用者量還不大,所以使用者基本無感知~

Docker-Compose

這個沒啥好說啦,就改了一下command而已~

version: "3"
services:
  redis:
    image: redis
    expose:
      - 6379
  web:
    restart: always # 除正常工作外,容器會在任何時候重啟,比如遭遇 bug、程式崩潰、docker 重啟等情況。
    build: .
    environment:
      - ENVIRONMENT=docker
    command: uwsgi uwsgi.ini
    volumes:
      - .:/code
    ports:
      - "19001:8000"
    depends_on:
      - redis

經過以上的步驟,一個簡單的docker-compose up命令就把我們的服務跑起來了,再在nginx裡配置一下反向代理和靜態檔案就美滋滋了,關於nginx的配置的,我打算下一篇文章再講。

最後就是關於效能了,經過以上的部署,經過測試這個系統在目前沒有任何優化的情況下可以承受最高1800 QPS,可能大佬會覺得太低了,嗯Python這效能確實…但按照目前我們的產品來說完全足夠(超出),不行就讓公司堆配置,反正是雲服務隨便擴容(公司伺服器和錢都管夠哈哈哈)以後按需優化…溜了哈哈哈

相關文章