对低延迟机器学习功能商店的需求比以往任何时候都更高,但实际上在规模上实现一个仍然是一个挑战,当时ShareChat工程师Ivan Burmistrov和Andrei Manakov参加了P99 CONF 23阶段,分享他们如何建立一个基于ScyllaDB的低延迟ML功能商店。 这是一个“教训”的故事,看看无情的性能优化的价值 - 与一些重要的工程采购。 最初的系统实现远远低于公司的可扩展性要求,最终的目标是每秒支持10亿个功能,但系统在100万个负载下失败了。 热衷于性能优化和低延迟工程?加入你的同行在P99 24 CONF,一个免费的高技术虚拟会议“万物性能”。 迈克尔·斯通布拉克,Postgres的创始人和麻省理工学院教授 Bryan Cantrill,氧化计算机的联合创始人和CTO Avi Kivity, KVM 创始人, ScyllaDB 联合创始人和 CTO Liz Rice,eBPF专家的开源首席官 Isovalent 安迪·帕夫洛,CMU教授 Ashley Williams,Axo创始人/首席执行官,前Rust核心团队,Rust基金会创始人 Carl Lerche,东京创建者,Rust贡献者和AWS工程师 现在注册 - 免费 现在注册 - 免费 现在注册 - 免费 除了来自ShareChat的伊万的另一个伟大的谈话之外,期待在迪士尼/Hulu,Shopify,Lyft,Uber,Netflix,American Express,Datadog,Grafana,LinkedIn,Google,Oracle,Redis,AWS,ScyllaDB等方面进行60多个性能优化工程谈话。 ShareChat:印度领先的社交媒体平台 要了解挑战的范围,重要的是了解印度领先的社交媒体平台ShareChat,在ShareChat应用程序上,用户可以发现和使用超过15种不同语言的内容,包括视频,图像,歌曲等。 在两种应用之间,它们服务于一个快速增长的用户群,每月已经有超过32500万活跃用户,并且基于人工智能的内容推荐引擎对于推动用户保留和参与至关重要。 机器学习功能商店在ShareChat 该故事侧重于Moj短形视频应用程序的ML功能商店背后的系统,它为大约2000万每月活跃用户和1亿每月活跃用户提供完全个性化的源,每秒提供8000个请求,每个请求中平均有2000个内容候选人排名(例如,找到10个推荐的最佳项目)。 ShareChat的首席软件工程师Ivan Burmistrov解释说: “我们计算不同“实体”的特性。邮件是一个实体,用户是另一个,等等。从计算的角度来看,它们非常相似。然而,重要的区别在于我们需要为每个实体类型采集的特性数量。当用户请求传输时,我们为该单个用户采集用户特性。 什么错了 起初,主要关注的是建立实时用户功能商店,因为当时用户功能是最重要的。团队开始构建功能商店,以此为目标。 接近实时邮件功能更为重要 排行榜的职位数量从数百增加到数千 伊万解释说:“当我们去测试这个新系统时,它失败了,每秒大约100万个特征,系统变得不响应,延迟通过屋顶等等。 最终,问题源于系统架构如何使用称为砖的预累积数据桶,例如,他们可以汇总在一分钟或其他时间范围内发布的帖子的喜欢次数,这使他们能够计算像过去两小时内多个帖子的喜欢次数这样的指标。 这里有一个高层次的系统架构观点. 有一些实时主题包含原始数据(喜欢,点击等)。 一个 Flink 工作将它们合并成板块,并将其写入 ScyllaDB。 最初的数据库方案和架构配置导致了可扩展性问题,最初,每个实体都有自己的分区,行时刻印和功能名称被排序为集群列。 圖片被計算為一分鐘,30分鐘和一天的部分,尋找一小時,一天,七天或30天需要平均每個功能收集大約70個圖片。 在这个 NoSQL 数据建模硕士课程中了解更多 如果你做数学,它变得清楚为什么它失败. 系统需要处理每秒约22亿行. 然而,数据库容量只有1000万行 / 秒。 初步优化 在那时,团队开始了优化任务,最初的数据库计划被更新,以便将所有功能行存储在一起,并将其序列化为特定时间标签的协议缓冲器,因为该架构已经使用了Apache Flink,因此,由于Flink在数据管道建设方面的先进功能,将其转移到新架构方案是相当容易的。 该团队还优化了砖的配置,将额外的五分钟、三小时和五天的砖添加到一分钟、30分钟和一天的砖中,从而将所需的平均砖从70个减少到23个,进一步减少了每秒的行到约7300万个。 为了在数据库侧处理更多的行/秒,他们改变了ScyllaDB压缩策略,从增量到水平。 该选项更适合他们的查询模式,将相关行保持在一起,并减少读取 I/O. 结果:ScyllaDB的容量有效增加了一倍。 了解更多关于压缩策略 最简单的方法来适应剩余的负载是将ScyllaDB扩展4倍,但是,更多的/更大的集群会增加成本,而这根本不在他们的预算范围内,所以团队继续专注于提高可扩展性而不会扩展ScyllaDB集群。 改进缓存位置 降低 ScyllaDB 的负载的一种潜在方法是改善本地缓存的打击率,所以团队决定研究如何实现这一点。显而易见的选择是使用一套一致的哈希方法,这是根据有关请求的一些信息向客户端发送请求的已知方法。由于团队在 Kubernetes 设置中使用 NGINX Ingress,使用 NGINX 的一致性哈希功能似乎是一个自然的选择。 这个简单的配置没有起作用,具体来说: 客户端子集导致了巨大的密钥重组 - 在最坏的情况下达到 100%. 由于节点密钥可以在哈希环中更改,因此无法使用自动扩展的现实场景。 提供一个请求的哈希值是困难的,因为Ingress不支持最明显的解决方案:gRPC标题。 延迟遭受了严重的退化,不清楚是什么导致尾巴延迟。 为了支持子组的子组,团队修改了他们的方法,他们创建了一个两个步骤的哈希函数:首先哈希一个实体,然后添加一个随机前缀,从而将实体分布在所需的子组数量上。 Ingress不支持使用gRPC标题作为变量,但团队找到了解决方案:使用路径重写并在路径本身中提供所需的哈希密钥。 不幸的是,确定延迟下降的原因需要相当长的时间,以及可观察性的改进。 为了达到截止日期,团队将Feature服务分为27个不同的服务,并在客户端上手动将所有实体分开,这不是最优雅的方法,但它是简单和实用的 - 并且取得了很好的结果。 然而,这种“老学校”部署分裂的方法仍然不是理想的设计。维护27个部署是无聊的和低效的。此外,缓存打击率并不稳定,而且扩展受到限制,因为必须在每个部署中保持高最低的Pod数目。 优化的下一阶段:一致的哈希,功能服务 准备再进行一轮优化,该团队使用一个名为“Envoy Proxy”的Sidecar重新审视了一致的哈希方法,并与功能服务一起部署。Envoy Proxy提供了更好的可观察性,有助于识别延迟尾部问题。 然后,团队优化了功能服务,他们: 铸造了缓存库(维多利亚Metrics的FastCache),并实施了批次写作和更好的驱逐,以减少百倍的突触争议。 铸造了gprc-go,并在不同的连接中实施了缓冲池,以避免高平行时的争议。 使用对象聚合和调整垃圾收集器(GC)参数来减少分配率和GC周期。 随着Envoy Proxy在其概念验证中处理了15%的流量,结果很有希望:98%的缓存打击率,这将ScyllaDB的负载降低到740万行 / 秒,他们甚至可以更大规模地扩展功能库:从10亿个特征 / 秒到30亿个特征 / 秒。 学到的教训 以下是这个旅程从时间线的角度看起来如何: 最后,Andrei总结了团队从这个项目中学到的主要教训(迄今为止): 即使ShareChat团队彻底改变了系统设计,ScyllaDB、Apache Flink和VictoriaMetrics仍然很好地工作。 每个优化都比前一个更难,而且影响更少。 简单而实用的解决方案(例如将功能商店划分为27个部署)确实有效。 提供最佳性能的解决方案并不总是用户友好的,例如,他们修订的数据库方案具有良好的性能,但很难维护和理解。 每个系统都是独一无二的,有时您可能需要将默认库折叠并调整为您的特定系统以获得最佳性能。 观看他们完整的P99 CONF谈话! 观看他们完整的P99 CONF谈话! 观看他们完整的P99 CONF谈话! 关于Cynthia Dunlop Cynthia 是 ScyllaDB 的内容策略高级总监,她已经写了 20 多年的软件开发和质量工程。