使用redis来实现tornado session的分布式存储
前言: 话说文章转自我的51cto博客里的,xiaorui.cc ! 前两天有人问我tornado到c10,先声明下,我也不知道tornado官方是咋测试的,我自己是没到那种牛逼的抗链接能力,不然咋说,该优化还是优化,EFI要这么较真,可以试着用nginx来处理tornado不太擅长的静
前言:
话说文章转自我的51cto博客里的,xiaorui.cc !
前两天有人问我tornado到c10,先声明下,我也不知道tornado官方是咋测试的,我自己是没到那种牛逼的抗链接能力,不然咋说,该优化还是优化,EFI要这么较真,可以试着用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页面。
插入一个广告,最近文章总是被爬虫爬走,这边标记下原文的地址 blog.xiaorui.cc 。 说来也郁闷,我本人也是负责业务爬虫业务的,而且爬虫采用的一些技术也相当的强悍,但是没招呀 。 对方有时候还伪装 spider 。你咋办,你不认真分析,有可能封杀了真正的spider bot 。
#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"])
关联的两个类:
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的主要文件
#/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
这个文章的原文是在 http://blog.xiaorui.cc ,我的文章总是被爬来爬去的。
tornado每个控制器相关的class ~
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:
self.session["user_name"] = self.get_argument("name") self.session["nima"] = 'xiaorui.cc' self.session.save()
对于退出登录:
self.session["nima"] =None self.session.save()
其实就改成None就行了,匹配都在装饰器那边搞好了。
偶了,这就可以了。用之前要配置下相关的组件!
pip install ujson redis
pip install tornado
session.py 代码来自:
git clone https://github.com/zs1621/tornado-redis-session
这老外写的有点简陋,说明几乎没有,还好tornado redis session本身就是不难的东西,看看就能搞定。
单个tornado我现在已经可以顶到1500个长连接不崩溃了,如果加上ngixn做tornado的分发负载,估计连接在6k问题不大。
本文出自:http://blog.xiaorui.cc, 原文地址:http://blog.xiaorui.cc/2014/11/02/%e4%bd%bf%e7%94%a8redis%e6%9d%a5%e5%ae%9e%e7%8e%b0tornado-session%e7%9a%84%e5%88%86%e5%b8%83%e5%bc%8f%e5%ad%98%e5%82%a8/, 感谢原作者分享。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Redis Cluster Mode는 Sharding을 통해 Redis 인스턴스를 여러 서버에 배포하여 확장 성 및 가용성을 향상시킵니다. 시공 단계는 다음과 같습니다. 포트가 다른 홀수 redis 인스턴스를 만듭니다. 3 개의 센티넬 인스턴스를 만들고, Redis 인스턴스 및 장애 조치를 모니터링합니다. Sentinel 구성 파일 구성, Redis 인스턴스 정보 및 장애 조치 설정 모니터링 추가; Redis 인스턴스 구성 파일 구성, 클러스터 모드 활성화 및 클러스터 정보 파일 경로를 지정합니다. 각 redis 인스턴스의 정보를 포함하는 Nodes.conf 파일을 작성합니다. 클러스터를 시작하고 Create 명령을 실행하여 클러스터를 작성하고 복제본 수를 지정하십시오. 클러스터에 로그인하여 클러스터 정보 명령을 실행하여 클러스터 상태를 확인하십시오. 만들다

Redis는 해시 테이블을 사용하여 데이터를 저장하고 문자열, 목록, 해시 테이블, 컬렉션 및 주문한 컬렉션과 같은 데이터 구조를 지원합니다. Redis는 Snapshots (RDB)를 통해 데이터를 유지하고 WRITE 전용 (AOF) 메커니즘을 추가합니다. Redis는 마스터 슬레이브 복제를 사용하여 데이터 가용성을 향상시킵니다. Redis는 단일 스레드 이벤트 루프를 사용하여 연결 및 명령을 처리하여 데이터 원자력과 일관성을 보장합니다. Redis는 키의 만료 시간을 설정하고 게으른 삭제 메커니즘을 사용하여 만료 키를 삭제합니다.

Redis 버전 번호를 보려면 다음 세 가지 방법을 사용할 수 있습니다. (1) info 명령을 입력하고 (2) -version 옵션으로 서버를 시작하고 (3) 구성 파일을 봅니다.

Redis-Server가 찾을 수없는 문제를 해결하기위한 단계 : Redis가 올바르게 설치되어 있는지 확인하십시오. 환경 변수를 설정 redis_host 및 redis_port; Redis Server Redis-Server를 시작하십시오. 서버가 Redis-Cli Ping을 실행 중인지 확인하십시오.

Redis 순서 세트 (ZSETS)는 순서가있는 요소를 저장하고 관련 점수별로 정렬하는 데 사용됩니다. ZSET을 사용하는 단계에는 다음이 포함됩니다. 1. ZSET을 만듭니다. 2. 회원 추가; 3. 회원 점수를 얻으십시오. 4. 순위를 얻으십시오. 5. 순위 범위에서 멤버를 받으십시오. 6. 회원 삭제; 7. 요소 수를 얻으십시오. 8. 점수 범위에서 멤버 수를 얻으십시오.

Redis Cluster는 Redis 인스턴스의 수평 확장을 허용하는 분산 배포 모델이며, 노드 간 통신, 해시 슬롯 디비전 키 공간, 노드 선거, 마스터 슬레이브 복제 및 명령 리디렉션을 통해 구현됩니다. 노드 간 통신 : 가상 네트워크 통신은 클러스터 버스를 통해 실현됩니다. 해시 슬롯 : 키 공간을 해시 슬롯으로 나누어 키를 담당하는 노드를 결정합니다. 노드 선거 : 최소 3 개의 마스터 노드가 필요하며 선거 메커니즘을 통해 하나의 활성 마스터 노드 만 보장됩니다. 마스터 슬레이브 복제 : 마스터 노드는 요청을 작성하고 슬레이브 노드는 요청 및 데이터 복제를 담당합니다. 명령 리디렉션 : 클라이언트는 키를 담당하는 노드에 연결하고 노드는 잘못된 요청을 리디렉션합니다. 문제 해결 : 결함 감지, 라인 마킹 및 재

Redis는 키의 독창성을 보장하기 위해 5 가지 전략을 사용합니다. 1. 네임 스페이스 분리; 2. 해시 데이터 구조; 3. 데이터 구조 설정; 4. 문자열 키의 특수 문자; 5. LUA 스크립트 확인. 특정 전략의 선택은 데이터 구성, 성능 및 확장 성 요구 사항에 따라 다릅니다.

Redis에서 모든 키를 보려면 세 가지 방법이 있습니다. 키 명령을 사용하여 지정된 패턴과 일치하는 모든 키를 반환하십시오. 스캔 명령을 사용하여 키를 반복하고 키 세트를 반환하십시오. 정보 명령을 사용하여 총 키 수를 얻으십시오.
