写点什么

如何在汽车中构建一个时序数据库 (TSDB)?

  • 2024-10-31
  • 本文字数:4177 字

    阅读完需:约 14 分钟

如何在汽车中构建一个时序数据库 (TSDB)?

随着电动汽车智能化的发展,车辆运行时生成的时序数据量不断增加,导致数据收集、传输和存储成本高昂。GreptimeDB 车云一体化解决方案利用现代车载设备的先进计算能力,解决了这些问题。与传统的车云协同方案中车辆仅充当数据收集器不同,这一新方案将车辆视为可以本地运行复杂任务的完整服务器。从 32 位微控制单元(MCU)到像高通 8155 或 8295 这样的强大芯片模块的演进,使得智能车辆能够高效地执行边缘计算,从而降低数据传输和存储成本并提升整体效率。

原生 GreptimeDB 解决方案及面临的挑战

GreptimeDB 是一款云原生的时序数据库,具有高度可扩展性。然而,最初研发团队并未把车端使用纳入到 GreptimeDB 的构建计划当中,于是在 GreptimeDB 上车使用后发现了一些显著的问题:


  • 资源使用的限制:GreptimeDB 运行在车辆的驾驶舱域控制器中,必须尽量减少 CPU 和内存的使用,以避免干扰信息娱乐系统。

  • 稳健性:GreptimeDB 从 CAN 总线收集关键诊断指标,因此任何崩溃都可能导致数据丢失。

  • 强环境适应能力:此外,与数据中心的服务器不同,基于车辆的 GreptimeDB 需要在各种条件下运行,如频繁的电源循环和由于道路交通变化而波动的 ADAS 数据速率,因此它需要在保持稳定和高效的同时适应这些变化。


在接下来的部分中,我们将详细阐述遇到的挑战及其解决方案。

CPU 使用量

与其他在数据中心运行的数据库类似,GreptimeDB 在使用时往往会占用尽可能多的 CPU 资源——这是衡量数据库可扩展性的一个关键指标。然而,在电动汽车中的使用情况有所不同,车载的人机界面(HMI)不仅要执行基本的数据收集任务,还需为乘客提供娱乐信息功能。因此,我们需要限制车载数据库的 CPU 资源消耗,以避免影响其他进程。


db#1694 实现之后,GreptimeDB 提供了一个便捷的工具用于记录和分析 CPU 使用情况。在持续的数据写入过程中,该工具会捕捉不同任务所消耗的 CPU 周期,并生成火焰图,显示每个组件的 CPU 使用情况,如下图所示。



(图 1 :数据库端(左)与 SDK 端(右)的 CPU 火焰图)

基于共享内存 IPC 的专有 SDK

上述图表显示,协议编码/解码在数据库端占用了大约 30% 的 CPU 周期,而在 SDK 端大约占用了 36%。优化协议处理将显著降低平均 CPU 使用率。目前,开源的 GreptimeDB SDK 使用 gRPC 作为其协议。虽然 gRPC 速度快且用户友好,但在处理大量数据写入时,尤其是在处理嵌套消息结构时,其编码开销变得相当显著。



(图 2 :gRPC SDK 的数据流)


由于 SDK 和 GreptimeDB 实例位于同一主机上,我们选择了共享内存(shm)来绕过内核网络栈,并使用 Arrow IPC 格式进行进程间通信。提交给 SDK 的数据行首先缓存在 Arrow 的缓冲区中,然后编码并写入到 SDK 和数据库之间的共享内存区域中。接着,SDK 通知数据库读取并解码该数据区域。下图展示了在共享内存解决方案中的数据流情况。



(图 3 :共享内存 IPC 方案中的数据流)


为了有效利用共享内存区域,我们设计了一个环形缓冲区。编码后的数据必须写入连续的内存区域,类似于直接内存访问 (DMA) 中使用的缓冲区。因此,当写入偏移量到达内存区域末端时,环形缓冲区能够确保写入数据不会被拆分。

平滑的刷盘和压缩

