前言:
为了提供让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
这老外写的有点简陋,说明几乎没有,还好tornado redis session本身就是不难的东西,看看就能搞定。
单个tornado我现在已经可以顶到1500个长连接不崩溃了,如果加上ngixn做tornado的分发负载,估计连接在6k问题不大。就算是接入所有业务的邮件转发问题也不大,估计问题都在邮件网关上了。
博客地址:http://rfyiamcool.blog.51cto.com/1030776/1406378