【SkyWalking从入门到精通】第49篇:SkyWalking存储模型全景图:四大模型如何撑起海量观测数据

发布时间:2026/7/14 8:16:59
【SkyWalking从入门到精通】第49篇:SkyWalking存储模型全景图:四大模型如何撑起海量观测数据 上一篇【第48篇】OAP集群规划实战从理论到生产的容量设计下一篇【第50篇】注册模型与明细模型名字的管家和现场的记录官一、开篇不是所有的数据都叫观测数据APM系统要存储的数据五花八门——服务名、Trace ID、响应时间、HTTP状态码、JVM指标、调用拓扑……如果像NoSQL那样用一个万能JSON把什么都往里塞查询性能会惨不忍睹。SkyWalking的设计者做了一个聪明的分类把所有数据按使用方式分成四大类型每种类型用专门的存储结构和优化策略。这就是四大存储模型的由来。APM数据 | | 按怎么用来分类 v ------------ | | | | | v v v v v 注册 明细 指标 采样 模型 模型 模型 模型 查得少 查得多 查得多 查得少 写得少 写得多 读得频繁 按需获取 小体积 大体积 小体积 大体积 永久 有限TTL 有限TTL 有限TTL 图1四大模型对APM数据的分类策略二、四种模型的特征速览维度注册模型明细模型指标模型采样模型存储内容服务名、端点名等实体Trace/Span明细聚合后的数值指标慢查询/异常堆栈数据量很小千级极大亿级/天中等万级/天小按规则触发写频率极低几乎不变极高实时中分钟级低按需读频率高Dashboard常查低问题排查时极高Dashboard低问题排查时保留周期永久7-14天分钟30天/小时90天/天180天7-14天典型大小KB级GB-TB级MB-GB级MB级三、注册模型Register Model3.1 解决什么问题当探针上报一个Span说这是user-service调用了order-service的/createOrder接口OAP需要把这些名字存起来。但每次Span都带完整名字太浪费于是SkyWalking做了一层名字到ID的映射name user-service -- serviceId 1 name order-service -- serviceId 2 name /createOrder -- endpointId 1013.2 注册模型的类结构// 注册模型 - 服务注册Stream(nameservice_inventory,scopeId0)publicclassServiceInventoryextendsRegisterSource{Column(columnNameservice_id)IDColumnprivateintserviceId;// 服务ID主键Column(columnNamename)NeedDefaultprivateStringname;// 服务名称Column(columnNameis_address)privateintisAddress;// 是否是地址Column(columnNameproperties)privateStringproperties;// 自定义属性}// 注册模型 - 端点注册Stream(nameendpoint_inventory,scopeId0)publicclassEndpointInventoryextendsRegisterSource{Column(columnNameendpoint_id)IDColumnprivateintendpointId;// 端点IDColumn(columnNameservice_id)privateintserviceId;// 所属服务IDColumn(columnNamename)privateStringname;// 端点名称Column(columnNamedetect_point)privateintdetectPoint;// 探测点类型}// 注册模型 - 网络地址注册Stream(namenetwork_address_inventory,scopeId0)publicclassNetworkAddressInventoryextendsRegisterSource{Column(columnNameaddress_id)IDColumnprivateintaddressId;Column(columnNamename)privateStringname;}四、明细模型Record Model4.1 解决什么问题明细模型存储的是原始证据——每一条Trace、每一个Span的完整信息。当需要排查问题时这些现场的细节是必不可少的。4.2 明细模型示例// 明细模型 - Segment记录一个Trace的完整记录Stream(namesegment,scopeId1)publicclassSegmentRecordextendsRecord{Column(columnNamesegment_id)IDColumnprivateStringsegmentId;// Segment唯一IDColumn(columnNametrace_id)privateStringtraceId;// 所属Trace IDColumn(columnNameservice_id)privateintserviceId;// 服务IDColumn(columnNameservice_instance_id)privateintserviceInstanceId;// 实例IDColumn(columnNameendpoint_id)privateintendpointId;// 端点IDColumn(columnNamestart_time)privatelongstartTime;// 开始时间Column(columnNameend_time)privatelongendTime;// 结束时间Column(columnNamelatency)privateintlatency;// 延迟(ms)Column(columnNameis_error)privateintisError;// 是否出错Column(columnNamedata_binary)privatebyte[]dataBinary;// Span列表的二进制数据Column(columnNameversion)privateintversion;// 协议版本}// 明细模型 - 告警记录Stream(namealarm_record,scopeId1)publicclassAlarmRecordextendsRecord{Column(columnNamealarm_record_id)IDColumnprivateStringid;Column(columnNamerule_name)privateStringruleName;Column(columnNamescope)privateintscope;Column(columnNamescope_id)privateintscopeId;Column(columnNamename)privateStringname;Column(columnNamealarm_message)privateStringalarmMessage;Column(columnNamestart_time)privatelongstartTime;Column(columnNamevalue)privateStringvalue;}五、指标模型Metrics Model指标模型是SkyWalking当之无愧的主角因为Dashboard上的每个图表背后都有指标模型在支撑。// 指标模型 - 服务响应时间指标Stream(nameservice_resp_time,scopeId2)MetricsExtension(supportDownSamplingtrue)publicclassServiceRespTimeMetricsextendsMetricsimplementsLongValueHolder{Column(columnNameentity_id)IDColumnprivateStringentityId;Column(columnNamevalue,dataTypeColumn.ValueDataType.COMMON_VALUE,functionFunction.Avg)privatelongvalue;// 平均值Column(columnNametotal)privatelongtotal;// 调用次数Column(columnNamesum)privatelongsum;// 延迟总和Column(columnNametime_bucket)privatelongtimeBucket;// 时间窗口}// 指标模型 - 百分位响应时间指标Stream(nameservice_percentile,scopeId2)publicclassServicePercentileMetricsextendsMetricsimplementsMultiLongValuesHolder{Column(columnNameentity_id)IDColumnprivateStringentityId;Column(columnNamep50)privatelongp50;Column(columnNamep75)privatelongp75;Column(columnNamep90)privatelongp90;Column(columnNamep95)privatelongp95;Column(columnNamep99)privatelongp99;Column(columnNametotal)privatelongtotal;Column(columnNametime_bucket)privatelongtimeBucket;}六、采样模型Sampling Model采样模型存储的是按需抓取的数据——不是所有数据都存只有满足特定条件时才记录。// 采样模型 - 慢查询记录Stream(nametop_n_database_statement,scopeId3)publicclassTopNDatabaseStatementextendsRecord{Column(columnNametrace_id)privateStringtraceId;Column(columnNameid)IDColumnprivateStringid;Column(columnNamestatement)privateStringstatement;// SQL语句Column(columnNamelatency)privatelonglatency;// 执行时间Column(columnNameservice_id)privateintserviceId;Column(columnNametime_bucket)privatelongtimeBucket;}// 采样模型 - Profile堆栈快照Stream(nameprofile_task_segment_snapshot,scopeId3)publicclassProfileThreadSnapshotRecordextendsRecord{Column(columnNametask_id)privateStringtaskId;Column(columnNamesegment_id)privateStringsegmentId;Column(columnNamedump_time)privatelongdumpTime;Column(columnNamestack_binary)privatebyte[]stackBinary;// 线程堆栈数据}七、注解驱动的存储字段编排SkyWalking使用一套优雅的注解体系来声明字段如何存储// Column注解——定义字段的存储行为publicinterfaceColumn{// 存储中的列名StringcolumnName();// 值的数据类型ValueDataTypedataType()defaultValueDataType.COMMON_VALUE;// 如果是指标使用的聚合函数Functionfunction()defaultFunction.Avg;// 是否可搜索booleanmatchQuery()defaultfalse;// 是否可全文搜索booleancontentQuery()defaultfalse;// 存储类型StorageTypestorageType()defaultStorageType.COMMON;enumValueDataType{COMMON_VALUE,// 普通数值CONSTANT_VALUE,// 常数值NOT_VALUE,// 非数值SAMPLED_RECORD,// 采样记录值LABELED_VALUE// 标签值}}// IDColumn——标记主键字段publicinterfaceIDColumn{}// Stream——定义存储流索引/表publicinterfaceStream{Stringname();// 流名称intscopeId();// 范围IDClassbuilder();// Builder类Classprocessor();// Processor类}// MetricsExtension——指标扩展属性publicinterfaceMetricsExtension{booleansupportDownSampling()defaulttrue;booleansupportUpdate()defaultfalse;booleantimeRelativeID()defaulttrue;}八、四种模型的读写流程------------------- | Agent探针 | ------------------ | gRPC上报 | v ------------------ | SegmentParser | | 解析原始Segment | ------------------ | ------------------------ | | v v ---------------------- ------------------ | 注册模型处理 | | 明细模型处理 | | | | | | 1. 检查服务名是否已注册 | | 1. 创建SegmentRecord| | 2. 检查端点名是否已注册 | | 2. 记录latency等字段| | 3. 未注册则生成新ID | | 3. 写入存储 | | 4. 将ID映射放入缓存 | | | ---------------------- ------------------ | | v v ---------------------- ------------------ | 后续使用 | | 指标模型处理 | | | | | | 其他模型引用注册ID | | 1. 拿到服务ID | | (如指标模型中的entityId)| | 2. 解析OAL指标定义 | | | | 3. 执行聚合计算 | | | | 4. 写入指标数据 | ----------------------- ------------------ | (慢调用/异常时) | v ------------------ | 采样模型触发 | | | | 1. 判断是否满足条件 | | 2. 抓取堆栈/慢SQL | | 3. 存储采样数据 | -------------------- 图2四种模型的协同工作流程九、存储模型的时间窗口分层指标模型的数据按时间粒度分为三层存储原始数据写入分钟级 | v [分钟窗口] ── TTL: 默认90天 | | 每小时聚合一次 v [小时窗口] ── TTL: 默认45天 | | 每天聚合一次 v [天窗口] ── TTL: 默认180天 查询时自动选择最合适的粒度 - 查询最近1小时 → 使用分钟粒度数据 - 查询最近24小时 → 使用小时粒度数据 - 查询最近30天 → 使用天粒度数据十、总结SkyWalking的四大存储模型是一种根据数据使用方式分层存储的经典设计注册模型名→ID映射体量最小永久存储明细模型原始证据体量最大较短TTL指标模型聚合结果体量中等是Dashboard的数据源采样模型按需抓取体量按规则决定这套模型体系让SkyWalking既能在Dashboard上秒级响应查询又能完整保留问题排查所需的原始数据实现了快和全的完美平衡。下一篇文章我们将深入注册模型和明细模型的细节实现。上一篇【第48篇】OAP集群规划实战从理论到生产的容量设计下一篇【第50篇】注册模型与明细模型名字的管家和现场的记录官

相关新闻