您的位置:首页 > 数据库 > Redis

tornado使用redis来实现session分布式存储 推荐

2014-05-05 00:09 375 查看
前言:
为了提供让tornado更接近c10的能力,只能用nginx来处理tornado不太擅长的静态文件及用多app方案来提高负载能力。
我人比较的懒,把接口和平台的页面都做成一个py了,用upstream不好做负载,如果你用ip_hash,或者insert cookie的方式,虽然保证了针对后端服务器的命中,但是哥还就不想命中。
我还就想rr轮训,为啥? 因为页面上大量的耗时间的io和计算请求,这个时候我总是命中调度到一台服务器,那我就会一直的等待,后面还有一堆的任务也都在同步堵塞着。。。太痛快啦,这个时候就需要rr轮训,session如何的一致性,这个时候就需要一个快速的存储来保证session cookie的存储。

以前更多是用tornado memcached来存储session或者cookie,因为报警平台中已经在用redis、mongodb这些nosql数据库,没必要再配置memcached了。 这次用我钟爱的redis了。

这里导入了相关的类和库,login_required是装饰器,专门来判断用户登录了没有,没有的话把访问扔给login.html页面。

#xiaorui.cc
from base import BaseHandler
from tornado.web import HTTPError
def login_required(f):
def _wrapper(self,*args, **kwargs):
print self.get_current_user()
logged = self.get_current_user()
if logged == None:
self.write('no login')
self.finish()
else:
ret = f(self,*args, **kwargs)
return _wrapper
class Application(tornado.web.Application):
def __init__(self):
settings = dict(
cookie_secret = "e446976943b4e8442f099fed1f3fea28462d5832f483a0ed9a3d5d3859f==78d",
session_secret = "3cdcb1f00803b6e78ab50b466a40b9977db396840c28307f428b25e2277f1bcc",
session_timeout = 60,
store_options = {
'redis_host': 'localhost',
'redis_port': 6379,
'redis_pass': '',
},
)
handlers = [
(r"/", MainHandler),
(r"", MainHandler),
(r"/login", LoginHandler)
]
tornado.web.Application.__init__(self, handlers, **settings)
self.session_manager = session.SessionManager(settings["session_secret"], settings["store_options"], settings["session_timeout"])


关联的两个类:

class MainHandler(BaseHandler):
@login_required
def get(self):
username = self.get_current_user()
print 'start..'
print username
print self.session['nima']
if username==None:
self.write('nima')
else:
self.write("What's up, " + username + "?")
class LoginHandler(BaseHandler):
def get(self):
self.session["user_name"] = self.get_argument("name")
self.session["nima"] = 'xiaorui.cc'
self.session.save()
self.write('你的session已经欧了')


处理session的文件 !

#/usr/bin/python
# coding: utf-8
import uuid
import hmac
import ujson
import hashlib
import redis
class SessionData(dict):
def __init__(self, session_id, hmac_key):
self.session_id = session_id
self.hmac_key = hmac_key
#   @property
#   def sid(self):
#       return self.session_id
#   @x.setter
#   def sid(self, value):
#       self.session_id = value
class Session(SessionData):
def __init__(self, session_manager, request_handler):
self.session_manager = session_manager
self.request_handler = request_handler
try:
current_session = session_manager.get(request_handler)
except InvalidSessionException:
current_session = session_manager.get()
for key, data in current_session.iteritems():
self[key] = data
self.session_id = current_session.session_id
self.hmac_key = current_session.hmac_key

def save(self):
self.session_manager.set(self.request_handler, self)
class SessionManager(object):
def __init__(self, secret, store_options, session_timeout):
self.secret = secret
self.session_timeout = session_timeout
try:
if store_options['redis_pass']:
self.redis = redis.StrictRedis(host=store_options['redis_host'], port=store_options['redis_port'], password=store_options['redis_pass'])
else:
self.redis = redis.StrictRedis(host=store_options['redis_host'], port=store_options['redis_port'])
except Exception as e:
print e

def _fetch(self, session_id):
try:
session_data = raw_data = self.redis.get(session_id)
if raw_data != None:
self.redis.setex(session_id, self.session_timeout, raw_data)
session_data = ujson.loads(raw_data)
if type(session_data) == type({}):
return session_data
else:
return {}
except IOError:
return {}
def get(self, request_handler = None):
if (request_handler == None):
session_id = None
hmac_key = None
else:
session_id = request_handler.get_secure_cookie("session_id")
hmac_key = request_handler.get_secure_cookie("verification")
if session_id == None:
session_exists = False
session_id = self._generate_id()
hmac_key = self._generate_hmac(session_id)
else:
session_exists = True
check_hmac = self._generate_hmac(session_id)
if hmac_key != check_hmac:
raise InvalidSessionException()
session = SessionData(session_id, hmac_key)
if session_exists:
session_data = self._fetch(session_id)
for key, data in session_data.iteritems():
session[key] = data
return session

def set(self, request_handler, session):
request_handler.set_secure_cookie("session_id", session.session_id)
request_handler.set_secure_cookie("verification", session.hmac_key)
session_data = ujson.dumps(dict(session.items()))
self.redis.setex(session.session_id, self.session_timeout, session_data)
def _generate_id(self):
new_id = hashlib.sha256(self.secret + str(uuid.uuid4()))
return new_id.hexdigest()
def _generate_hmac(self, session_id):
return hmac.new(session_id, self.secret, hashlib.sha256).hexdigest()
class InvalidSessionException(Exception):
pass


tornado每个控制器相关的class ~

import tornado.web
import sys
import session
class BaseHandler(tornado.web.RequestHandler):
def __init__(self, *argc, **argkw):
super(BaseHandler, self).__init__(*argc, **argkw)
self.session = session.Session(self.application.session_manager, self)
def get_current_user(self):
return self.session.get("user_name")


对于登录注册session:

self.session["user_name"] = self.get_argument("name")
self.session["nima"] = 'xiaorui.cc'
self.session.save()
对于退出登录:

self.session["nima"] =None
self.session.save()


其实就改成None就行了,匹配都在装饰器那边搞好了。

原文:http://rfyiamcool.blog.51cto.com/1030776/1406378
偶了,这就可以了。用之前要配置下相关的组件!
pip install ujson redis
pip install tornado

session.py 代码来自:
git clone https://github.com/zs1621/tornado-redis-session[/code] 
这老外写的有点简陋,说明几乎没有,还好tornado redis session本身就是不难的东西,看看就能搞定。

单个tornado我现在已经可以顶到1500个长连接不崩溃了,如果加上ngixn做tornado的分发负载,估计连接在6k问题不大。就算是接入所有业务的邮件转发问题也不大,估计问题都在邮件网关上了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息