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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

前言:

   为了提供让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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#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" ])


关联的两个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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的文件 !

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#/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 ~


1
2
3
4
5
6
7
8
9
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:


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

对于退出登录:


1
2
self.session[ "nima" ] =None
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问题不大。就算是接入所有业务的邮件转发问题也不大,估计问题都在邮件网关上了。



 本文转自 rfyiamcool 51CTO博客,原文链接:http://blog.51cto.com/rfyiamcool/1406378,如需转载请自行联系原作者


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
NoSQL 算法 安全
Redlock 算法-主从redis分布式锁主节点宕机锁丢失的问题
Redlock 算法-主从redis分布式锁主节点宕机锁丢失的问题
152 0
|
1月前
|
NoSQL 关系型数据库 MySQL
分布式锁(redis/mysql)
分布式锁(redis/mysql)
55 1
|
23天前
|
NoSQL Java Redis
如何通俗易懂的理解Redis分布式锁
在多线程并发的情况下,我们如何保证一个代码块在同一时间只能由一个线程访问呢?
34 2
|
1月前
|
缓存 NoSQL Java
【Redis】5、Redis 的分布式锁、Lua 脚本保证 Redis 命令的原子性
【Redis】5、Redis 的分布式锁、Lua 脚本保证 Redis 命令的原子性
57 0
|
1月前
|
人工智能 监控 NoSQL
【万字长文 一文搞定】Redis:从新手村到大师殿堂的奥德赛之旅 9种实现分布式锁的全技术指南
【万字长文 一文搞定】Redis:从新手村到大师殿堂的奥德赛之旅 9种实现分布式锁的全技术指南
81 4
|
1月前
|
存储 NoSQL 前端开发
【SpringBoot】Redis集中管理Session和自定义用户参数解决登录状态及校验问题
【SpringBoot】Redis集中管理Session和自定义用户参数解决登录状态及校验问题
|
1月前
|
消息中间件 存储 NoSQL
【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统
【Redis项目实战】使用Springcloud整合Redis分布式锁+RabbitMQ技术实现高并发预约管理处理系统
|
1月前
|
NoSQL API Redis
Redis分布式锁实现的三个核心
Redis分布式锁实现的三个核心
|
1月前
|
NoSQL Java Redis
Redis分布式锁和Java锁的区别
Redis分布式锁和Java锁的主要区别在于它们的适用范围和实现机制。
39 2
|
1月前
|
运维 NoSQL Java
【Redis】6、Redisson 分布式锁的简单使用(可重入、重试机制...)
【Redis】6、Redisson 分布式锁的简单使用(可重入、重试机制...)
93 1

热门文章

最新文章