在现代实时数据分析系统中,高效稳定的数据摄取是保证平台性能的关键环节。Tinybird作为一款面向实时分析的云端平台,每天要处理数以千亿计的事件和数据,数据摄取的性能直接关系到系统的响应速度和运行成本。近期,Tinybird发布了一项令人瞩目的技术进展——通过采用C++重构其摄取管线的JSON数据转换部分,使系统整体CPU使用率下降了30%,性能得以显著提升。本文将带您深入了解这次改进的背景、技术细节及背后的故事。 首先,需要明确的是Tinybird在数据摄取时,并非简单地将JSON或NDJSON格式的数据转为普通的二进制格式,而是转换为ClickHouse数据库特有的一种工业级高效格式——RowBinaryWithDefaults。这种格式不同于传统的行存储,它结合了列式存储的效率优势,同时又极大地优化了基于事件或行数据自然形态的摄取过程。
具体来说,每条数据行中的字段会被编码成紧凑的二进制形式,并支持字段的缺失到数据库默认值的智能替代,这种灵活性极大地提升了摄取的兼容性和稳定性。 长期以来,Tinybird的数据摄取核心组件最初是基于Python实现的,并辅以部分用C语言编写的辅助函数。尽管早期实现已高度优化,但由于Python本身的性能限制及所承担任务的复杂性,进一步挖掘性能潜力成为一项艰难的挑战。更重要的是,随着ClickHouse持续扩展数据类型支持,原有方案不得不不断重复实现各类编码逻辑,维护负担日益加重。 基于此,Tinybird团队决定寻找一种能够直接调用ClickHouse底层编码逻辑,且拥有更强性能和更好可维护性的解决路径。经过调研与探索,团队锁定了C++作为理想的实现语言。
ClickHouse的本身就是用C++打造,其内部编码功能和API能够被合理封装调用,直接重用官方编码库不仅保证了兼容性,也减少了重复开发带来的潜在风险。 然而,实际实施过程中遇到的困难远超预期。很重要的一点是,RowBinaryWithDefaults作为输入格式,ClickHouse内部并未提供相应的输出格式支持,这使得简单封装不可行。除此之外,Tinybird摄取管线还有诸多“潜规则”和细节要求,如支持复杂的JSON路径(jsonpath)映射、多样化的数据类型处理,以及极其重要的错误隔离机制——“隔离区”(quarantine)。这些都必须由新方案无缝支持才能保持与旧版系统的行为一致,避免对客户现有应用造成冲击。 在jsonpath处理上,Tinybird需要根据业务定义,将复杂嵌套的JSON结构中不同字段映射到数据库表的指定列,这远非普通json提取能满足。
为了提高性能并减少重复解析,团队创新性地设计了jsonpath树结构。该结构整合多个路径的公共前缀,允许对输入JSON只遍历一次片段即可获取所有目标字段,有效降低了CPU开销。 为了解决JSON解析的性能瓶颈,Tinybird选择了业界公认的最快JSON解析库——simdjson。该库基于SIMD指令集,对输入数据进行零拷贝的按需解析,极大提升了解析速度和内存效率。使用simdjson的ondemand模式,Tinybird能够直接在原始字符串上逐层访问JSON节点,避免了传统生成完整内存树所带来的资源负担。但simdjson的此种使用方式也带来了更高的编码复杂度,开发团队需要小心管理生命周期,确保数据访问安全且稳定。
完成jsonpath提取后,下一步是将每个字段的数据构造成ClickHouse内部使用的Field对象。Field不仅仅是简单的值封装,它需支持丰富的数据类型,诸如高精度的Decimal,复杂的日期时间格式(包括时区偏移和纳秒级精度),以及递归嵌套的数组、元组、映射和JSON等结构。针对日期时间,团队甚至重新实现了解析器,覆盖了标准库或ClickHouse内置函数不支持的特性。 此外,为了兼容历史数据和维护原有行为,团队添加了“旧版兼容模式”,处理各种此前未发现的小怪癖和数据异常。这个模式在默认情况下启用,确保现有客户的摄取管线不会因为升级而出现数据缺失或异常拦截。未来,若关闭此模式,系统可以更严格地审查数据,帮助用户提升数据质量和一致性。
健壮的错误处理机制是Tinybird数据摄取成功的重要保障。系统设计允许部分字段异常时记录详细错误信息,将异常数据送入隔离区,同时正常数据可继续被摄取。针对simdjson解析器可能进入不可恢复状态的情况,团队巧妙实现了恢复策略,允许重新定位并继续解析后续数据块,保证整体摄取任务的高可用性。 经过反复测试和多阶段灰度发布,Tinybird成功将基于C++的新转换方案导入生产环境。在性能监控中,尤其是在处理Events API请求的区域震荡明显:CPU使用率显著降低近30%,显著节省了计算资源和成本。更重要的是,系统稳定性和容错能力得到加强,运维负担下降,代码结构清晰且易于扩展。
这次优化项目不仅仅是一次技术升级,更推动了Tinybird与ClickHouse数据库核心功能的深度融合。未来,基于该方案,平台还计划推出“非兼容旧版”的严格摄取模式,以持续提升数据质量和系统性能。同时,计划将此转换功能推广到更多数据源和连接器,造福更广泛的用户群体。 总结来看,Tinybird借助C++对Json到RowBinaryWithDefaults转换流程的重构,成功突破了原有Python实现的性能瓶颈,构建了兼具高性能、高可靠和高维护性的摄取管线。这背后,是对ClickHouse底层强大编码功能的合理复用,是对业界领先JSON解析库simdjson的创新集成,也是对复杂业务需求的深入洞察和精细工程实践。 对于希望打造实时数据摄取与分析平台的开发团队而言,Tinybird的经验提供了宝贵启示:合适的技术选型、对底层数据库内部功能的充分利用、严谨的错误管理和持续的回归测试,是实现系统性能与稳定性双赢的关键要素。
未来,随着数据量的爆炸式增长和实时分析需求的日益多样,类似Tinybird这样在细节和架构上持续打磨的案例,将成为行业开发者学习的范本及加速自身产品优化的助推器。