Redis Timeseries读取时序数据慢于Pandas读CSV的问题排查
Redis Timeseries读取速度慢于本地CSV问题排查
问题现象
使用Redis Timeseries存储时序数据时,读取同一份数据集的速度远慢于Python Pandas读取本地CSV文件的速度,通过控制变量的最小可复现示例验证,该现象稳定存在。
测试复现逻辑
测试流程如下:
- 生成由Unix时间戳、2位精度随机浮点数组成的测试数据集
- 将完全相同的数据分别写入本地CSV文件与Redis Timeseries
- 仅统计读取环节的耗时,不考量写入性能差异
测试代码:
import csv from datetime import datetime from random import randrange, uniform from datetime import timedelta import redis import pandas as pd import time def random_date(start, end): delta = end - start int_delta = (delta.days * 24 * 60 * 60) + delta.seconds random_second = randrange(int_delta) return start + timedelta(seconds=random_second) with open('justcsv.csv', mode='w', newline='') as file: file_writer = csv.writer( file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) # 初始化Redis连接 r = redis.Redis(host="localhost", port="6379") r.flushall() # 创建时序键 r_tsname = "TESTKEY" label = { "label" : r_tsname} key_name = "TESTKEY1" r.ts().create(key_name, labels=label) # 定义随机时间生成范围 d1 = datetime.strptime('1/1/2008 1:30 PM', '%m/%d/%Y %I:%M %p') d2 = datetime.strptime('1/1/2022 4:50 AM', '%m/%d/%Y %I:%M %p') # 循环生成并写入测试数据 for x in range(30000): dt = random_date(d1, d2) timestamp = int(dt.timestamp()) random_number = round(uniform(1.5, 1000.9), 2) # 写入CSV file_writer.writerow([timestamp, random_number]) # 写入Redis Timeseries r.ts().add(key_name, timestamp, random_number) # 统计Pandas读取CSV耗时 start_csv = time.time() df = pd.read_csv('justcsv.csv') end_csv = time.time() print(f"CSV READING TIME IS: {end_csv-start_csv}") # 统计Redis Timeseries读取耗时 start_redis = time.time() full_range = r.ts().range("TESTKEY1", "-", "+") end_redis = time.time() print(f"REDIS READING TIME IS: {end_redis-start_redis}")
基准测试结果
测试使用官方最新版Redis Timeseries Docker镜像部署服务,不同数据量下的耗时对比如下:
10000条数据 - Redis读取速度慢2倍 CSV READING TIME IS: 0.0124 REDIS READING TIME IS: 0.052 20000条数据 - Redis读取速度慢4倍 CSV READING TIME IS: 0.025 REDIS READING TIME IS: 0.102 30000条数据 - Redis读取速度慢10倍 CSV READING TIME IS: 0.0139 REDIS READING TIME IS: 0.153
测试过程中观测到的固定现象:
- 直接通过redis-cli执行查询命令,读取耗时无明显下降
- 两者的读取耗时差距随数据量增长持续拉大
核心疑问
- Redis Timeseries作为专门面向时序场景设计的内存存储结构,读取速度远慢于本地磁盘CSV读取的根本原因是什么?
- 当前的测试逻辑、使用方式是否存在配置错误或者逻辑疏漏?
- 有哪些可落地的优化方案可以提升Redis Timeseries的读取性能?
问题解答
1. 读取速度偏慢的根本原因
结果反常识的核心是两个普遍存在的认知偏差:
- 所有Redis操作都自带固定的网络与协议解析开销:哪怕Redis部署在本地,客户端和服务端之间的TCP通信、RESP协议序列化/反序列化成本是刚性存在的,全量拉取数万条数据时这部分开销占比极高。而Pandas读本地CSV是进程内操作,小文件会被操作系统直接缓存在页缓存中,本质是读内存,没有额外网络交互成本,你默认的"磁盘读比内存慢"的前提在这个场景下根本不成立。
- 两边的解析效率存在数量级差距:
TS.RANGE默认会将所有时序点以(时间戳, 值)的二元组结构逐条序列化返回,Python客户端收到响应后需要在Python解释器层逐行解析成原生元组对象,这个过程是O(n)线性开销,数据量越大成本越高;而Pandas读CSV的逻辑是C语言实现的批量解析,直接把整块文件内容一次性转成连续内存存储的DataFrame结构,解析效率比Python层逐行处理高一个量级。 - 测试数据量太小,远没到磁盘IO成为瓶颈的阈值:3万行的CSV文件大小仅几百KB,操作系统第一次读取后就会完整缓存到内存,后续读取完全不碰磁盘,本质和Redis一样是内存读取,比Redis多省了网络和跨进程交互的成本,速度自然更快。
2. 当前测试与使用方式的疏漏
现有测试逻辑存在多处不对等的问题,结果参考性有限:
- 数据写入逻辑不对等:测试用的时间戳是完全随机生成的乱序数据,Redis Timeseries写入乱序数据时会在后台做块整理、排序合并,读取时需要遍历多个非连续块;而CSV是按生成顺序逐行写入,Pandas读取时不会做任何时间排序处理,两边的处理成本不对等。
- 没有做预热排除干扰:CSV读取直接命中操作系统页缓存,而Redis侧是写完立刻读取,没有排除服务端后台压缩、索引构建任务对读取耗时的影响。
- 读取后的数据结构不对等:Redis返回的是Python原生元组组成的列表,每个元素都是独立的Python对象,内存碎片化严重;而Pandas返回的是连续内存的DataFrame结构,本身的访问和解析开销就低很多。
- 没有用到Redis Timeseries的优化参数:
TS.RANGE默认没有开启批量优化,返回数据的冗余度高,没有发挥出时序结构的压缩优势。
3. 可落地的读取性能优化方案
可以从几个维度调整,将读取性能提升数倍:
- 开启传输压缩:Redis客户端连接时开启LZ4等压缩算法,大幅降低网络传输的payload大小,万级以上数据点场景下传输耗时可降低60%以上。
- 调整时序键的块配置:创建时序键时将
CHUNK_SIZE参数从默认的4KB调整为16KB或32KB,减少数据块的总数量,降低范围查询时的块遍历开销。 - 合理使用查询参数:大结果集场景下用
TS.MRANGE配合COUNT参数分批拉取,避免单次返回过大响应导致服务端和客户端的序列化阻塞;不要每次都拉全量数据,尽量配合时间范围做增量查询。 - 减少客户端侧计算:如果需要做聚合计算,优先在Redis侧通过时序引擎自带的降采样、聚合能力直接返回计算结果,不要把全量原始数据拉到客户端再处理。
- 降低网络开销:部署时尽量让客户端和Redis服务端在同节点,用Unix Domain Socket连接替代TCP连接,可砍掉一半以上的网络IO开销。
- 写入时尽量按时间戳顺序写入,减少乱序数据导致的后台块合并开销,提升查询时的块扫描效率。
内容的提问来源于stack exchange,提问作者user840718
相关产品推荐
相关产品推荐

