第三方 Python 库 redis-py + hiredis 的使用
第三方 Python 库 redis-py hiredis 的使用一、背景为什么 Python 开发者需要关注 Redis 客户端库做过 Web 开发的同学对 Redis 一定不陌生。无论是做缓存、会话管理、消息队列还是排行榜、计数器Redis 几乎是后端架构里的标配组件。但问题来了——Python 怎么跟 Redis 打交道答案是通过客户端库。Python 生态里最主流的 Redis 客户端就是redis-py它是 Redis 官方维护的 Python SDK几乎所有的 Python 项目操作 Redis 都在用它。而hiredis则是另一个经常被提起的名字。很多教程里会告诉你装上 hiredis 能让 redis-py 跑得更快但很少有人把两者的关系和原理讲清楚。这篇文章就来把这件事说透redis-py 和 hiredis 到底是什么关系为什么要一起用怎么用二、概念厘清redis-py 和 hiredis 分别是什么2.1 redis-py —— Python 的 Redis “翻译官”redis-py是 Redis 官方出品的 Python 客户端库用纯 Python 编写。它的职责很明确把你在 Python 里写的r.set(name, Tom)翻译成 Redis 能理解的 RESP 协议报文把 Redis 返回的二进制响应解析成 Python 能用的数据类型bytes、str、int、list 等你可以把它想象成一个翻译官你用 Python 说话Redis 用 RESP 协议说话redis-py 负责两边互译。importredis# 创建连接rredis.Redis(hostlocalhost,port6379,db0,decode_responsesTrue)# 操作 Redis 就像操作 Python 字典一样简单r.set(name,Tom)print(r.get(name))# 输出: Tom2.2 hiredis —— 用 C 写的高性能翻译引擎hiredis是 Redis 官方用C 语言编写的客户端库。它的定位不是给 Python 开发者直接用的而是作为一个底层引擎。hiredis 最核心的价值在于它的回复解析器Reply Parser——它用 C 实现了一套高效的 RESP 协议解析逻辑能把 Redis 返回的原始字节流快速解析成结构化数据。打个比方redis-py 自带的解析器是用 Python 写的相当于一个普通翻译hiredis 的解析器是用 C 写的相当于一个同声传译设备——速度更快、效率更高2.3 两者的关系redis-py 是外壳hiredis 是加速引擎关键结论redis-py 和 hiredis 不是竞争关系而是合作关系。redis-py 从 3.x 版本开始就内置了对 hiredis 的支持。当系统中安装了 hiredis 1.0redis-py 会自动切换使用 hiredis 的 C 语言解析器来处理 Redis 响应而不需要你修改任何代码。用一张表来总结对比维度redis-pyhiredis语言PythonC角色完整的 Redis 客户端 SDK底层协议解析引擎能否独立使用能开箱即用能但需要 C 编程在 Python 中的作用主角负责所有 Redis 操作配角只负责加速响应解析是否需要改代码—不需要redis-py 自动识别并启用三、方案选择要不要装 hiredis3.1 只用 redis-py纯 Python 模式redis-py 自带一个纯 Python 实现的响应解析器功能完全够用。如果你的场景是数据量不大对延迟不敏感不想引入 C 扩展依赖那么只装 redis-py 就够了pipinstallredis3.2 redis-py hiredis加速模式如果你的场景是高并发每秒处理大量 Redis 命令需要解析大量数据比如HGETALL一个有几万个 field 的 Hash对响应时间有要求那就推荐安装 hiredispipinstallredis[hiredis]这个命令会同时安装 redis-py 和 hiredis而且 redis-py 会自动检测并启用hiredis 解析器无需任何代码改动。3.3 性能差距有多大hiredis 解析器相比纯 Python 解析器通常能带来2~10 倍的解析速度提升具体取决于响应数据的大小和复杂度。数据量越大、结构越复杂比如嵌套的数组hiredis 的优势越明显。不过要注意hiredis 只优化了响应解析这一环节。如果你的瓶颈在网络延迟或 Redis 本身的执行速度装 hiredis 的提升就不会那么显著。四、环境搭建与配置4.1 前置条件Python 3.12本文开发环境Redis 服务端 7.2推荐pip 包管理器4.2 关于 Python 版本的说明本文的开发环境基于Python 3.12选择这个版本有几个考量Python 3.12 的主要改进Python 3.12 是一个值得关注的版本带来了不少实质性的提升性能优化CPython 解释器本身的执行效率有了明显提升整体性能比 3.11 提升约 5%类型提示增强typing模块进一步完善支持更灵活的泛型写法错误信息更友好报错提示更加精准调试体验好了不少移除废弃模块distutils等老旧模块被正式移除对 redis-py 的影响结论完全兼容放心使用。redis-py 6.2.0 要求 Python 3.9Python 3.12 完全满足要求。而且 redis-py 的代码风格也在跟进新版 Python 的特性比如类型注解的写法更规范了。# 在 Python 3.12 环境下安装 redis-py没有任何兼容性问题pipinstallredis对 hiredis 的影响结论使用 hiredis 2.0 版本即可。hiredis 是 C 扩展包需要编译后才能在 Python 中使用。Python 3.12 对 C API 做了一些调整比如移除了一些废弃的 API所以 hiredis 需要相应更新才能兼容。好消息是hiredis 2.0 已经适配了 Python 3.12 的 C API 变化直接安装就行pipinstallredis[hiredis]如果你之前在旧版本 Python 下安装过 hiredis升级到 Python 3.12 后建议重新安装pipinstall--force-reinstallredis[hiredis]版本对应关系速查Python 版本redis-py 要求hiredis 建议版本兼容性3.9 ~ 3.11 6.2.0 1.0完全兼容3.12 6.2.0 2.0完全兼容推荐小提示如果你是新项目直接用 Python 3.12 redis-py 最新版 hiredis 2.0 就是最稳的组合。4.3 启动 Redis用 Docker 启动一个 Redis 实例最省事# Redis 8.0dockerrun-p6379:6379-itredis:latest# Redis 8.0 以下dockerrun-p6379:6379-itredis/redis-stack:latest4.4 安装 redis-py两种方式方式一只装 redis-pypipinstallredis方式二redis-py hiredis 加速推荐pipinstallredis[hiredis]安装完成后可以通过以下方式验证 hiredis 是否生效importredisprint(redis.__version__)# 查看 redis-py 版本# 检查 hiredis 是否可用try:importhiredisprint(fhiredis 版本:{hiredis.__version__})print(hiredis 解析器已启用性能加速生效)exceptImportError:print(hiredis 未安装使用纯 Python 解析器)4.5 建立连接redis-py 提供了多种连接方式从简单到复杂依次是直接连接importredis rredis.Redis(hostlocalhost,port6379,db0)带解码的连接推荐默认情况下redis-py 返回的是 bytes 类型如bTom。加上decode_responsesTrue后返回的就是 Python 字符串了rredis.Redis(hostlocalhost,port6379,db0,decode_responsesTrue)r.set(name,Tom)print(r.get(name))# 输出: Tom字符串print(type(r.get(name)))# class str使用连接池在生产环境中建议使用连接池来管理连接避免频繁创建和销毁连接的开销importredis# 创建连接池poolredis.ConnectionPool(hostlocalhost,port6379,db0,decode_responsesTrue,max_connections20# 最大连接数)# 从连接池获取连接rredis.Redis(connection_poolpool)五、实战redis-py 常用操作以下示例均基于 redis-py 官方文档使用decode_responsesTrue以便输出更直观。5.1 字符串操作importredis rredis.Redis(hostlocalhost,port6379,db0,decode_responsesTrue)# SET / GETr.set(name,Tom)print(r.get(name))# Tom# 设置过期时间秒r.setex(token,60,abc123)# 60 秒后自动删除# 自增操作r.set(counter,0)r.incr(counter)r.incr(counter)r.incr(counter)print(r.get(counter))# 35.2 哈希操作Hash 是 Redis 中最常用的结构之一特别适合存储对象# 存储用户信息r.hset(user:1001,mapping{name:Tom,age:25,city:Beijing})# 获取单个字段print(r.hget(user:1001,name))# Tom# 获取所有字段print(r.hgetall(user:1001))# {name: Tom, age: 25, city: Beijing}5.3 列表操作# 从右侧推入r.rpush(tasks,task1,task2,task3)# 获取列表长度print(r.llen(tasks))# 3# 获取指定范围的元素print(r.lrange(tasks,0,-1))# [task1, task2, task3]# 从左侧弹出print(r.lpop(tasks))# task15.4 集合操作# 添加元素r.sadd(tags:python,web,data,ai)r.sadd(tags:java,web,enterprise,android)# 集合交集共同标签print(r.sinter(tags:python,tags:java))# {web}# 集合并集print(r.sunion(tags:python,tags:java))# {web, data, ai, enterprise, android}5.5 Pipeline批量操作的利器当你需要一次性执行多条命令时Pipeline 能显著减少网络往返次数# 不用 Pipeline3 次网络往返r.set(a,1)r.set(b,2)r.set(c,3)# 使用 Pipeline1 次网络往返piper.pipeline()pipe.set(a,1)pipe.set(b,2)pipe.set(c,3)resultspipe.execute()print(results)# [True, True, True]Pipeline 的原理很简单它把多条命令打包在一起一次性发送给 Redis然后一次性接收所有响应。命令数量越多Pipeline 的优势越明显。5.6 Pub/Sub发布订阅# 创建一个独立的连接用于订阅pubsubr.pubsub()# 订阅频道pubsub.subscribe(notifications)# 在另一个进程/线程中发布消息# r.publish(notifications, Hello, everyone!)# 监听消息formessageinpubsub.listen():ifmessage[type]message:print(f收到消息:{message[data]})六、深入理解redis-py 如何自动启用 hiredis这是很多开发者好奇的地方——redis-py 是怎么感知到 hiredis 的存在的原理其实不复杂。redis-py 在初始化时会做一次检测尝试import hiredis如果导入成功且版本 1.0就使用 hiredis 的 C 语言解析器如果导入失败就退回到纯 Python 解析器这个过程对用户完全透明你不需要写任何额外代码。redis-py 的官方文档是这样说的For faster performance, install redis with hiredis support, this provides a compiled response parser, andfor most casesrequires zero code changes. By default, if hiredis 1.0 is available, redis-py will attempt to use it for response parsing.翻译过来就是装上 hiredis大多数情况下零代码改动redis-py 自动启用它。那什么时候需要手动控制极少数情况下你可能想强制使用纯 Python 解析器比如调试协议问题。这时候可以在创建连接时显式指定importredis# 强制使用纯 Python 解析器不推荐在生产环境使用rredis.Redis(hostlocalhost,port6379,db0)但在实际项目中几乎没有理由拒绝 hiredis——它是一个免费的性能提升没有副作用。七、版本兼容性速查在使用之前确认一下版本兼容性避免踩坑redis-py 版本与 Python 版本redis-py 版本Python 要求5.0Python 3.7最后支持5.1 ~ 6.1Python 3.86.2Python 3.9redis-py 版本与 Redis 服务端版本redis-py 版本支持的 Redis 版本3.5.3 6.2 4.5.05.0 ~ 7.0 5.0.05.0 ~ 7.4 6.0.07.2 ~ 当前hiredis 版本要求redis-py 要求hiredis 1.0低于此版本不会被自动启用。当前 hiredis 的稳定版是 1.x 系列直接pip install hiredis装到的就是满足要求的版本。八、常见问题与注意事项Q1装了 hiredis 之后代码需要改吗不需要。这是 redis-py 设计的初衷——hiredis 是一个透明的加速层对上层 API 没有任何影响。Q2hiredis 装不上怎么办hiredis 是一个 C 扩展包安装时需要编译。如果你在 Windows 上遇到编译错误# 确保安装了 Visual C Build Tools# 或者使用预编译的 wheelpipinstallhiredis --only-binary:all:在 Linux/macOS 上一般不会有问题系统自带的 GCC/Clang 就能编译。Q3redis-py 的 RESP3 协议支持是什么从 redis-py 5.0 开始支持 RESP3 协议Redis 6.0 引入的新协议。RESP3 相比 RESP2 支持更多数据类型如布尔值、双精度浮点数、Map 等。redis-py 8.0 之后默认使用 RESP3 传输但为了兼容性响应格式仍然保持 RESP2 的风格。如果你是新项目可以显式启用rredis.Redis(hostlocalhost,port6379,db0,legacy_responsesFalse)Q4连接池的最大连接数怎么设置一般的经验公式max_connections 并发线程数 预留余量比如你有 10 个工作线程设置 15~20 就够了。设太大会浪费 Redis 端的连接资源。九、总结回到文章开头的问题redis-py 和 hiredis 到底是什么关系用一句话概括redis-py 是 Python 操作 Redis 的主力hiredis 是给它加装的涡轮增压。几个核心要点redis-py是完整的 Python Redis 客户端能独立使用覆盖所有 Redis 命令hiredis是 C 语言实现的高效协议解析器不直接给 Python 开发者用而是作为底层引擎两者结合使用时redis-py 负责上层 APIhiredis 负责底层解析加速安装方式pip install redis[hiredis]零代码改动即可获得性能提升hiredis 只加速响应解析环节如果瓶颈在网络或 Redis 本身效果有限最佳实践建议场景建议学习 / 原型开发只装 redis-py 就够了生产环境 / 高并发强烈推荐 redis-py hiredis需要 RESP3 特性redis-py 5.0推荐搭配 hiredisWindows 开发环境优先用--only-binary安装 hiredis十、参考文档redis-py 官方仓库https://github.com/redis/redis-pyredis-py 官方文档https://redis.readthedocs.io/en/stable/hiredis 官方仓库https://github.com/redis/hiredisRedis 官方命令文档https://redis.io/commandsRESP3 协议规范https://github.com/antirez/RESP3/blob/master/spec.mdRedis University 免费课程https://redis.io/learn/university写在最后技术选型这件事不是越新越好或越快越好而是适合的才是最好的。redis-py hiredis 的组合本质上就是在开发便利性和运行性能之间找到了一个很好的平衡点。希望这篇文章能帮你把这个知识点串起来下次遇到 Redis 性能优化的时候多一个可选方案。