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

简介:

前言:

   为了提供让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,如需转载请自行联系原作者


相关文章
|
11月前
|
存储 负载均衡 NoSQL
【赵渝强老师】Redis Cluster分布式集群
Redis Cluster是Redis的分布式存储解决方案,通过哈希槽(slot)实现数据分片,支持水平扩展,具备高可用性和负载均衡能力,适用于大规模数据场景。
752 2
|
11月前
|
存储 缓存 NoSQL
【📕分布式锁通关指南 12】源码剖析redisson如何利用Redis数据结构实现Semaphore和CountDownLatch
本文解析 Redisson 如何通过 Redis 实现分布式信号量(RSemaphore)与倒数闩(RCountDownLatch),利用 Lua 脚本与原子操作保障分布式环境下的同步控制,帮助开发者更好地理解其原理与应用。
808 6
|
12月前
|
存储 缓存 NoSQL
Redis核心数据结构与分布式锁实现详解
Redis 是高性能键值数据库,支持多种数据结构,如字符串、列表、集合、哈希、有序集合等,广泛用于缓存、消息队列和实时数据处理。本文详解其核心数据结构及分布式锁实现,帮助开发者提升系统性能与并发控制能力。
|
10月前
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
561 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
10月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
854 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
10月前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
12月前
|
NoSQL Redis
Lua脚本协助Redis分布式锁实现命令的原子性
利用Lua脚本确保Redis操作的原子性是分布式锁安全性的关键所在,可以大幅减少由于网络分区、客户端故障等导致的锁无法正确释放的情况,从而在分布式系统中保证数据操作的安全性和一致性。在将这些概念应用于生产环境前,建议深入理解Redis事务与Lua脚本的工作原理以及分布式锁的可能问题和解决方案。
402 8
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
3486 7
|
缓存 监控 NoSQL
Redis设计与实现——分布式Redis
Redis Sentinel 和 Cluster 是 Redis 高可用与分布式架构的核心组件。Sentinel 提供主从故障检测与自动切换,通过主观/客观下线判断及 Raft 算法选举领导者完成故障转移,但存在数据一致性和复杂度问题。Cluster 支持数据分片和水平扩展,基于哈希槽分配数据,具备自动故障转移和节点发现机制,适合大规模高并发场景。复制机制包括全量同步和部分同步,通过复制积压缓冲区优化同步效率,但仍面临延迟和资源消耗挑战。两者各有优劣,需根据业务需求选择合适方案。
1000 14
|
NoSQL 算法 安全
redis分布式锁在高并发场景下的方案设计与性能提升
本文探讨了Redis分布式锁在主从架构下失效的问题及其解决方案。首先通过CAP理论分析,Redis遵循AP原则,导致锁可能失效。针对此问题,提出两种解决方案:Zookeeper分布式锁(追求CP一致性)和Redlock算法(基于多个Redis实例提升可靠性)。文章还讨论了可能遇到的“坑”,如加从节点引发超卖问题、建议Redis节点数为奇数以及持久化策略对锁的影响。最后,从性能优化角度出发,介绍了减少锁粒度和分段锁的策略,并结合实际场景(如下单重复提交、支付与取消订单冲突)展示了分布式锁的应用方法。
998 3

热门文章

最新文章