1.3 万亿条数据查询,知乎如何做到毫秒级响应?
(给数据分析与开发加星标,提升数据技能)
作者:孙晓光
http://itindex.net/
知乎搜索后端负责人,目前承担知乎搜索后端架构设计以及工程团队的管理工作。曾多年从事私有云相关产品开发工作,关注云原生技术,TiKV 项目 Committer。
作为中国最大的知识共享平台,我们目前拥有 2.2 亿注册用户,3000 万个问题,网站答案超过 1.3 亿。
随着用户群的增长,我们的应用程序的数据大小无法实现。我们的 Moneta 应用程序中存储了大约 1.3 万亿行数据(存储用户已经阅读过的帖子)。
由于每月累计产生大约 1000 亿行数据且不断增长,这一数字将在两年内达到 3 万亿。在保持良好用户体验的同时,我们在扩展后端方面面临严峻挑战。
在这篇文章中,我将深入探讨如何在如此大量的数据上保持毫秒级的查询响应时间,以及 TiDB 是一个开源的 MySQL 兼容的 NewSQL 混合事务/分析处理( HTAP)数据库,如何为我们提供支持获得对我们数据的实时洞察。
我将介绍为什么我们选择 TiDB,我们如何使用它,我们学到了什么,优秀实践以及对未来的一些想法。
我们的痛点
本节介绍了我们的 Moneta 应用程序的体系结构,我们尝试构建的理想体系结构,以及数据库可伸缩性作为我们的主要难点。
系统架构要求
知乎的 Post Feed 服务是一个关键系统,用户可以通过该系统接收网站上发布的内容。
后端的 Moneta 应用程序存储用户已阅读的帖子,并在知乎的推荐页面的帖子流中过滤掉这些帖子。
Moneta 应用程序具有以下特征:
需要高可用性数据:Post Feed 是第一个出现的屏幕,它在推动用户流量到知乎方面发挥着重要作用。
处理巨大的写入数据:例如,在高峰时间每秒写入超过 4 万条记录,记录数量每天增加近 30 亿条记录。
长期存储历史数据:目前,系统中存储了大约 1.3 万亿条记录。随着每月累积约 1000 亿条记录并且不断增长,历史数据将在大约两年内达到 3 万亿条记录。
处理高吞吐量查询:在高峰时间,系统处理平均每秒在 1200 万个帖子上执行的查询。
将查询的响应时间限制为 90 毫秒或更短:即使对于执行时间最长的长尾查询,也会发生这种情况。
容忍误报:这意味着系统可以为用户调出许多有趣的帖子,即使有些帖子被错误地过滤掉了。
高可用性:当用户打开知乎的推荐页面时,找到大量已经阅读过的帖子是一种糟糕的用户体验。
出色的系统性能:我们的应用具有高吞吐量和严格的响应时间要求。
易于扩展:随着业务的发展和应用程序的发展,我们希望我们的系统可以轻松扩展。
勘探
代理:这会将用户的请求转发给可用节点,并确保系统的高可用性。
缓存:这暂时处理内存中的请求,因此我们并不总是需要处理数据库中的请求。这可以提高系统性能。
存储:在使用 TiDB 之前,我们在独立的 MySQL 上管理我们的业务数据。随着数据量的激增,独立的 MySQL 系统还不够。
然后我们采用了 MySQL 分片和 Master High Availability Manager( MHA)的解决方案,但是当每月有 1000 亿条新记录涌入我们的数据库时,这个解决方案是不可取的。
MySQL Sharding 和 MHA 的缺点
MySQL 分片的缺点:
应用程序代码变得复杂且难以维护。
更改现有的分片键很麻烦。
升级应用程序逻辑会影响应用程序的可用性。
MHA 的缺点:
我们需要通过编写脚本或使用第三方工具来实现虚拟 IP(VIP)配置。
MHA 仅监视主数据库。
要配置 MHA,我们需要配置无密码安全 Shell( SSH)。这可能会导致潜在的安全风险。
MHA 不为从属服务器提供读取负载平衡功能。
MHA 只能监视主服务器(而不是从主服务器)是否可用。
什么是 TiDB?
TiDB 平台是一组组件,当它们一起使用时,它们将成为具有 HTAP 功能的 NewSQL 数据库。
TiDB 服务器是一个无状态的 SQL 层,它处理用户的 SQL 查询,访问存储层中的数据,并将相应的结果返回给应用程序。它与 MySQL 兼容并且位于 TiKV 之上。
TiKV 服务器是数据持久存在的分布式事务键值存储层。它使用 Raft 共识协议进行复制,以确保强大的数据一致性和高可用性。
TiSpark 集群也位于 TiKV 之上。它是一个 Apache Spark 插件,可与 TiDB 平台配合使用,支持商业智能(BI)分析师和数据科学家的复杂在线分析处理(OLAP)查询。
放置驱动程序(PD)服务器是由 etcd 支持的元数据集群,用于管理和调度 TiKV。
水平可扩展性。
MySQL 兼容的语法。
具有强一致性的分布式事务。
云原生架构。
使用 HTAP 进行最小提取,转换,加载( ETL)。
容错和 Raft 恢复。
在线架构更改。
我们如何使用 TiDB
我们架构中的 TiDB
顶层:无状态和可伸缩的客户端 API 和代理。这些组件易于扩展。
中间层:软状态组件和分层 Redis 缓存作为主要部分。当服务中断时,这些组件可以通过恢复保存在 TiDB 群集中的数据来自我恢复服务。
底层:TiDB 集群存储所有有状态数据。它的组件高度可用,如果节点崩溃,它可以自我恢复其服务。
TiDB 的性能指标
在高峰时间每秒写入 40,000 行数据:
在高峰时段每秒检查 30,000 个查询和 1200 万个帖子:
第 99 百分位响应时间约为 25 毫秒,第 999 百分位响应时间约为 50 毫秒。实际上,平均响应时间远远小于这些数字,即使对于需要稳定响应时间的长尾查询也是如此。
第 99 百分位响应时间
我们学到了什么
更快地导入数据
减少查询延迟
有些查询对查询延迟很敏感,有些则不然。我们部署了一个单独的 TiDB 数据库来处理对延迟敏感的查询。(其他非延迟敏感的查询在不同的 TiDB 数据库中处理。)
这样,大型查询和对延迟敏感的查询在不同的数据库中处理,前者的执行不会影响后者。
对于没有理想执行计划的查询,我们编写了 SQL 提示来帮助执行引擎选择最佳执行计划。
我们使用低精度时间戳 Oracle( TSO)和预处理语句来减少网络往返。
评估资源
对 TiDB 3.0 的期望
④gRPC 和多线程 Raftstore 中的批处理消息
⑤SQL 计划管理
⑥TiFlash
⑦反垃圾邮件应用程序中的 TiDB 3.0
下一步是什么
推荐阅读
(点击标题可跳转阅读)
看完本文有收获?请转发分享给更多人
关注「数据分析与开发」加星标,提升数据技能
好文章,我在看❤️