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