对于许多机器学习应用,尤其是在线预测或用户交互相关的应用,从在线存储获取特征的速度是系统可行性的决定因素。延迟,以毫秒衡量,直接影响用户体验以及将机器学习模型集成到响应式应用中的可行性。离线系统重视大规模处理的吞吐量,而在线服务则要求近乎即时地获取单个实体的特征值。优化这种在线服务延迟需要多方面的方法,解决从网络层到数据库和应用逻辑的瓶颈。
识别延迟来源
在优化之前,有必要了解在线特征获取路径中延迟通常发生在何处。一个典型的请求可能包含:
- 网络传输(应用到特征存储): 请求从消费应用(例如,预测服务)传输到特征存储服务API所需的时间。
- 特征存储服务开销: 特征存储API层处理请求、处理认证/授权以及解析查询所需的时间。
- 查询规划/执行: 如果底层存储需要查询规划(对于简单的键值查询不太常见,但有可能),这会增加延迟。
- 数据获取(存储I/O): 核心延迟组成部分,代表在线数据库定位并从磁盘或内存读取特征数据所需的时间。
- 数据序列化/反序列化: 为传输回客户端编码数据以及数据到达后解码所需的时间。
- 网络传输(特征存储到应用): 响应数据传输回消费应用所需的时间。
系统地衡量在线服务管道的各个组件对于找出主要瓶颈是必不可少的,这通常通过使用集成到您的MLOps平台中的分布式追踪工具(如Jaeger或Zipkin)来完成。将优化工作集中在能获得最大回报的地方。记住不仅要测量平均延迟,还要测量尾部延迟(例如p99、p99.9),因为这些通常对感知性能影响最大,尤其是在高负载下。
缓存策略
缓存通常是减少延迟最有效的方法,它通过将常访问的数据存储在更接近消费者或更快内存层级中来实现。
客户端缓存
消费特征的应用可以维护本地缓存(例如,内存字典或专用缓存库)。这完全消除了缓存命中时的网络开销。
- 优点: 缓存数据访问速度最快。减轻特征存储服务的负载。
- 缺点: 如果缓存失效处理不当,可能导致数据过时。增加客户端应用的内存占用。跨多个客户端实例的缓存一致性可能具有挑战。需要根据特征的易变性仔细管理存活时间 (TTL)。
服务端缓存(特征存储层面)
在特征存储的在线服务组件内部或前方实现缓存层很常见。常用Redis或Memcached等技术。
请求流显示了服务端缓存在请求到达主在线数据库之前拦截查找。
- 优点: 集中式缓存逻辑。减轻底层持久化在线存储的负载。可被多个客户端共享。
- 缺点: 引入了另一个需要管理的 инфраструктура 组件。客户端和特征存储服务之间仍涉及网络延迟。缓存失效和TTL管理仍然很重要。
内容分发网络 (CDN)
对于全球分布式应用,CDN可以在更接近终端用户的边缘位置缓存特征数据。这对于相对静态或不常变化的特征,且由地理位置分散的客户端请求的特征最有效。
- 优点: 显著降低了远离源特征存储的用户网络延迟。
- 缺点: 主要适用于读密集型、非个性化、相当静态的特征。增加了复杂性和成本。CDN网络中的缓存失效可能很复杂。
数据建模和存储优化
数据在在线数据库中的结构和存储方式对获取速度有深远影响。在线服务的主要访问模式通常是基于一个或多个实体键的直接查找。
- 选择合适的数据库: 选择为低延迟键值查找优化的在线存储。
- 内存数据库(例如,Redis,Aerospike): 通过将数据主要保存在RAM中,提供最低的延迟。权衡因素包括持久化配置、成本以及如果未配置持久性可能导致的数据丢失。
- 优化过的NoSQL数据库(例如,AWS DynamoDB,Google Cloud Bigtable,Cassandra): 旨在实现大规模扩展和快速基于键的读取。性能很大程度上取决于正确的数据建模,尤其是分区键的选择,以确保数据均匀分布并避免“热点”。
- 索引: 确保数据库表在用于查找的实体键上正确创建索引。了解数据库的索引机制(例如,用于点查找的哈希索引,排序索引)。如果次级索引显著增加写入延迟或复杂性,应避免将其用于关键路径,除非特定查询模式下绝对必要。
- 数据布局(宽表与窄表):
- 宽表: 将实体的所有特征存储在单行中,可以有效一次性获取多个特征,最大程度减少读取操作。
- 窄表: 以更规范化的方式存储特征(例如,每个实体-特征对一行)可能提供灵活性,但通常需要多次读取或扫描才能获取实体的所有特征,从而增加延迟。对于键值查找,通常优先选择宽表。
- 数据类型: 使用数据库提供的最有效的数据类型来存储特征。如果仅频繁需要大对象(例如,大型JSON blob)的小部分,则避免直接存储它们;考虑将其拆分。
查询和网络效率
优化请求本身和网络通信会带来更多益处。
- 批量请求: 不要为每个实体发送单独的请求(例如,在微批量预测场景中),而是将多个实体查找批量处理成对特征存储的一次请求。这减少了网络往返次数,并允许特征存储在后端优化数据获取。许多特征存储客户端和数据库支持批量
Get 操作。
- 特征投影: 只请求模型或应用所需的特定特征。获取不必要的特征会浪费网络带宽并增加序列化/反序列化开销。特征存储API应允许客户端指定所需的特征名称。
- 高效序列化: JSON等标准文本格式可读性好,但在性能要求高的路径上可能效率不高。考虑使用二进制序列化格式,如Protocol Buffers (Protobuf) 或 Apache Avro。这些格式通常更紧凑且解析速度更快,从而减少网络传输时间和CPU开销。
- 网络邻近性: 将在线特征存储基础设施部署在地理位置上靠近主要消费应用的地方。云服务商提供可用区和区域;在同一区域内共同部署服务可以最大程度减少网络延迟。
减少读取时的计算
在线服务理想情况下应涉及最少的计算。复杂的转换或聚合应离线处理,结果直接存储在在线存储中。
- 预计算特征: 如果延迟是重要因素,避免在在线请求路径中按需计算特征。复杂逻辑、时间窗口聚合或模型推理(例如,嵌入)的结果应通过批量或流式管道计算,并物化到在线存储中。
- 避免复杂逻辑: 特征存储的服务层应主要执行简单的查找。将复杂的过滤或转换逻辑推送到在线服务路径会增加延迟和复杂性。
监控和迭代调优
优化不是一次性任务。持续的监控和调整是必要的。
- 详细监控: 追踪特征获取操作的重要延迟指标(p50、p90、p99、p99.9)。使用仪表盘可视化趋势并设置延迟下降警报。
- 基准测试: 定期在模拟生产流量模式的负载下对在线存储的性能进行基准测试。这有助于在瓶颈影响用户之前发现它们。
- 负载测试: 在高峰负载下对系统进行压力测试,以了解其临界点以及压力下延迟如何恶化。这有助于容量规划(稍后介绍)。
- 迭代改进: 使用监控和基准测试结果来识别瓶颈,并迭代应用上述优化方法。衡量每次更改的影响。
应用缓存和请求批量处理对p99在线服务延迟的影响。
实现低在线服务延迟需要仔细的设计选择,涵盖缓存、数据建模、基础设施选择和查询模式。通过系统地识别瓶颈并应用这些优化策略,您可以确保您的特征存储满足实时机器学习应用严苛的性能要求。