Django Redisession
A Redis-based Django session engine for django.contrib.sessions.
This engine supports storing session data as a Redis String, or distributing sessions to Redis hashs for more efficient usage of Redis storage(without much extra CPU cost on Redis server. Refs http://antirez.com/post/redis-weekly-update-7.html and http://redis.io/topics/memory-optimization , you may need to tweak Redis conf for actual usage. The tech is referred as hash mode below).
Installation
- Require Django version >= 1.3
-
pip install django-redisession
or in sourcepython setup.py install
. - Add redisession to INSTALLED_APPS in your current settings file.
- Set
SESSION_ENGINE='redisession.backend'
in the settings file.
Configuration
- Configuration options to the django-redisession can be placed in dict REDIS_SESSION_CONFIG:
-
- SERVER -- If set to a dict then the value will be used as arguments for redis.Redis() to make a redis connection instance. If set to a string then the django-redisession will get redisession.helper.get_redis to lookup the value in REDIS_CONFIG for existing connection instance, see below.
- USE_HASH -- If set to True (hash mode), the django-redisession will store sessions as items of Redis Hashes. HASH_KEY_GENERATOR will be used to generate corresponding Redis keys. If set to False, the data of a session will be stored as Redis String value of the Redis key which is generated by KEY_GENERATOR. session keys generated by md5 is not as well distribudated as those by sha1, but still acceptable.
- KEY_GENERATOR -- The callable to generate Redis key, or Redis Hash field name when in hash mode, for a session. The callable accepts session_key as the only parameter. The default generates the binary string, 16 bytes for md5, from session_key which is normally a hex string. Note if you are customizing it, open LOG_KEY_ERROR and run test ./manage.py test redisession to "ensure" KEY_GENERATOR works with session keys. For session key contains '0-9a-z' in incoming Django 1.5, you could check comments in redisession/backend.py.
- HASH_KEY_GENERATOR -- The callable to generate Redis key for Redis Hashes, in hash mode. The default uses the first two bytes of the binary string of a session_key, and thus distributes sessions to 65536 hashes. Other dispatching logics or key prefix could be achieved by customizing this option. Note if you are customizing it, open LOG_KEY_ERROR and run test ./manage.py test redisession to "ensure" HASH_KEY_GENERATOR works with session keys. For session key contains '0-9a-z' in incoming Django 1.5, you could check comments in redisession/backend.py.
- HASH_KEYS_CHECK_FOR_EXPIRY -- The callable to generate Redis keys to check for deleting expired sessions, in hash mode. The callable accepts redis connection instance as parameter. The default applys Redis.randomkey 100 times to sample keys.
- COMPRESS_LIB -- The module name of the compress library used to compress session data, leave blank to disable compress. Defaults to 'snappy', refs snappy and python-snappy . The compress library should support compress and decompress, such as zlib, lzo, etc. A slow library may have higher compression ratio, which implies higher load on web server, but less IO on communicating w/ Redis. So decide it by your tradeoff.
- COMPRESS_MIN_LENGTH -- The minimal length of the session data to try compress. Defaults to 400.
- LOG_KEY_ERROR -- Whether log key error caused by bad key or misconfigured HASH_KEY_GENERATOR or KEY_GENERATOR. Defaults to False.
Examples:
# default: distributes sessions to 65536 Redis Hashes, # use binary string form of session_key, # applys Redis.randomkey 100 times to sample hash keys # to check for deleting expired session, # try to compress data (length >= 400) by using snappy. REDIS_SESSION_CONFIG = { 'SERVER': {}, 'USE_HASH': True, 'KEY_GENERATOR': lambda x: x.decode('hex'), 'HASH_KEY_GENERATOR': lambda x: x[:4].decode('hex'), 'HASH_KEYS_CHECK_FOR_EXPIRY': lambda r: (reduce(lambda p,y :p.randomkey(), xrange(100), r.pipeline()).execute()), 'COMPRESS_LIB': 'snappy', 'COMPRESS_MIN_LENGTH': 400, 'LOG_KEY_ERROR': False }
# use session thru Redis get/set. store session key just as it is, hex string. REDIS_SESSION_CONFIG = { 'USE_HASH': False, 'KEY_GENERATOR': lambda x: x }
# almost as above, but add key prefix 's:' for Redis keys REDIS_SESSION_CONFIG = { 'USE_HASH': False, 'KEY_GENERATOR': lambda x: 's:'+x }
# use Redis connection instance through redisession.helper.get_redis # here django-redisession will try to use Redis connection instance 'foo' REDIS_SESSION_CONFIG = { 'SERVER': 'foo' } # see following REDIS_CONFIG = { 'default': {'db':1}, 'foo': {'db':2, unix_socket_path='/tmp/bar'} }
# Here are some other possible settings of 'HASH_KEYS_CHECK_FOR_EXPIRY' # Fetching and scaning ALL keys and ALL of their fields. Use with caution. lambda r: r.keys() # Sampling 100 hash keys out of 65536 possible slots. # This is useful if the number of actually used slots is closer to 65536. lambda r: (map(lambda x:('%04x'%x).decode('hex'), random.sample(xrange(65536), 100)))
You could use redisession.helper.get_redis
to create and get global Redis connection instance by name. First, setting REDIS_CONFIG in the settings file, which is similar to DBs settings in django. For example:
REDIS_CONFIG = { # 'name': arguments passed to redis.Redis to build a connection instance, as dict items 'default': {'port':63790, 'db':1}, 'foo': {'db':2, unix_socket_path='/tmp/bar'}, 'session': {'db':3}, }
then
>>> from redisession.helper import get_redis >>> r = get_redis() # get Redis connection instance of name 'default' >>> r = get_redis('foo') # or of name 'foo' >>> r = get_redis('session') # use db 3 for sessions only >>> r.info()
Security
Isolate the Redis server of storing sessions from other usages is RECOMMENDED. You could achieve this by using a seperate db, like conf 'session' in REDIS_CONFIG above, or by specifying a unique key prefix in KEY_GENERATOR. For possible security issue, refs https://www.djangoproject.com/weblog/2011/sep/09/security-releases-issued/ and https://code.djangoproject.com/changeset/16759
Cleanup expired sessions in hash mode
run django command cleanuprs in shell or cronjob.
Test
python manager.py test redisession
. It uses your REDIS_SESSION_CONFIG settings for tests, so corresponding Redis server should be available.