使用Redis构建web应用

登录和cookie缓存 购物车 网页缓存 数据行缓存 网页分析
代码格式有问题,见谅

欢迎访问本人博客:http://wangnan.tech

目录

登录和cookie缓存

cookie:当我们登录互联网服务的时候,这些服务都会使用cookie来记录我们的身份,cookie由少量数据组成,网站会要求我们的浏览器存储这些数据,并在每次服务发生请求时将这些数据传回给服务

对于用来登录的cookie,有两种方法可以将登录信息储存在cookie里面,一种是签名(signed)cookie一种是令牌(token)cookie

签名cookie通常会储存用户名,还可能有用户ID,用户最后一次成功登录的时间,以及网站觉得有用的其他信息,除此之外,cookie还会包含一个签名,服务器可以用它来验证浏览器发生的信息是否被改动(比如cookie中的登录用户名改成另一个用户)

令牌cookie会在cookie里面储存一串随机字节作为令牌,服务器可以根据令牌在数据库中查找令牌的拥有者,随着时间的推移,旧令牌会被新令牌取代

01.png

redis实现令牌登录cookie:首先,我们将使用一个hash来储存登录cookie令牌和已登录用户之间的映射,要检查一个用户是否已经登录,需要根据给定的令牌来查找与之对应的用户,并在用户已经登录的情况下,返回该用户的id

尝试获取并返回令牌对应的用户

def check_token(conn,token):
    return conn.hget('login:',token)

更新令牌:用户每次浏览页面的时候,程序都会对用户存储在登录hash里面的信息进行更新,并将用户的令牌和当前时间戳添加到记录最近登录用户的有序集合里面,如果用户正在浏览一个商品页面,那么程序还会将这个商品添加到记录这个用户最近浏览过的商品的有序集合里面,并在被记录的商品的数量超过25个时,对这个有序集合进行修剪

    def update_token(conn,token,user,item=None):
        timestamp = time.time()  //获取当前时间戳
        conn.hset('login:',token,user) //维持令牌与用户之间的映射
        conn.zadd('recent',token,timestamp)//记录令牌最后一次出现的时间
            if item:
                conn.zadd('viewed:'+token,item,timestamp) //记录用户浏览过的商品
                conn.zremrangebyrank('viewed:'+token,0,-26)//移除旧的记录,只保存用户浏览过的25个商品

储存会话的数据所需的内存会随着时间的推移不断增加,需要清理旧数据,只保存1000万个,清理程序是一个循环,检查集合的大小,超过了限制就移除最多100个旧令牌,并移除记录用户信息的hash信息,并清除浏览信息。如果没有要清理的,休眠1秒,在检查(附:使用redis过期时间,就可以在一段时间之后让redis自动删除他们)

    QUIT = False
    LIMIT = 10000000

    def clean_sessions(conn):
        while not QUIT:
        //找出目前已有令牌的数量
        size = conn.zcard('recent:')  
        //令牌数量未超过限制,休眠并在之后重新检查
        if size <= LIMIT:
            time.sleep(1)
            continue
        //获取需要移除的令牌id
        end_index = min(size-LIMIT,100)
        tokens = conn.zrange('recent:',0,end_index-1)
        //为那些要被删除的令牌构建键名
        session_keys = []
        for token in tokens:
            session_keys.append(‘viewed:’+token)
        //移除旧的那些令牌
        conn,delete(*session_keys)
        conn.hdel('login:',*tokens)
        conn.zrem('recent',*tokens)

购物车

每个用户的购物车是一个散列,这个散列储存了商品ID与商品订购数量之间的映射,对商品数量验证的工作由web应用程序复杂,我们要做的是在商品的订购数量发生变化的时候,对购物车进行更新

        def add_to_cart(conn,session,count)
        if count <=0;
            conn.hrem('cart:'+session,item)
        else
            conn.hset('cart:'+session,item,count)

网页缓存

    def cache_request(conn,request,callback):
        //对于不用背缓存的请求,直接调用回调函数
        if not can_cache(conn,request);
            return callback(request)
        //将请求装换成一个简单的字符串建。方便之后进 行查找
        page_key = 'cache:'+hash_request(request)
        //查找被缓存的页面
        content = conn.get(request)
        //如果页面还没有被缓存,那么生成页面
        if not content:
            content=callback(request)
            //将新生成的页面放到缓存里
            conn.setex(page_key,content,300)
        return content

