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

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

前言:

为了提供让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页面。

  1. #xiaorui.cc   
  2. from base import BaseHandler   
  3. from tornado.web import HTTPError   
  4. def login_required(f):   
  5.     def _wrapper(self,*args, **kwargs):   
  6.         print self.get_current_user()   
  7.         logged = self.get_current_user()   
  8.         if logged == None:   
  9.             self.write('no login')   
  10.             self.finish()   
  11.         else:   
  12.             ret = f(self,*args, **kwargs)   
  13.     return _wrapper   
  14. class Application(tornado.web.Application):   
  15.     def __init__(self):   
  16.         settings = dict(   
  17.             cookie_secret = "e446976943b4e8442f099fed1f3fea28462d5832f483a0ed9a3d5d3859f==78d",   
  18.             session_secret = "3cdcb1f00803b6e78ab50b466a40b9977db396840c28307f428b25e2277f1bcc",   
  19.             session_timeout = 60,   
  20.             store_options = {   
  21.             'redis_host''localhost',   
  22.                 'redis_port': 6379,   
  23.                 'redis_pass''',   
  24.         },   
  25.         )   
  26.         handlers = [   
  27.             (r"/", MainHandler),   
  28.             (r"", MainHandler),   
  29.             (r"/login", LoginHandler)   
  30.         ]   
  31.         tornado.web.Application.__init__(self, handlers, **settings)   
  32.         self.session_manager = session.SessionManager(settings["session_secret"], settings["store_options"], settings["session_timeout"])  

