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库.