万亿条数据查询如何做到毫秒级响应?

知乎 , 在古典中文中意为“你知道吗?” , 它是中国的 Quora , 一个问答网站 , 其中各种问题由用户社区创建 , 回答 , 编辑和组织 。作为中国最大的知识共享平台 , 我们目前拥有 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 不是一个好的解决方案 , 因为 MySQL 分片和 MHA 都有它们的缺点 。
MySQL 分片的缺点:
  • 应用程序代码变得复杂且难以维护 。
  • 更改现有的分片键很麻烦 。
  • 升级应用程序逻辑会影响应用程序的可用性 。
MHA 的缺点: