Redis practical tutorial

Are you still complaining about slow web application queries, occasional lost sessions, or even e-commerce oversales and oversubscriptions? Today I will take you from "zero installation" to "implementation of Python high-frequency scenarios", using a lightweight and efficient solution to solve these problems!


What is Redis?

Redis (Remote Dictionary Server) is an open source memory-first data structure storage system that can be used as a cache, semi-persistent database, and lightweight message middleware at the same time. Its biggest feature is that it supports many more structured operations than ordinary key values, and can help us quickly implement complex logic using Redis native commands without having to write a bunch of code at the application layer.

Let’s briefly list a few commonly used features at the production level:

  • Millisecond response: full memory storage, single node read and write up to 100,000/second+
  • Data half-implementation: RDB (scheduled snapshot) + AOF (incremental log) dual persistence, taking into account both speed and security
  • Full coverage of master-slave/sentinel/cluster: from read-write separation to high availability, to distributed horizontal expansion
  • Lua script atomic operation: an artifact to solve oversold and counting consistency

1. Quickly install Redis in 3 steps

Whether you are on Windows, Mac or Linux, Docker can avoid environment dependency problems:

# 1. 拉取官方稳定版(LTS最新通常选7.x以上)
docker pull redis:7-alpine

# 2. 后台启动,绑定本地6379端口,开启持久化
docker run -d \
  --name my-redis-dev \
  -p 6379:6379 \
  -v redis-data-dev:/data \
  redis:7-alpine \
  redis-server --appendonly yes

# 3. 测试连接
docker exec -it my-redis-dev redis-cli ping
# 输出PONG就成功了!

1.2 Alternate: WSL/Ubuntu native

If you are not used to Docker, install it with WSL 2 Ubuntu/Debian:

sudo apt update && sudo apt install -y redis-server
sudo systemctl enable --now redis-server
redis-cli ping  # 测试

2. A quick overview of high-frequency Redis data types (with code)

The core of Redis is not "storing key values", but using corresponding data structures to solve corresponding problems! Only the types used in 80% of production scenarios are listed below:

2.1 String: Tiger Balm

It can be used to store single values, counters, and temporary tokens:

# 设置带过期时间的token(NX=仅不存在时设,EX=过期秒数)
SET token:user:1000 "abc123xyz" EX 3600 NX

# 获取token
GET token:user:1000

# 原子自增(电商库存、日活统计)
INCR daily:active:users
INCRBY product:stock:2024 5  # 补5件库存

2.2 Hash: Storing objects saves memory

Replacing hashed string keys like "user:1000:name=xx" saves about 30-50% of memory:

# 设置用户信息
HSET user:profile:1000 name "道满Python" role "博主" age 28

# 批量获取指定字段
HMGET user:profile:1000 name role

# 只获取某个字段
HGET user:profile:1000 age

2.3 List: lightweight queue/stack

Use LPUSH/RPUSH+BRPOP/BLPOP to implement a blocking message queue without introducing heavyweight middleware such as RabbitMQ/Kafka:

# 模拟生产者:左侧推入待处理订单
LPUSH orders:todo "order:20240501001" "order:20240501002"

# 模拟消费者:右侧阻塞等待订单(0=永久等待)
BRPOP orders:todo 0

2.4 Sorted Set: Automatic Ranking

Automatically sort by score (such as number of likes, score, timestamp) without application layer operations:

# 发布文章并设置初始点赞数
ZADD article:likes 0 "article:20240501001"

# 点赞+1(ZINCRBY自动更新排序)
ZINCRBY article:likes 1 "article:20240501001"

# 获取点赞数前3的文章(带分数,倒序)
ZREVRANGE article:likes 0 2 WITHSCORES

3. Seamless integration of Python and Redis

For production environments, it is recommended to use officially maintained ones.redisLibrary, supports synchronous/async:

3.1 Installation and basic connection

# 安装同步/异步通用库
pip install redis redis[hiredis]  # hiredis是C加速解析器,性能翻倍
import redis
# 同步基础连接(自动解码响应,避免bytes转str)
r = redis.Redis(
    host="localhost",
    port=6379,
    db=0,
    decode_responses=True,
    socket_timeout=5  # 超时避免卡死
)
print(r.ping())  # 测试

3.2 High-frequency Python scenario 1: interface caching

By writing a decorator, you can add Redis cache to any synchronous/asynchronous interface to avoid frequent database checks:

import json
from functools import wraps

# 同步装饰器
def sync_cache(expire=300):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # 生成唯一缓存键(要考虑参数顺序)
            key = f"cache:{func.__name__}:{hash(repr(args)+repr(sorted(kwargs.items())))}"
            cached = r.get(key)
            if cached:
                return json.loads(cached)
            # 查库并缓存
            res = func(*args, **kwargs)
            r.setex(key, expire, json.dumps(res, ensure_ascii=False))
            return res
        return wrapper
    return decorator

# 测试装饰器
@sync_cache(expire=600)
def get_user_profile(user_id: int):
    print("=== 模拟数据库查询 ===")
    return {"id": user_id, "name": "道满Python", "role": "博主"}

print(get_user_profile(1000))  # 第一次查库
print(get_user_profile(1000))  # 第二次走缓存

3.3 High-frequency Python scenario 2: oversold atomic lock

Use Lua script + SET NX EX to solve the overselling problem of e-commerce flash sales and reservation registration to ensure atomicity:

import uuid

# Lua脚本:检查库存>0 → 扣减库存 → 返回扣减结果
LUA_DEDUCT_STOCK = """
local stock = tonumber(redis.call('GET', KEYS[1]))
if stock and stock >= tonumber(ARGV[1]) then
    redis.call('DECRBY', KEYS[1], tonumber(ARGV[1]))
    return 1  -- 成功
end
return 0  -- 失败
"""

def deduct_stock(product_id: int, count: int = 1):
    key = f"product:stock:{product_id}"
    # 加载脚本(缓存后SHA执行更快)
    sha = r.script_load(LUA_DEDUCT_STOCK)
    try:
        res = r.evalsha(sha, 1, key, count)
        return res == 1
    except Exception as e:
        # 如果脚本过期(比如重启Redis),重新加载
        print(f"脚本过期,重新加载:{e}")
        return deduct_stock(product_id, count)

# 测试
r.set("product:stock:2024", 3)  # 初始3件库存
for _ in range(5):  # 5个请求
    print(f"秒杀{'成功' if deduct_stock(2024) else '失败'}")

4. Redis tips to avoid pitfalls

4.1 Key naming convention

Unified team standards to avoid confusion, recommended业务:模块:资源IDThe colon layering:

✅ session:user:1000
✅ cache:article:list:page1
✅ product:stock:2024
❌ a123456(无业务含义)
❌ User_Profile-1000(符号混用)

4.2 Slow query monitoring

For production environmentSLOWLOG GET 10Check the last 10 commands that exceed the specified time. By default, the records exceed 10000 microseconds (10ms):

# 临时设置慢查询阈值为5ms(生产建议永久改配置文件)
CONFIG SET slowlog-log-slower-than 5000

Summarize

Redis is a lightweight but powerful tool. As long as you choose the right data structure, you can solve the most difficult performance problems with the least amount of code. Today we learned:

  1. Docker starts the development environment with one click
  2. Usage of 4 high-frequency data structures
  3. The complete code of Python plus interface cache and oversold atomic lock
  4. Tips for avoiding pitfalls in production

If you want to learn more, you can read the "Sentinel Mode/Cluster Mode" and "Memory Optimization" content later!