使用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)
扫描二维码关注公众号,回复: 6590650 查看本文章

参考资料:

《Redis实战》

转载于:https://www.cnblogs.com/gattaca/p/6993035.html

猜你喜欢

转载自blog.csdn.net/weixin_34101229/article/details/93401893