与其他基于 LSM 树的数据库一样,GreptimeDB 在处理数据写入的同时,还会定期执行刷盘和压缩任务,这些后台任务的编码和压缩过程可能导致 CPU 尖刺。因此,控制这些活动的时机至关重要。GreptimeDB 允许针对不同的列使用不同的压缩和编码算法,以平衡压缩率和 CPU 使用率。


如果所有任务同时运行,可能会导致 CPU 峰值,从而导致车辆娱乐信息系统产生明显的延迟。在 GreptimeDB 中,刷新和压缩任务在专用的资源池中执行。通过正确配置该资源池中的线程数量和调度策略,我们可以在满足数据写入性能要求的同时保持低资源消耗。


目前,这些限制仍然是软约束;在写入流量极高的时期,CPU 尖刺仍可能发生。为全面解决这些问题,我们在开放源码推广计划(OSPP)活动下启动了一项研究计划,探索类似于 cgroups 的机制,以对 GreptimeD 的资源消耗施加硬约束,旨在彻底解决这些问题。


在生产级高通 8295 模块上的基准测试中,车载 GreptimeDB 可以每秒接收 60 万个数据点的写入,占用不到 8% 的 CPU 使用率和 300MB 的内存,且没有数据丢失或乱序情况



(图 4 :高通 8295 上的 CPU 使用情况)

内存使用情况

与 CPU 性能分析类似,GreptimeDB 提供了一个内存分析工具。更多详细信息可以查看我们的博客。如果你熟悉 LSM 树,那么很容易可以猜到 memtable 占用了大部分内存,分析结果也证实了这一点。尽管 GreptimeDB 提供了全局写入缓冲区大小参数来控制内存使用,但默认的 BTree memtable 的开销通常会导致内存使用超过阈值。下图来自 Nicole 的博客,展示了 Rust 中不同集合的开销情况。



(图 5 :Rust 中不同集合的开销情况)


GreptimeDB 目前正在快速开发中,其主要的内存缓冲组件 memtable 已经经历了多次迭代。在后续的迭代中,我们通过引入时间序列 memtable 解决了内存膨胀问题,并在数据低基数的工作负载下提供了极高的写入性能。下图展示了时间序列 memtable 的结构:



(图 6 :时间序列 memtable 的结构)


除了 memtable 之外,还需要仔细检查其他组件的内存使用情况,例如日志组件。在 Android 平台上,我们的日志输出通过 logcat 进行连接,因此可以禁用默认日志附加器的缓冲区,这一改变可以节省数十兆字节的内存

Flash 磨损问题

车辆的 HiMl 系统通常使用 NAND Flash 存储而非固态硬盘(SSD)。由于 NAND Flash 有写擦寿命的限制,在此类存储上运行时序数据库时,必须尽量减少写放大效应。这是基于 Log-Structured Merge (LSM) 树架构的数据库的已知问题。


为了解决这一问题,运行在车辆上的 GreptimeDB 实例支持不同表的 Write-Ahead Logging (WAL) 策略。


  • 对于高写入量的表,可以禁用 WAL 以减少写放大;

  • 而对于数据量较低但对可靠性要求较高的表,则可以保持 WAL 开启;

  • 考虑到现代电动汽车通常一直处于通电状态,WAL 在意外断电时保证数据持久性通常是多余的,这就能够允许更加灵活和高效地利用 NAND Flash 存储;

  • 此外在手动断电的情况下,GreptimeDB 还提供了一个 hook,可以将所有待处理的数据持久化到闪存中。


对于涉及大量数据读写的压缩操作,考虑到车载侧相对较小的数据量,并且这些数据很快就会被上传到云端并由 ingester 组件合并处理,GreptimeDB 允许在车端禁用压缩操作,这也有助于减少 Flash 磨损。



(图 7 :云端 ingester 组件中的文件合并策略)


除了上述措施外,我们还探索了基于匿名内存的共享内存方法。在 Linux 系统上,这种机制通常在 /dev/shm 下创建一个文件,该文件被 SDK 和数据库分别映射到各自的进程中。不幸的是,Android 不支持 /dev/shm。最初,我们在 Flash 存储中创建物理文件,但很快发现这会导致严重的 Flash 磨损。最终,我们发现 Android 提供的 ashmem 不需要写入物理文件,从而避免了这种问题。



