引言
手頭上的項目有一些采用django框架編寫, 如果說并發(fā)量比較小的時候簡單的runserver是可以應(yīng)對的.
那么當(dāng)并發(fā)達(dá)到一兩千的時候臊恋,該怎么提高django的并發(fā)能力呢谚殊?
Overview
- 環(huán)境說明:
- python: 3.5
- django: 1.8.2
- gunicorn: 19.7.1
- 系統(tǒng):
- 服務(wù)器: centos 4核
- 壓測機(jī)器: centos 4核
- 壓測環(huán)境
- siege/ysab
- 4核centos測試機(jī)
- 為什么用django
- 開發(fā)效率高
- 好上手
- 關(guān)于gunicorn
- Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX.It's a pre-fork worker model. The Gunicorn server is broadly compatible with various web frameworks, simply implemented, light on server resources, and fairly speedy.(這是官方給出的回答)
壓測方式及命令
-
壓測方式:
-
壓測命令:
- siege: siege -c255 -t200S -v -b 'http://B_ip:8080/test POST appid=111'
- ysab: ysab -n 900 -m POST -u http://B_ip:8080/test -d '{"appid": "111", "other": "other"}'
- 備注: 歡迎使用ysab, ysab文檔
本次實驗業(yè)務(wù)場景
代碼展示
settings部分
# 這里我們用mysql,其他配置都是默認(rèn)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ce',
'USER': 'root',
'PASSWORD': '',
'HOST': '192.168.96.95',
'PORT': '3306',
# 'CONN_MAX_AGE': 600,
}
}
models部分
class Test(models.Model):
url = models.CharField(max_length=228, blank=True, null=True)
img_url = models.CharField(max_length=228, blank=True, null=True)
title = models.CharField(max_length=228, blank=True, null=True)
content = models.CharField(max_length=228, blank=True, null=True)
class Meta:
db_table = 'test'
verbose_name = "test表"
def __unicode__(self):
return self.id
views部分
class Test(APIView):
def post(self, requsts):
Test.objects.create(
**{'url': str(1000000 * time.time())})
return Response({"status": 200})
開始壓測
數(shù)據(jù)說明
目前數(shù)據(jù)庫test表的數(shù)據(jù)量是, 其中id是自增主鍵
MySQL [ce]> select id from test order by id desc limit 2;
+--------+
| id |
+--------+
| 627775 |
| 627774 |
+--------+
runserver 方式壓測結(jié)果
Lifting the server siege... done.
Transactions: 24041 hits
Availability: 99.93 %
Elapsed time: 99.60 secs
Data transferred: 0.32 MB
Response time: 1.03 secs
Transaction rate: 241.38 trans/sec # 并發(fā)量只有241
Throughput: 0.00 MB/sec
Concurrency: 248.94
Successful transactions: 24041
Failed transactions: 16
Longest transaction: 32.55
Shortest transaction: 0.05
gunicorn + gevent (4個worker)
Lifting the server siege... done.
Transactions: 23056 hits
Availability: 100.00 %
Elapsed time: 99.49 secs
Data transferred: 0.31 MB
Response time: 1.09 secs
Transaction rate: 231.74 trans/sec # 并發(fā)量只有231
Throughput: 0.00 MB/sec
Concurrency: 252.95
Successful transactions: 23056
Failed transactions: 0
Longest transaction: 8.21
Shortest transaction: 0.01
gunicorn + gthread (4個worker, --threads=50)
啟動方式
[官方有相應(yīng)說明]((http://docs.gunicorn.org/en/latest/settings.html)
gunicorn --env DJANGO_SETTINGS_MODULE=ce.settings ce.wsgi:application -w 4 -b 0.0.0.0:8080 -k gthread --threads 40 --max-requests 4096 --max-requests-jitter 512
壓測結(jié)果
啟動方式:
done.
siege aborted due to excessive socket failure; you
can change the failure threshold in $HOME/.siegerc
Transactions: 28231 hits
Availability: 95.67 %
Elapsed time: 30.71 secs
Data transferred: 0.41 MB
Response time: 0.27 secs
Transaction rate: 919.28 trans/sec # 提高了不少吧央碟,能不能在提高?
Throughput: 0.01 MB/sec
Concurrency: 251.06
Successful transactions: 28231
Failed transactions: 1278 # 但是失敗的有些多
Longest transaction: 8.06
Shortest transaction: 0.01
gunicorn + gthread + CONN_MAX_AGE(4個worker, --threads=50)
CONN_MAX_AGE: 復(fù)用數(shù)據(jù)庫鏈接
Lifting the server siege... done.
Transactions: 110289 hits
Availability: 99.62 %
Elapsed time: 99.65 secs
Data transferred: 1.47 MB
Response time: 0.23 secs
Transaction rate: 1106.76 trans/sec # 這次又提升了不少啊
Throughput: 0.01 MB/sec
Concurrency: 253.84
Successful transactions: 110289
Failed transactions: 422
Longest transaction: 3.85
Shortest transaction: 0.01
能不能gunicorn+gevent+CONN_MAX_AGE(4個worker)
這里我不建議使用群井,這樣的話你的數(shù)據(jù)庫連接數(shù)會飚的很高传趾,服務(wù)會掛的很慘, 畢竟數(shù)據(jù)庫是不會允許
無休止的建立連接的晤郑。前邊的提高手段無非用的多線程,如果一定要用協(xié)程(gevent)的方式呢袍辞,能不
能解決數(shù)據(jù)庫連接數(shù)過高的問題鞋仍,而且還能有不錯的性能呢?可以看一下這篇文章:
gunicorn+gevent+django數(shù)據(jù)庫連接池
如何再次增加并發(fā)量
采用nginx做負(fù)載
[圖片上傳失敗...(image-55dc84-1555064167047)]
去掉自增主鍵
原因很簡單,因為自增主鍵的存在寫庫存在搶鎖, 可以利用全局id生成器提前生成id直接寫入數(shù)據(jù)庫
換成異步任務(wù)去寫庫
如果數(shù)據(jù)只是存在mysql中做備份搅吁,建議使用異步的方式寫入庫威创,先把數(shù)據(jù)寫到緩存下發(fā)給用戶落午,之后在
利用后臺異步任務(wù)一點點的寫入,例如聊天系統(tǒng)可以這樣干
換成更高效的框架或者語言
可以試試tornado, 如果tornado依然無法滿足肚豺,可以嘗試使用golango溃斋,畢竟golang是以高并發(fā)著稱,
而且是編譯語言,而且基于它的web框架也很容易上手吸申,性能很可觀梗劫,例如Gin
Gin
文章推薦
關(guān)于gunicorn的worker調(diào)度
gunicorn+gevent+django數(shù)據(jù)庫連接池