• 使用Redis构建电商网站


    涉及到的key:

    1. login,hash结构,存储用户token与用户ID之间的映射。

    2. recent_tokens,存储最近登陆用户token,zset结构

      member: token,score: 登陆时间戳

    3. viewed_token,存储token对应用户的浏览商品集合,zset结构,

      member: 商品ID,score: 浏览时间戳

    4. cart_token, 存储token对应用户的购物车,hash结构,key:商品ID,value: 商品数量

    5. schedule, zset结构, member为数据行的行ID,score是一个时间戳,对应何时将指定的数据行缓存到Redis里面

    6. delay,zset结构, member为数据行的行ID,score记录了指定数据行的缓存需要每隔多少秒更新一次。

    7. viewed, zset结构, member:商品ID, score: 商品浏览次数,用负数表示,浏览次数最高的商品,其索引值为0

    # python3
    # -*- coding: utf-8 -*-
    
    import redis
    import time
    import json
    
    def check_token(conn, token):
        return conn.hget('login', token)
    
    def update_token(conn, token, user, item=None):
        timestamp = time.time()
        conn.hset('login', token, user)
        conn.zadd('recent_tokens', token, timestamp)
    
        # 用户正在浏览的是一个商品页面
        if item:
            conn.zadd('viewed_' + token, item, timestamp)
            # 只保留用户最近浏览过的25个商品
            conn.zremrangebyrank('viewed_' + token, 0, -26)
            # 采用负数表示页面浏览次数,浏览次数越高的页面,其索引值越小
            conn.zincrby('viewed', item, -1)
    
    QUIT = False
    LIMIT = 10000000
    
    # 应该用守护进程来执行这个函数或者做成定时任务
    #清除内容包括: recent_tokens,login,用户对应的浏览记录、购物车
    def clean_full_session(conn):
        while not QUIT:
            size = conn.zcard('recent_tokens')
            if size <= LIMIT:
                time.sleep(1)
                continue
    
            end_index = min(size - LIMIT, 100)
            sessions = conn.zrange('recent_tokens', 0, end_index - 1)
    
            session_keys = []
            for sess in sessions:
                session_keys.append('viewed_' + sess)
                session_keys.append('cart_' + sess)
    
            conn.delete(*session_keys)
            conn.hdel('login', *sessions)
            conn.zrem('recent_tokens', *sessions)
    
    # 添加商品到购物车
    def add_to_cart(conn, session, item, count):
        if count <= 0:
            conn.hrem('cart_' + session, item)
        else:
            conn.hset('cart_' + session, item, count)
    
    def can_cache(conn,request):
        item_id = extract_item_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 < 1000
    
    def cache_request(conn, request, callback):
        if not can_cache(conn,request):
            return callback(request)
    
        page_key = 'cache_' + hash_request(request)
        content = conn.get(page_key)
    
        if not content:
            content = callback(request)
            conn.setex(page_key, content, 300)
    
        return content
    
    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=True)
            now = time.time()
            if not next or next[0][1] > now:
                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.dumps(row.to_dict()))
    
    def rescale_viewed(conn):
        while not QUIT:
            # 保留浏览次数最低的20000个商品
            conn.zremrangebyrank('viewed', 0, -20001)
            conn.zinterstore('viewed', {'viewed': .5})
            time.sleep(300)
            
    r = redis.Redis(host='redis_serverip', port=6379, password='redis_passwd', db=0)

    参考资料:

    《Redis实战》

  • 相关阅读:
    Vue-CLI
    Vue生命周期函数
    构建之法阅读笔记之四
    大二下个人总结
    个人加分项
    对老师的建议
    学习进度条 第九十一-第一百零五天 vue+uniapp app开发学习笔记
    第15周作业
    二进制安装mysql 5.7.31 启动报错/etc/init.d/mysqld: line 239: my_print_defaults: command not found
    获取最小数字
  • 原文地址:https://www.cnblogs.com/gattaca/p/6993035.html
Copyright © 2020-2023  润新知