Redis 不只是缓存:深入解析 Redis Stack 与实时 AI 推理
很多人对 Redis 的印象还停留在“高速缓存”或“键值数据库”,这当然没错,但这个认知已经过时了。今天的 Redis,尤其是在 Redis Stack 的加持下,早已成为一个功能强大的多模型数据库,能处理从全文搜索到图数据,再到实时 AI 推理等一系列复杂任务。
作为一名技术从业者,我经常被问到:“Redis Stack 和 Redis server 有什么区别?”、“用 Redis 来做 AI 推理靠谱吗?性能怎么样?”。今天,我就以一个技术的视角,带大家深入剖析这些问题。
Redis server:万物之基
我们首先从 Redis server 谈起。它是所有 Redis 产品的核心,一个开源、内存中的数据结构存储系统。它的强大之处在于:
-
极简而高效: 提供了字符串、哈希、列表、集合和有序集合等基础数据结构,这些结构都是为了性能而设计,每个操作都在毫秒甚至微秒级别完成。
-
原子操作: 每个命令都是原子性的,这对于构建并发系统至关重要。你无需担心在多线程环境下会出现竞态条件。
-
持久化: RDB 和 AOF 机制确保数据在断电后不会丢失,兼顾了性能和可靠性。
可以说,Redis server 就是一个为速度而生的精简版瑞士军刀,是构建高性能应用的基础。但它也有局限性,例如不具备原生全文搜索、复杂文档处理或图形计算的能力。
Redis Stack:能力的聚变
然而,现代应用的需求远超简单的键值存储。当我们需要处理 JSON 文档、构建全文搜索引擎,或者分析时间序列数据时,原生 Redis 的能力就显得捉襟见肘。
Redis Stack 应运而生,它并非一个全新的产品,而是在 Redis server 的基础上,预先集成了多个官方开发的高级功能模块。你可以把它看作是一个“Redis server + 全家桶”,其中包含了:
-
RediSearch: 强大的全文搜索引擎,支持多语言、模糊查询、聚合等,让 Redis 也能像 Elasticsearch 那样进行高效搜索。
-
RedisJSON: 原生支持 JSON 数据类型,可以直接在 Redis 内部操作复杂的 JSON 文档,例如通过 JSONPath 查询和更新嵌套字段。
-
RedisGraph: 图数据库模块,用 Redis 来存储和查询图数据,支持 Cypher 查询语言,用于社交网络、推荐引擎等场景。
-
RedisTimeSeries: 专为时间序列数据优化,适用于 IoT 和监控场景,支持数据聚合、下采样和范围查询。
-
RedisBloom: 提供布隆过滤器等概率数据结构,用极小的内存处理大规模数据,常用于去重和存在性校验。
-
RedisAI: **今天的重点!**它让 Redis 具备了直接进行 AI 推理的能力。
结论很明确: 如果你只追求基础的缓存或键值存储,选择 Redis server 即可。但如果你想利用 Redis 的速度和内存优势,去处理更复杂的数据模型和业务逻辑,那么 Redis Stack 无疑是更高效、更具扩展性的选择。
RedisAI:把 AI 推理搬进数据库
现在,我们来聊聊最前沿的话题:RedisAI。
传统的实时 AI 推理架构通常是这样的:应用层从数据库(如 Redis)读取数据,然后通过网络将数据发送到一个独立的推理服务(如 TensorFlow Serving 或 TorchServe),推理服务计算出结果后再返回给应用层。这个过程中,网络延迟是最大的瓶颈。
RedisAI 彻底颠覆了这种模式。它的核心思想是:让计算尽可能地靠近数据。
整个实现过程可以拆解为三个步骤。这里我们以一个简单的图像分类任务为例,假设我们使用一个 ONNX 格式的预训练模型。
1. 模型入库 (AI.MODELSET
)
首先,你需要将训练好的模型文件加载到 Redis 的内存中。这通常通过 PHP 的 Redis 客户端完成。
注意:在运行以下代码之前,请确保你已经安装并启用了 phpredis
扩展
<?php$redis = new Redis();
$redis->connect('127.0.0.1', 6379);//ONNX模型文件'model.onnx'
$model_blob = file_get_contents('model.onnx');// 使用 AI.MODELSET 将模型加载到 Redis
// 参数: key, backend, device, inputs, outputs, blob
// 'input_tensor'和'output_tensor'是模型定义的输入输出名称
// [1, 3, 224, 224] 是模型的输入张量形状
try {$redis->rawCommand('AI.MODELSET', 'my_image_classifier','ONNX', 'CPU','INPUTS', 1, 'input_tensor', [1, 3, 224, 224],'OUTPUTS', 1, 'output_tensor', [1, 1000],'BLOB', $model_blob);echo "模型已成功加载到 Redis。\n";
} catch (Exception $e) {echo "加载模型失败: " . $e->getMessage() . "\n";
}?>
2. 数据入库 (AI.TENSORSET
)
接下来,将用于推理的输入数据,例如一张处理后的图片,转换为一个张量,并存储到 Redis 中。我们需要将 PHP 数组转换为 RedisAI 可识别的二进制格式。
<?php$redis = new Redis();
$redis->connect('127.0.0.1', 6379);/*** 将图像文件处理为 RedisAI 张量格式的二进制数据* @param string $image_path 图像文件路径* @return string 处理后的张量二进制数据*/
function getImageTensorBlob($image_path) {if (!file_exists($image_path)) {throw new Exception("图像文件不存在: " . $image_path);}//加载并调整图像大小 记得安装Imagick扩装$imagick = new Imagick($image_path);$imagick->resizeImage(224, 224, Imagick::FILTER_LANCZOS, 1, true);$imagick->stripImage(); // 移除元数据以减小大小//将图像转换为 RGB 像素数组$pixels = $imagick->exportImagePixels(0, 0, 224, 224, 'RGB', Imagick::PIXEL_CHAR);// RedisAI 通常需要浮点数格式,将每个像素值从 0-255 归一化到 0.0-1.0$tensor_array = [];foreach ($pixels as $pixel_value) {// 将字符值转换为浮点数并归一化$tensor_array[] = ord($pixel_value) / 255.0;}//将浮点数数组打包为二进制字符串$tensor_blob = '';foreach ($tensor_array as $value) {$tensor_blob .= pack('f', $value);}return $tensor_blob;
}$image_path = 'cat.jpg'; try {//获取二进制数据$image_tensor_blob = getImageTensorBlob($image_path);// 获取张量的形状 (224x224x3)$shape = [224, 224, 3];// 使用 AI.TENSORSET 将张量数据存储到 Redis$redis->rawCommand('AI.TENSORSET', 'input_image_tensor','FLOAT', ...$shape, // 使用 '...' 解包数组作为可变参数'BLOB', $image_tensor_blob);echo "图像张量已成功存储到 Redis。\n";} catch (Exception $e) {echo "发生错误: " . $e->getMessage() . "\n";
}?>
3. 内部分析 (AI.MODELRUN
)
最后,调用 AI.MODELRUN
命令执行推理。RedisAI 会在内部将输入张量传递给模型,执行计算,并将结果存储到另一个张量键中。
<?php// 执行模型推理
try {$redis->rawCommand('AI.MODELRUN', 'my_image_classifier','INPUTS', 1, 'input_image_tensor','OUTPUTS', 1, 'output_result_tensor');echo "模型推理已完成。\n";
} catch (Exception $e) {echo "执行推理失败: " . $e->getMessage() . "\n";die();
}// 获取推理结果张量
$result_tensor_blob = $redis->rawCommand('AI.TENSORGET', 'output_result_tensor', 'BLOB');// 将二进制数据解包为 PHP 浮点数数组
$result_array = unpack('f*', $result_tensor_blob);echo "推理完成,结果张量:\n";
print_r($result_array);// 假设模型输出是1000个类别的分数,你可以找到分数最高的类别
$predicted_class = array_keys($result_array, max($result_array))[0] - 1; // 索引从1开始,需要-1
echo "预测类别索引为:" . $predicted_class . "\n";?>
总结
RedisAI 的核心思想是数据本地化:让计算尽可能地靠近数据。通过将 AI 模型和输入数据都存储在 Redis 中,它极大地减少了数据传输的开销,从而实现了超低延迟的实时 AI 推理。
RedisAI 带来的巨大价值在于:
-
极低延迟: 推理计算在 Redis 进程内部完成,完全消除了网络传输带来的延迟,这对于广告推荐、金融风控、实时监控等毫秒必争的场景至关重要。
-
架构简化: 你不再需要维护一个独立的推理服务集群,也不用担心数据同步问题。所有操作都在一个统一的平台上完成。
-
原子性保障: 结合 Redis 的事务和 Lua 脚本,你可以将数据准备、推理和结果处理打包成一个不可分割的原子操作,确保业务逻辑的严谨性。
当然,RedisAI 并非适用于所有场景。对于模型体积巨大或对 GPU 算力有极致需求的复杂模型(如生成式 AI),独立的推理服务依然是更合适的选择。但对于那些需要低延迟、高并发的实时推荐、风控、模式识别等轻量级推理任务,RedisAI 提供了一个颠覆性的、极具吸引力的解决方案。
现在,你对 Redis 的认知是不是又刷新了?不妨下载 Redis Stack,亲手体验一下它的强大吧!