用gunicorn實現Django高併發的解決方案

2021-10-01 17:45:58 字數 3691 閱讀 9467

django提供了自帶的runserver命令啟動服務,這種方式一般用於開發環境以便於除錯程式,併發量比較小的時候也是可以應對的,但是併發量超過這種方式的承載能力時,就需要使用gunicorn啟動django的服務來提高併發能力了。

pip3 install django==2.0.6 gevent==1.4.0 gunicorn==19.7.1
import os

import multiprocessing

reload = false # **更新時不重啟專案

daemon = false # 不守護gunicorn程序

backlog = 2048 # 伺服器中排隊等待的最大連線數,建議值64-2048,超過2048時client連線會得到乙個error。

workers = multiprocessing.cpu_count() * 2 + 1 # 用於處理工作的程序數,這裡使用了文件建議的值

keyfile = '.../server.key' # ssl證書金鑰檔案路徑

certfile = '.../server.crt' # ssl證書檔案路徑

worker_class = 'gthread' # worker程序的工作方式,有sync、eventlet、gevent、tornado、gthread, 預設值sync, django使用gevent容易造成阻塞, 使用gthread的方式好一些。

threads = int(480 / workers) # 資料庫連線數=workers*threads*2

timeout = 60 # 訪問超時時間

graceful_timeout = 60 # 接收到restart訊號後,worker可以在graceful_timeout時間內,繼續處理完當前requests。

keepalive = 30 # server端保持連線時間。

# max_requests = 1000 # 有記憶體洩露時使用此選項重啟work

# max_requests_jitter = 50 # 重啟work的抖動幅度,一般設定為max_requests的5%

pythonpath = '/usr/bin/python3 -u' # 逗號分隔的python執行路徑,可以加上引數,這裡只有乙個路徑,-u表示使用無緩衝的二進位制終端輸出流

access_log_format = '%(t)s %(h)s "%(r)s" %(s)s %(b)s "%(f)s" "%(l)s"' # 日誌檔案格式

accesslog = '-' # 日誌檔案路徑,'-'表示輸出到終端

errorlog = '-' # 錯誤日誌檔案路徑,'-'表示輸出到終端

bind = '0:1999' # 指定監聽的位址和埠,這裡使用nginx**了,所以監聽特殊埠

project_name = 'mysite'

proc_name = 'gunicorn_%s' % project_name # 設定程序名稱

os.environ.setdefault('django_settings_module', '%s.settings' % project_name) # 設定環境變數指定django執行使用的配置檔案

os.environ.setdefault('werkzeug_run_main', 'true') # 設定環境變數告訴wekzeug這個是用於reload的主程序

threads值的計算比較重要,同乙個程序中的執行緒共享乙個資料庫連線池,乙個執行緒需要兩個與資料庫的連線,否則會報錯「mysql error:2014 commands out of sync; you can't run this command now」。

用max_connections表示資料庫支援的最大連線數,用workers表示程序數,threads表示執行緒數,每個程序中的執行緒數計算如下:

threads = max_connections / workers / 2

如果max_connections等於1000,我們預留40個資料庫連線作其他用途:

threads = int(int((max_connections - 40) / 2) / workers)

化間後得到上面的例子:

threads = int(480 / workers)

from myproject.gunicorn_config import threads

...,

'gunicorn',

]databases =

}}

併發量高了,資料庫連線量會過大,報錯「too many connections」,參考我的這篇文章解決。

其中pool_size的值設定為gunicorn_config.py中threads值的兩倍,因為每個執行緒需要建立兩個資料庫連線,否則會報錯「mysql error:2014 commands out of sync; you can't run this command now」。

也就是說,最終併發量上限為資料庫max_connections配置的數值的一半。

使用指令碼啟動的原因是supervisor殺不掉服務的子程序,需要用指令碼殺一下再啟動新的服務。

#!/bin/sh

pname=$1

port=$2

if [ -z "$" ]

then

pname="mysite"

fiif [ -z "$" ]

then

if [ "$pname"x = "mysite"x ]

then

port="1999"

else

echo "error project name \"$pname\""

exit 0

fifips aux | grep $/gunicorn_config.py | grep $ | awk '' | xargs kill -9 > /dev/null 2>&1 # 根據程序名和埠號過濾出程序id,殺死已存在的服務程序

# unbuffer表示使用無緩衝的二進位制輸出流,-p表示unbuffer可以從管道命令"|"的輸出中讀取內容(相容supervisor)

# $/gunicorn_config.py是第三步編寫的配置檔案的位置

# 0:$是指定監聽的位址和埠,這個會覆蓋gunicorn_config.py中的配置,加上這個便於過濾程序id

[program:mysite]

environment=user=root,pythonpath=/usr/bin/

directory=/var/www/mysite/

command=bash start.sh mysite

autostart=true

autorestart=true

stopasgroup=true

stderr_logfile=/var/log/supervisor/mysite_error.log

stdout_logfile=/var/log/supervisor/mysite_out.log

user=root

redirect_stderr=false

startretries=20

stdout_logfile_maxbytes=20mb

stdout_logfile_backups=20

用棧實現佇列 用佇列實現棧

棧的特點 filo firstinlastout 僅能從棧頂插入,刪除元素。最基本的介面包括push 從棧頂壓入元素 pop 從棧頂彈出元素 佇列的特點 fifo firstinfirstout 僅能從隊頭刪除元素,從隊尾插入元素。最基本的介面包括enque 從隊尾插入元素 deque 從隊頭刪除元...

用棧實現佇列,用佇列實現棧。好玩!!!

因為在資料結構中,棧和佇列長得實在是太像了,將他們拿來比較是不可避免的,棧 後進先出,而佇列 先進先出。同樣是只能在一端進行操作,那麼問題來了,能相互實現?能不能得好好分析一下嘛,如果是用兩個棧來實現佇列,好像這操作可以哦。一下,你就明白!顯然用兩個棧可以實現佇列的功能,就是借助另乙個棧來中轉一下,...

232 用棧實現佇列 225 用佇列實現棧

用棧實現佇列 佇列是先進先出,實現佇列的最直觀的方法是用鍊錶。但本題是要求使用棧。本題兩個stack相互倒,負負得正 class myqueue def init self self.instack self.outstack defpush self,x def pop self if len s...