数据行缓存

为了应对促销活动带来的大量负载,我们需要对数据进行缓存,具体的做法是:编写一个持续运行的守护进程函数,让这个函数将指定数据行缓存到redis里面,并不定期地对缓存进行更新,数据将被转为json储存在redis的字符串里

程序使用了两个zset,来记录应该在何时何地对缓存进行更新:第一个有序集合为调度有序集合,它的成员为数据行的行id,而分值是一个时间戳,记录了应该在何时将指定的数据行缓存到redis里面,第二个有序集合为延时zset,它的成员也是数据行的行id,而分值则记录了指定数据行的缓存需要每隔多少秒更新一次

调度缓存和终止缓存的函数

    def schedule_row_cache(conn,row_id,delay):
        //先设置数据行的延迟值
        conn.zadd('delay',row_id,delay)
        //立即对需要缓存的数据进行调度
        conn.zadd('schedule‘,row_id,time.time())

复杂缓存数据的函数

 def cache_rows(conn):
        while not QUIT:
            //尝试获取下一个需要被缓存的数据行以及该行的调度时间戳,命令会返回一个包含零个或一个元组的列表
        next = conn.zrange('schedule:',0,0,withscores=Ture)
        now =  time.time()
    //暂时没有行需要被缓存,休眠60ms后重试 
        if not next or next[0][1]>row
        time.sleep(.05)
        continue
         row_id = next[0][0]
    //提前获取下一次调度的延迟时间
            delay=conn.zscore('delay',row_id)
             if delay <=0:
            //不必缓存这个行,从他从缓存中移除
            conn.zrem('delay:',row_id)
            conn.zrem('schedule:',row_id)
            conn.delete('inv:'+row_id)
            continue
    
            //读取数据行,更新调度时间并设置缓存值
            row = Inventory.get(row_id)
            conn.zadd('schedule:',row_id,now+delay)
            conn.set('inv'+row_id,json.dump(row.to_dict()))

网页分析

在原来的update_token中

    def update_token(conn,token,user,item=None):
        timestamp = time.time()  //获取当前时间戳
        conn.hset('login:',token,user) //维持令牌与用户之间的映射
        conn.zadd('recent',token,timestamp)//记录令牌最后一次出现的时间
    if item:
       conn.zadd('viewed:'+token,item,timestamp) //记录用户浏览过的商品
       conn.zremrangebyrank('viewed:'+token,0,-26)//移除旧的记录,只保存用户浏览过的25个商品
       conn.zincrby('viewed:'item,-1)

新添加的代码记录了商品的浏览次数,并根据浏览次数对商品进行了排序,被浏览的最多的商品将被放在有序集合的索引0的位置上,并且具有最少的分值
为了让商品浏览次数保持最新,我们需要定期修剪有序集合的长度并调整已有元素的分值,从而使得新流行的商品也可以在排行榜里面占据一席之地

    def rescale_viewed(conn);
        while not QUIT:
            //删除所有牌面在2万名之后的商品
            conn.zremrangebyrank('viewed',0,-20001)
            //将浏览次数降低为原来的一般
            conn,zinterstore('viewed:' .5)
            time.sleep(300)

修改之前的的can_cache()函数

    def can_cache(conn request);
        //尝试从页面里面获取商品id
        item_id = extract_itrm_id(request)
        //检查这个页面能否被缓存已经这个页面是否为商品页面
        if not item_id or is_dynamic(request);
        return False
        //获取商品的浏览次数牌面    
        rank = conn,zrank('viewed',item_id)
        根据排名判断是否需要被缓存
        return rank is not None and rank<10000

(注:内容整理自《redis实战》)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,178评论 11 349
  • 我的Mac Air是11年买的,最近电池报废了,淘宝上买了新电池准备给换上,几个螺丝拧完拆下后盖就看到下面的样子,...
    我不是段誉阅读 1,046评论 2 1
  • 那是在二十年前,夜黑风高的夜晚。连都的电影院还没有发达到成影院的地步。是在一个大操场上用大棚搭建的简易电影院。三个...
    被窝里的文字阅读 131评论 0 1
  • LeetCode题目链接 注意:凡是以英文出现的,都是题目提供的,包括答案代码里的前几行。 题目: Write a...
    _Xie_阅读 129评论 0 0