关联的两个类:

  1. class MainHandler(BaseHandler):   
  2.     @login_required   
  3.     def get(self):   
  4.         username = self.get_current_user()   
  5.         print 'start..' 
  6.         print username   
  7.         print self.session['nima']   
  8.         if username==None:   
  9.             self.write('nima')   
  10.         else:   
  11.             self.write("What's up, " + username + "?")   
  12. class LoginHandler(BaseHandler):   
  13.     def get(self):   
  14.         self.session["user_name"] = self.get_argument("name")   
  15.         self.session["nima"] = 'xiaorui.cc' 
  16.         self.session.save()   
  17.         self.write('你的session已经欧了'

处理session的文件 !

  1. #/usr/bin/python   
  2. # coding: utf-8 
  3. import uuid   
  4. import hmac   
  5. import ujson   
  6. import hashlib   
  7. import redis   
  8. class SessionData(dict):   
  9.     def __init__(self, session_id, hmac_key):   
  10.         self.session_id = session_id   
  11.         self.hmac_key = hmac_key   
  12. #   @property   
  13. #   def sid(self):   
  14. #       return self.session_id   
  15. #   @x.setter   
  16. #   def sid(self, value):   
  17. #       self.session_id = value   
  18. class Session(SessionData):   
  19.     def __init__(self, session_manager, request_handler):   
  20.         self.session_manager = session_manager   
  21.         self.request_handler = request_handler   
  22.         try:   
  23.             current_session = session_manager.get(request_handler)   
  24.         except InvalidSessionException:   
  25.             current_session = session_manager.get()   
  26.         for key, data in current_session.iteritems():   
  27.             self[key] = data   
  28.         self.session_id = current_session.session_id   
  29.         self.hmac_key = current_session.hmac_key
  30.  
  31. def save(self):   
  32.         self.session_manager.set(self.request_handler, self)   
  33. class SessionManager(object):   
  34.     def __init__(self, secret, store_options, session_timeout):   
  35.         self.secret = secret   
  36.         self.session_timeout = session_timeout   
  37.         try:   
  38.             if store_options['redis_pass']:   
  39.                 self.redis = redis.StrictRedis(host=store_options['redis_host'], port=store_options['redis_port'], password=store_options['redis_pass'])   
  40.             else:   
  41.                 self.redis = redis.StrictRedis(host=store_options['redis_host'], port=store_options['redis_port'])   
  42.         except Exception as e:   
  43.             print e
  44.  
  45.    def _fetch(self, session_id):   
  46.         try:   
  47.             session_data = raw_data = self.redis.get(session_id)   
  48.             if raw_data != None:   
  49.                 self.redis.setex(session_id, self.session_timeout, raw_data)   
  50.                 session_data = ujson.loads(raw_data)   
  51.             if type(session_data) == type({}):   
  52.                 return session_data   
  53.             else:   
  54.                 return {}   
  55.         except IOError:   
  56.             return {}   
  57.     def get(self, request_handler = None):   
  58.         if (request_handler == None):   
  59.             session_id = None   
  60.             hmac_key = None   
  61.         else:   
  62.             session_id = request_handler.get_secure_cookie("session_id")   
  63.             hmac_key = request_handler.get_secure_cookie("verification")   
  64.         if session_id == None:   
  65.             session_exists = False   
  66.             session_id = self._generate_id()   
  67.             hmac_key = self._generate_hmac(session_id)   
  68.         else:   
  69.             session_exists = True   
  70.         check_hmac = self._generate_hmac(session_id)   
  71.         if hmac_key != check_hmac:   
  72.             raise InvalidSessionException()   
  73.         session = SessionData(session_id, hmac_key)   
  74.         if session_exists:   
  75.             session_data = self._fetch(session_id)   
  76.             for key, data in session_data.iteritems():   
  77.                 session[key] = data   
  78.         return session 
  79.  
  80. def set(self, request_handler, session):   
  81.         request_handler.set_secure_cookie("session_id", session.session_id)   
  82.         request_handler.set_secure_cookie("verification", session.hmac_key)   
  83.         session_data = ujson.dumps(dict(session.items()))   
  84.         self.redis.setex(session.session_id, self.session_timeout, session_data)   
  85.     def _generate_id(self):   
  86.         new_id = hashlib.sha256(self.secret + str(uuid.uuid4()))   
  87.         return new_id.hexdigest()   
  88.     def _generate_hmac(self, session_id):   
  89.         return hmac.new(session_id, self.secret, hashlib.sha256).hexdigest()   
  90. class InvalidSessionException(Exception):   
  91.     pass 

tornado每个控制器相关的class ~

  1. import tornado.web   
  2. import sys   
  3. import session   
  4. class BaseHandler(tornado.web.RequestHandler):   
  5.     def __init__(self, *argc, **argkw):   
  6.         super(BaseHandler, self).__init__(*argc, **argkw)   
  7.         self.session = session.Session(self.application.session_manager, self)   
  8.     def get_current_user(self):   
  9.         return self.session.get("user_name"

对于登录注册session:

  1. self.session["user_name"] = self.get_argument("name")   
  2. self.session["nima"] = 'xiaorui.cc' 
  3. self.session.save() 

对于退出登录:

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

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

原文:http://rfyiamcool.blog.51cto.com/1030776/1406378

偶了,这就可以了。用之前要配置下相关的组件!

pip install ujson redis

pip install tornado

session.py 代码来自:

  1. git clone https://github.com/zs1621/tornado-redis-session 

这老外写的有点简陋,说明几乎没有,还好tornado redis session本身就是不难的东西,看看就能搞定。

单个tornado我现在已经可以顶到1500个长连接不崩溃了,如果加上ngixn做tornado的分发负载,估计连接在6k问题不大。就算是接入所有业务的邮件转发问题也不大,估计问题都在邮件网关上了。

博客地址:http://rfyiamcool.blog.51cto.com/1030776/1406378

 

责任编辑:林师授 来源: 51cto博客
相关推荐

2015-08-19 15:45:33

2021-03-08 09:56:24

存储分布式Session

2024-04-01 05:10:00

Redis数据库分布式锁

2023-12-29 08:18:31

Session分布式系统微服务

2022-01-06 10:58:07

Redis数据分布式锁

2023-08-21 19:10:34

Redis分布式

2019-06-19 15:40:06

分布式锁RedisJava

2015-06-17 14:10:34

Redis分布式系统协调

2017-10-27 08:40:44

分布式存储剪枝系统

2019-02-26 09:51:52

分布式锁RedisZookeeper

2023-01-13 07:39:07

2023-07-11 10:24:00

分布式限流算法

2015-05-12 13:03:54

开源分布式存储HDFS

2023-03-01 08:07:51

2024-01-02 13:15:00

分布式锁RedissonRedis

2022-06-28 08:37:07

分布式服务器WebSocket

2020-07-30 09:35:09

Redis分布式锁数据库

2020-07-15 16:50:57

Spring BootRedisJava

2018-11-28 16:00:41

2018-12-12 15:20:27

点赞
收藏

51CTO技术栈公众号