图 8 :基于物理文件的共享内存(左)与 ashmem(右)


在实际车辆的性能测试中,我们观察到 SDK 端没有发生任何磁盘 I/O(Input/Output) 操作;所有的 I/O 都与数据库的 flush 任务有关。得益于其高压缩率,GreptimeDB 每秒仅写入 2MB 的文件



图 9 :SDK(左)和数据库(右)的 I/O 监控

构建一个真正适用于车辆的二进制文件

现代智能车辆的 HMI 系统通常运行在 Android 平台上,因此我们的主要挑战是如何将 GreptimeDB 的源代码编译成可以在 Android 上运行并与制造商代码库集成的二进制文件。在传统的 C/C++ 系统编程中,交叉编译通常是一项复杂的任务。幸运的是,得益于 Rust 丰富的生态系统,我们找到了 cargo-ndk,这是一个帮助 Android 平台设置交叉编译的 Cargo 插件。通过 cargo-ndk,我们可以从 Linux、macOS 和 Windows 平台编译出 Android 上运行的二进制文件。


cargo ndk --platform 23 \        -t aarch64-linux-android \        build --bin greptime \        --profile release \        --no-default-features
复制代码


除了交叉编译外,为了在 Android 上运行数据库,还需要提供适合 Android 系统的组件,例如日志。为此,我们使用了 android-logger 库,它可以无缝连接 Rust 中的常规日志宏(如 debug!info!warn!error!)到 logcat。GreptimeDB 已经将这些详细的工作集成到 GitHub 的工作流中,你可以从我们的 GitHub 发布页面下载 Android 二进制文件。


值得注意的是,我们的 SDK 也是用 Rust 编写的,而汽车制造商的代码库通常使用 C/C++。因此,我们提供了一个外部函数接口(FFI),将 Rust API 封装并暴露给 C 语言使用,如下图所示。



(图 10 :外部函数接口)


这种架构不仅受益于 Rust 生态系统的便利性,还提供了稳定且易于集成的用户接口。然而,正如在博客中提到的,对于跨越 FFI 边界的指针和异常处理仍需谨慎。

面向未来的车载智能

本文介绍了一种基于 GreptimeDB 低成本、高实时性的车云集成数据解决方案,并讨论了我们在实施过程中遇到的问题及其解决方案。目前,该方案在车端时序诊断数据的收集和分析方面取得了卓越的成果,为制造商节省了数百万美元的成本。然而,我们探索智能汽车边缘计算的旅程从未停止。随着大语言模型(LLM)应用的兴起,智能汽车现在可以利用 LLM 提供更丰富的乘客娱乐体验和智能诊断工具。在严格的隐私保护法规下,边缘智能变得越来越重要,要求智能汽车能够处理各种多模态数据类型,如向量和图像。GreptimeDB 正在探索如何将多模态数据集成到现有的车云集成解决方案中,从而加速汽车向更智能和多功能终端的演变。


关于 Greptime

Greptime 格睿科技专注于为可观测、物联网及车联网等领域提供实时、高效的数据存储和分析服务,帮助客户挖掘数据的深层价值。目前基于云原生的时序数据库 GreptimeDB 已经衍生出多款适合不同用户的解决方案,更多信息或 demo 展示请联系下方小助手(微信号:greptime)。

欢迎对开源感兴趣的朋友们参与贡献和讨论,从带有 good first issue 标签的 issue 开始你的开源之旅吧~期待在开源社群里遇见你!添加小助手微信即可加入“技术交流群”与志同道合的朋友们面对面交流哦~

Star us on GitHub Now: https://github.com/GreptimeTeam/greptimedb

官网:https://greptime.cn/

文档:https://docs.greptime.cn/

Twitter: https://twitter.com/Greptime

Slack: https://greptime.com/slack

LinkedIn: https://www.linkedin.com/company/greptime/

用户头像

专注于 Infra 技术分享 2022-09-23 加入

分布式、高性能、存储计算分离的开源云原生时序数据库

评论

发布
暂无评论
如何在汽车中构建一个时序数据库 (TSDB)?_边缘计算_Greptime 格睿科技_InfoQ写作社区