Django 優化雜談
Apr 21 2017總結下最近看過的一些文章,而後想到的一些優化點,整理一下.html
數據庫鏈接池
Django 默認DB配置提供了選項CONN_MAX_AGE
用於配置在同一個thread/greenlet裏面DB connection的最大存活時間,便於鏈接的複用,在實踐中發現若是使用gunicorn+gevent的方式來啓動WSGI服務,因爲gunicorn會建立一個很大的gevent pool,致使數據庫鏈接數會暴漲.因此這個選項被放棄了,另外的方式是使用connection pool.mysql
instagram 使用 PostGreSQL 而且使用 Pgbouncer 這個中間件來管理鏈接池,MySQL也有Proxy這種中間件可是比較重,因此考慮在django mysql backend的基礎上本身實現一個鏈接池.git
https://gist.github.com/zhu327/94c22c7fa9c92cc38e998eab41e77c38github
主要參考了Connector/Python的pool實現.redis
數據庫鏈接池也不是」銀彈」,在應用層作數據庫鏈接池也不值得推薦,隨着業務的擴展,使用一主多備搭建集羣,經過讀寫分類中間件來作鏈接池管理,推薦ProxySQL.sql
緩存一切
https://mozillazg.github.io/2015/09/high-performance-django-note-1.html數據庫
從服務器的角度來看,咱們能夠用Nginx cache/Varnish來緩存響應.這裏咱們只討論django cache framework.django
咱們的系統中使用redis做爲緩存服務器,使用redis-py與django-redis做爲cache backend.json
redis-py是純python實現的,查看了文檔後發現它也支持使用一個C客戶端的python綁定,只須要安裝hiredis-py便可使用C解析器提高redis性能.
redis-py是自帶connection pool支持的,默認使用redis.connection.ConnectionPool
,鏈接數較多的狀況下可能致使鏈接不夠用拋出異常,能夠考慮用redis.connection.BlockingConnectionPool
替換,無鏈接可用時阻塞.
Session
Django 默認的 Session Engine 用的是數據庫,由於Session中間件的緣故,每一個請求進來都會首先訪問Session表.咱們能夠用緩存來替代這個數據庫訪問的過程,推薦配置SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'
即用了緩存,又保存到db保證數據不丟失.
Django 的 session 表在一段時間之後會數據會變得很大,須要定時執行python manage.py clearsessions
來清理過時session.
緩存Model
awesome-django有一些用戶緩存的工具,翻過一些文檔後決定引入django-cache-machine
- 訪問頻繁讀多寫少的Model要緩存
- 寫多讀少的Model酌情緩存(寫的時候更新緩存開銷大)
日誌
Python的日誌是同步的,因此若是直接把日誌寫入文件,也會有文件系統I/O的開銷,更快的方式是把日誌記錄到sys.stderr
或sys.stdout
,而後用gunicorn把標準輸出的日誌重定向到文件.
# 日誌配置 import logging, logging.config import sys LOGGING = { 'version': 1, 'handlers': { 'console': { 'class': 'logging.StreamHandler', 'stream': sys.stdout, } }, 'root': { 'handlers': ['console'], 'level': 'INFO' } }
gunicorn選項:
http://docs.gunicorn.org/en/stable/settings.html#capture-output
Celery
http://docs.jinkan.org/docs/celery/userguide/optimizing.html https://blog.balthazar-rouberol.com/celery-best-practices http://orangleliu.info/2014/08/09/celery-best-practice/
安裝 librabbitmq 提高amqp訪問速度,路由長任務與短任務到不一樣的Queue,並配置不一樣的預取策略.使用msgpack來序列化消息,性能優於json.
gevent 與 MySQLdb
由於redis最夠快,因此在gunicorn+gevent的服務器下使用redis C客戶端綁定也沒什麼問題,可是MySQL就不同了,爲了讓MySQLdb也能在gevent/greenlet下切換引入Douban的greenify庫.