更新时间:2022-10-02 21:39:19
前言:
为了提供让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,如需转载请自行联系原作者