Redis 原理、概念与数据类型;增删改查实例;实现缓存并统计点击量
目录
一、Redis 原理、概念与数据类型
1.1 Redis 概念
Redis(Remote Dictionary Server)是一款开源的内存键值对数据库,也被称为“数据结构服务器”。它支持多种数据结构(如字符串、哈希、列表等),并提供持久化、事务、发布订阅等功能。核心特点是:
- 高性能:内存存储,读写速度可达10万+ QPS;
- 持久化:支持RDB(快照)和AOF(日志)两种持久化方式;
- 多数据结构:内置丰富的数据类型,适用于复杂场景;
- 原子性:单线程模型保证命令执行的原子性;
- 分布式:支持主从复制、哨兵、集群等分布式方案。
1.2 Redis 核心原理
(1)内存存储与持久化
- 内存存储:数据主要存储在内存中,读写效率极高;但内存断电易失,因此需要持久化机制。
- RDB(Redis Database):定期将内存数据快照写入磁盘(通过
save
配置触发,如save 900 1
表示900秒内至少1次修改则触发)。优点是文件紧凑、恢复快;缺点是可能丢失最后一次快照后的数据。 - AOF(Append Only File):记录所有写操作命令(追加到文件),重启时重新执行命令恢复数据。支持
always
(每条命令同步)、everysec
(每秒同步,默认)、no
(由操作系统决定)三种同步策略。优点是数据安全性高(最多丢失1秒数据);缺点是文件体积大,恢复速度慢。
(2)单线程模型
Redis 6.0 前采用单线程处理命令(IO多路复用技术处理网络请求),避免了多线程上下文切换的开销。6.0 后引入多线程处理网络IO(仅负责接收/发送命令),但命令执行仍由主线程完成,保证了原子性。
(3)IO多路复用
通过epoll
/kqueue
等系统调用,监听多个客户端连接,实现单线程高效处理大量并发请求。
1.3 Redis 数据类型
Redis 支持以下核心数据类型(均基于键值对存储,键为字符串):
数据类型 | 描述 | 典型应用场景 |
---|---|---|
String | 字符串(支持整数、浮点数、二进制数据,最大512MB) | 缓存、计数器、分布式锁 |
Hash | 键值对集合(类似Java的HashMap ) |
存储对象(如用户信息user:1001 ) |
List | 有序可重复的列表(基于双向链表) | 消息队列、历史记录 |
Set | 无序唯一的集合(基于哈希表或跳表) | 去重、共同好友、随机抽取 |
Sorted Set | 有序唯一的集合(元素关联分数score ,按分数排序) |
排行榜、时间线 |
Bitmap | 基于String的位操作(每一位表示一个布尔值) | 统计活跃用户、签到记录 |
HyperLogLog | 基于概率算法的统计结构(误差约0.81%) | 统计海量数据的独立总数(如UV) |
Geo | 地理位置存储(经纬度) | 附近的人/地点查询 |
二、Redis 缓存增删改查实例(Python实现)
2.1 环境准备
- 安装Redis服务(本地或远程,本文假设本地运行在
localhost:6379
); - 安装Python Redis客户端:
pip install redis
。
2.2 业务场景
以“用户信息缓存”为例,实现以下功能:
- 增加缓存:用户注册时,将用户信息存入Redis;
- 查询缓存:用户登录时,优先从Redis获取信息;
- 修改缓存:用户信息更新时,同步更新Redis;
- 删除缓存:用户注销时,删除Redis中的缓存。
2.3 代码实现
import redis
class RedisCache:
def __init__(self, host='localhost', port=6379, db=0, password=None):
self.redis_client = redis.Redis(
host=host,
port=port,
db=db,
password=password,
decode_responses=True # 自动解码字节为字符串
)
# 增加缓存(用户信息)
def add_user_cache(self, user_id, user_info):
"""将用户信息以Hash形式存入Redis"""
key = f"user:{user_id}"
# user_info格式:{"name": "张三", "age": 25, "email": "zhangsan@example.com"}
return self.redis_client.hset(key, mapping=user_info)
# 查询缓存(用户信息)
def get_user_cache(self, user_id):
"""从Redis获取用户信息"""
key = f"user:{user_id}"
user_data = self.redis_client.hgetall(key)
return user_data if user_data else None # 无缓存返回None
# 修改缓存(用户信息)
def update_user_cache(self, user_id, updated_info):
"""更新用户信息(仅更新存在的字段)"""
key = f"user:{user_id}"
if self.redis_client.exists(key):
return self.redis_client.hupdate(key, mapping=updated_info)
else:
raise ValueError(f"用户{user_id}缓存不存在")
# 删除缓存(用户信息)
def delete_user_cache(self, user_id):
"""删除用户缓存"""
key = f"user:{user_id}"
return self.redis_client.delete(key)
# 示例用法
if __name__ == "__main__":
# 初始化缓存客户端
cache = RedisCache()
# 1. 增加缓存:用户注册
user_info = {"name": "张三", "age": 25, "email": "zhangsan@example.com"}
cache.add_user_cache(user_id=1001, user_info=user_info)
print("添加缓存成功,用户1001信息:", cache.get_user_cache(1001))
# 2. 查询缓存:用户登录
cached_user = cache.get_user_cache(1001)
print("查询缓存结果:", cached_user)
# 3. 修改缓存:用户信息更新(年龄改为26)
updated_info = {"age": 26}
cache.update_user_cache(user_id=1001, updated_info=updated_info)
print("修改后缓存信息:", cache.get_user_cache(1001))
# 4. 删除缓存:用户注销
cache.delete_user_cache(1001)
print("删除后缓存信息:", cache.get_user_cache(1001)) # 应返回None
三、使用Redis实现缓存并统计点击量
3.1 业务场景
统计某个页面(如商品详情页)的点击量,要求:
- 实时性:每次点击立即更新计数;
- 高并发:支持大量用户同时点击;
- 持久化:重启后数据不丢失。
3.2 实现方案
使用Redis的String类型配合INCR
命令实现计数器。INCR
是原子操作,保证高并发下的正确性;结合持久化机制(如RDB/AOF)确保数据不丢失。
3.3 代码实现
import redis
from datetime import datetime
class ClickCounter:
def __init__(self, host='localhost', port=6379, db=0):
self.redis_client = redis.Redis(host=host, port=port, db=db, decode_responses=True)
# 记录一次点击(按页面和日期分组)
def record_click(self, page_id):
# 键格式:click:page:{page_id}:{date}(如click:page:101:20250808)
today = datetime.now().strftime("%Y%m%d")
key = f"click:page:{page_id}:{today}"
return self.redis_client.incr(key) # 原子递增,返回当前总次数
# 获取某页面今日点击量
def get_today_clicks(self, page_id):
today = datetime.now().strftime("%Y%m%d")
key = f"click:page:{page_id}:{today}"
return int(self.redis_client.get(key) or 0) # 无数据返回0
# 获取某页面历史总点击量(可选:按日期聚合)
def get_total_clicks(self, page_id):
# 匹配所有日期的键(如click:page:101:*)
keys = self.redis_client.keys(f"click:page:{page_id}:*")
total = 0
for key in keys:
total += int(self.redis_client.get(key))
return total
# 示例用法
if __name__ == "__main__":
counter = ClickCounter()
# 模拟用户点击商品详情页(page_id=101)
for _ in range(5):
counter.record_click(page_id=101)
print("今日点击量(101页):", counter.get_today_clicks(101)) # 输出5
print("历史总点击量(101页):", counter.get_total_clicks(101)) # 输出5(假设仅今日有数据)
四、总结
- Redis 是高性能内存数据库,核心优势在于内存存储、多数据结构和持久化;
- 缓存设计需考虑增删改查的原子性及与数据库的一致性;
- 点击量统计利用String的
INCR
命令实现高效计数,支持高并发场景。