购物商城网站的运营,用户体验设计师是干嘛,wordpress百度地图页,怎么做简单的视频网站TDengine 数据缓存架构及使用详解
一、设计理念
TDengine 采用**写驱动缓存#xff08;Write-driven Cache#xff09;**设计#xff0c;与传统数据库的读驱动缓存截然不同。核心思想是#xff1a;时序数据场景下#xff0c;最新写入的数据往往是最频繁查询的数据。
传…TDengine 数据缓存架构及使用详解一、设计理念TDengine 采用**写驱动缓存Write-driven Cache**设计与传统数据库的读驱动缓存截然不同。核心思想是时序数据场景下最新写入的数据往往是最频繁查询的数据。传统缓存 vs TDengine 缓存传统数据库读驱动缓存: 查询什么 → 缓存什么 ↓ 问题冷数据占用缓存空间 问题缓存命中率不稳定 TDengine写驱动缓存: 写入什么 → 缓存什么 ↓ 优势最新数据始终在缓存 优势最新数据查询命中率 99% 优势可替代 Redis 等缓存中间件二、缓存架构总览┌─────────────────────────────────────────────────────────┐ │ TDengine 多级缓存架构 │ ├─────────────────────────────────────────────────────────┤ │ │ │ ┌────────────────────────────────────────────────┐ │ │ │ L1: 写入缓存 (Write Buffer) │ │ │ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │ │ │ │ Block1 │ │ Block2 │ │ Block3 │ (轮转使用) │ │ │ │ │(写入中)│ │(待落盘)│ │(落盘中)│ │ │ │ │ └────────┘ └────────┘ └────────┘ │ │ │ │ 数据结构: SkipList Red-Black Tree │ │ │ │ 作用: 接收写入 缓存最新数据 │ │ │ └────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────┐ │ │ │ L2: 元数据缓存 (Meta Cache) │ │ │ │ - 表 Schema 信息 │ │ │ │ - 标签信息 │ │ │ │ - vgroup 路由信息 │ │ │ │ 数据结构: BTree LRU │ │ │ │ 作用: 加速表查找和标签过滤 │ │ │ └────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────┐ │ │ │ L3: Last/Last_Row 缓存 │ │ │ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ │ │ Last 缓存 │ │ Last_Row 缓存 │ │ │ │ │ │ (每列最新值) │ │ (最后一条记录) │ │ │ │ │ └─────────────┘ └─────────────────┘ │ │ │ │ 数据结构: LRU 延迟加载 │ │ │ │ 作用: 加速 LAST/LAST_ROW 查询 │ │ │ └────────────────────────────────────────────────┘ │ │ ↓ │ │ ┌────────────────────────────────────────────────┐ │ │ │ L4: 页面缓存 (Page Cache) │ │ │ │ - 数据页缓存 │ │ │ │ - 索引页缓存 │ │ │ │ 数据结构: Hash LRU │ │ │ │ 作用: 加速磁盘数据访问 │ │ │ └────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘三、核心缓存机制详解3.1 写入缓存 (Write Buffer)设计原理采用多块内存轮转机制实现写入与落盘并行内存块轮转机制: 时刻 T1: [Block1: 写入中] → [Block2: 空闲] → [Block3: 空闲] 时刻 T2 (Block1 写满 1/3): [Block1: 待落盘] → [Block2: 写入中] → [Block3: 空闲] ↓ 触发 Block1 落盘后台线程 时刻 T3 (Block1 落盘完成): [Block1: 空闲] → [Block2: 写入中] → [Block3: 空闲] 优势: ✓ 写入永不阻塞 ✓ 始终保持 1/3 内存缓存最新数据 ✓ 落盘与写入并行执行源码实现基于 SkipList// 数据写入流程写入数据 ↓ 查找目标表的 SkipListO(log n) ↓ 插入数据到 SkipList按时间排序 ↓ 更新统计信息 ↓ 检查内存块使用率 ↓ 超过阈值 → 触发落盘配置参数-- 创建数据库时配置写入缓存CREATEDATABASEsensor_db BUFFER256-- 每个 vnode 的写缓存大小MBPAGES128-- 元数据缓存页数PAGESIZE4;-- 每页大小KB-- 参数说明:-- BUFFER: 写入缓存总大小越大可缓存越多最新数据-- PAGES × PAGESIZE 元数据缓存大小3.2 Last/Last_Row 缓存设计原理专门为时序数据的查询最新值场景优化Last 缓存: ┌─────────────────────────────────────────┐ │ sensor_001: │ │ temperature: (ts2024-01-15 12:00, 25.5)│ │ humidity: (ts2024-01-15 12:00, 60) │ │ pressure: (ts2024-01-15 11:55, 101) │ ← 各列可能时间不同 └─────────────────────────────────────────┘ Last_Row 缓存: ┌─────────────────────────────────────────┐ │ sensor_001: │ │ 最后一行: (ts2024-01-15 12:00, │ │ temperature25.5, │ │ humidity60, │ │ pressureNULL) ← 该行可能有 NULL│ └─────────────────────────────────────────┘ 区别: - LAST(col): 返回每列最后一个非 NULL 值时间可能不同 - LAST_ROW(*): 返回表中最后一条记录可能含 NULL配置方式-- 方式1: 创建数据库时配置CREATEDATABASEsensor_db CACHEMODELboth-- 启用 last 和 last_row 缓存CACHESIZE10;-- 缓存大小MB-- CACHEMODEL 选项:-- none: 不启用缓存-- last_row: 只缓存 last_row-- last_value: 只缓存 last-- both: 同时缓存两者推荐-- 方式2: 修改已有数据库ALTERDATABASEsensor_db CACHEMODELboth;ALTERDATABASEsensor_db CACHESIZE20;查询加速效果-- 无缓存时SELECTLAST(temperature)FROMsensor_001;执行: 扫描数据文件 → 找到最后非NULL值 耗时:10-100ms-- 有缓存时SELECTLAST(temperature)FROMsensor_001;执行: 直接从Last缓存返回 耗时:1ms 性能提升:100x3.3 元数据缓存 (Meta Cache)设计原理基于 BTree LRU 的元数据管理// 源码结构 (tdbPCache.c)structSPCache{intszPage;// 页面大小intnPages;// 总页面数SPage**aPage;// 页面数组tdb_mutex_tmutex;// 并发锁intnFree;// 空闲页面数SPage*pFree;// 空闲链表intnHash;// 哈希表大小SPage**pgHash;// 页面哈希表intnRecyclable;// 可回收页面数SPage lru;// LRU 链表头};缓存页面生命周期页面状态流转: [空闲列表] → 分配 → [活跃使用] ↓ 引用计数归零 [LRU 队列] ↓ 空间不足时回收 [空闲列表] 关键操作: 1. Fetch: 从缓存获取页面命中或从磁盘加载 2. Pin: 固定页面防止被回收 3. Unpin: 释放固定允许回收 4. Release: 减少引用计数3.4 页面缓存实现细节哈希查找 LRU 淘汰// 页面查找流程 (简化)SPage*tdbPCacheFetchImpl(SPCache*pCache,constSPgid*pPgid){// 1. 计算哈希值uint32_thtdbPCachePageHash(pPgid)%pCache-nHash;// 2. 在哈希表中查找SPage*pPagepCache-pgHash[h];while(pPage){if(pPage-pgid.pgnopPgid-pgnomemcmp(pPage-pgid.fileid,pPgid-fileid,TDB_FILE_ID_LEN)0)break;pPagepPage-pHashNext;}// 3. 命中从 LRU 移除Pin 住if(pPage){tdbPCachePinPage(pCache,pPage);returnpPage;}// 4. 未命中从空闲列表或 LRU 获取页面if(pCache-pFree){pPagepCache-pFree;pCache-pFreepPage-pFreeNext;}elseif(!pCache-lru.pLruPrev-isAnchor){// 从 LRU 尾部回收pPagepCache-lru.pLruPrev;tdbPCacheRemovePageFromHash(pCache,pPage);}// 5. 加载数据并加入哈希表// ...returnpPage;}四、缓存优化最佳实践4.1 ✅ 推荐配置场景1高频实时查询IoT 监控-- 最新数据查询频繁需要大缓存CREATEDATABASEiot_monitor BUFFER512-- 大写入缓存512MBCACHEMODELboth-- 启用双缓存CACHESIZE100-- Last 缓存 100MBPAGES256-- 元数据缓存页数PAGESIZE4;-- 4KB 页面-- 适用场景:-- - 设备状态实时监控-- - 最新数据仪表盘展示-- - 实时告警系统场景2历史数据分析数据仓库-- 历史查询为主缓存可以小一些CREATEDATABASEdata_warehouse BUFFER128-- 中等写入缓存CACHEMODELnone-- 不需要 Last 缓存PAGES512-- 大元数据缓存历史表多PAGESIZE4;-- 适用场景:-- - 历史数据报表-- - 批量数据分析-- - 数据归档存储场景3混合负载通用场景-- 平衡配置CREATEDATABASEmixed_workload BUFFER256CACHEMODELbothCACHESIZE50PAGES256PAGESIZE4;4.2 ✅ 加速查询的技巧1. 利用 LAST_ROW 替代 ORDER BY LIMIT-- ❌ 慢需要排序SELECT*FROMsensor_001ORDERBYtsDESCLIMIT1;-- ✅ 快直接从缓存返回SELECTLAST_ROW(*)FROMsensor_001;性能提升:100x2. 使用 LAST 获取各列最新值-- ❌ 慢多次查询SELECT(SELECTtemperatureFROMsensor_001ORDERBYtsDESCLIMIT1)astemp,(SELECThumidityFROMsensor_001ORDERBYtsDESCLIMIT1)ashum;-- ✅ 快一次查询命中缓存SELECTLAST(temperature),LAST(humidity)FROMsensor_001;性能提升:50x3. 批量获取多表最新值-- ✅ 高效利用 Last 缓存SELECTtbname,LAST(temperature),LAST(humidity)FROMsensorsWHERElocation北京GROUPBYtbname;-- 执行过程:-- 1. 标签过滤内存操作毫秒级-- 2. 每张表从 Last 缓存获取值-- 3. 组装返回结果-- 1000 张表查询耗时: 100ms4. 实时数据展示优化-- ✅ 推荐最近 N 分钟数据命中写入缓存SELECT*FROMsensor_001WHEREtsNOW-10m;-- 执行过程:-- 1. 检查写入缓存MemTable-- 2. 大部分数据在内存中命中-- 3. 少量数据可能需要读磁盘-- 缓存命中率: 90%4.3 ❌ 要避免的误区1. 避免不合理的缓存配置-- ❌ 差缓存太小写入频繁落盘CREATEDATABASEsensor_db BUFFER16;-- 问题:-- - 频繁触发落盘-- - 写入性能下降-- - 最新数据缓存命中率低-- ✅ 好根据写入量配置-- 计算公式: BUFFER 写入速率 × 期望缓存时间-- 例如: 10MB/s × 30s 300MBCREATEDATABASEsensor_db BUFFER300;2. 避免未启用 Last 缓存却频繁查询最新值-- ❌ 差未启用缓存CREATEDATABASEsensor_db CACHEMODELnone;-- 然后频繁执行SELECTLAST(temperature)FROMsensor_001;-- 每次都读磁盘-- ✅ 好启用缓存ALTERDATABASEsensor_db CACHEMODELboth;3. 避免 CACHESIZE 设置过小-- ❌ 差缓存太小频繁淘汰CREATEDATABASEsensor_db CACHEMODELbothCACHESIZE1;-- 只有 1MB-- 问题:-- - 10000 张表每表缓存条目约 100 字节-- - 1MB 只能缓存约 10000 条-- - 频繁 LRU 淘汰缓存命中率低-- ✅ 好根据表数量配置-- 计算公式: CACHESIZE 表数量 × 0.001 MB-- 例如: 100000 张表 → CACHESIZE 100CREATEDATABASEsensor_db CACHEMODELbothCACHESIZE100;4. 避免用 SELECT * 查询最新数据-- ❌ 差SELECT * 可能不走缓存SELECT*FROMsensor_001ORDERBYtsDESCLIMIT1;-- ✅ 好使用专用函数SELECTLAST_ROW(*)FROMsensor_001;-- 或SELECTLAST(col1),LAST(col2),...FROMsensor_001;五、性能监控与调优5.1 查看缓存配置-- 查看数据库缓存配置SHOWDATABASES;-- 查看详细参数SELECT*FROMinformation_schema.ins_databasesWHEREnamesensor_db;-- 关注字段:-- buffer: 写入缓存大小-- cachemodel: 缓存模式-- cachesize: Last 缓存大小-- pages: 元数据缓存页数5.2 动态调整缓存-- 增大 Last 缓存ALTERDATABASEsensor_db CACHESIZE200;-- 修改缓存模式ALTERDATABASEsensor_db CACHEMODELboth;-- 注意: BUFFER 和 PAGES 创建后不可修改5.3 内存使用估算总内存使用 ≈ vnode数 × BUFFER vnode数 × PAGES × PAGESIZE CACHESIZE 系统开销 示例计算: - 4 个 vnode - BUFFER 256MB - PAGES 128, PAGESIZE 4KB - CACHESIZE 50MB 总计 ≈ 4×256 4×128×0.004 50 100 ≈ 1024 2 50 100 ≈ 1176 MB六、缓存与其他数据库对比特性TDengineMySQLRedis缓存驱动写驱动读驱动读驱动最新数据命中99%不确定需要应用层维护专用函数LAST/LAST_ROW无无缓存一致性自动保证需要应用层处理需要应用层处理内存效率高中高配置复杂度低中高七、总结TDengine 缓存核心优势✅写驱动设计最新数据自动缓存命中率 99%✅多级缓存写入缓存 元数据缓存 Last 缓存 页面缓存✅专用优化LAST/LAST_ROW 函数直接利用缓存✅配置简单几个参数即可完成优化✅自动管理无需应用层处理缓存一致性性能提升效果查询类型无缓存有缓存提升LAST_ROW10-50ms 1ms100xLAST10-100ms 1ms100x最近时间范围50-200ms5-20ms10x元数据查询10-50ms 1ms50x最佳实践速查-- 高频实时查询场景CREATEDATABASEiot_db BUFFER512CACHEMODELbothCACHESIZE100PAGES256PAGESIZE4;-- 查询最新数据SELECTLAST_ROW(*)FROMtable_name;SELECTLAST(col1),LAST(col2)FROMtable_name;-- 查询最近数据命中写入缓存SELECT*FROMtable_nameWHEREtsNOW-10m;TDengine 的缓存机制是其高性能的关键因素之一通过合理配置和正确使用可以实现毫秒级最新数据查询大幅提升时序数据应用的用户体验。关于 TDengineTDengine 专为物联网IoT平台、工业大数据平台设计。其中TDengine TSDB 是一款高性能、分布式的时序数据库Time Series Database同时它还带有内建的缓存、流式计算、数据订阅等系统功能TDengine IDMP 是一款AI原生工业数据管理平台它通过树状层次结构建立数据目录对数据进行标准化、情景化并通过 AI 提供实时分析、可视化、事件管理与报警等功能。