建立站点的作用,wordpress 连接池,潍坊市网站优化,seo链接优化建议Quora 的流量涉及大量阅读而非写入#xff0c;一直致力于优化读和数据量而非写。
0 数据库负载的主要部分
读取数据量写入
1 优化读取
1.1 不同类型的读需要不同优化
① 复杂查询#xff0c;如连接、聚合等
在查询计数已成为问题的情况下#xff0c;它们在另一个表中构…
Quora 的流量涉及大量阅读而非写入一直致力于优化读和数据量而非写。
0 数据库负载的主要部分
读取数据量写入
1 优化读取
1.1 不同类型的读需要不同优化
① 复杂查询如连接、聚合等
在查询计数已成为问题的情况下它们在另一个表中构建了计数以便它们可以直接读取计数值而非计算计数。
② 大型扫描
他们使用 LIMIT 改变它或使用分页
③ 模式与查询之间不匹配
若
无很好的索引或索引没有足够的列或索引中的列顺序对查询来说不是最佳
则查询可能很慢可能对数据库造成很大负载。
这种情况下通常会修改索引以对查询进行优化。 有时查询也可修改以对索引进行优化。如
删除 select 子句中不必要的列(特别是索引中不存在的列)删除 order by 子句改为在客户端上排序(MySQL CPU 一般比客户端 CPU 更宝贵) 若该查询提供的功能不再重要可完全删除查询
1.2 高 QPS 查询
即使使用了优化的 SQL 和良好的模式高 QPS查询也给数据库带来很大负载。有时可能表示缓存效率低下(甚至没缓存)。
① 低效的缓存是否导致了高 QPS 查询
缓存通常用于减少数据库 QPS。缓存键的选择可以极大地影响缓存的效率
若缓存键过于具体或狭窄可能导致数据库出现高 QPS若缓存键太宽泛每次查询都会从数据库中拉取大量数据
② 对用户语言表的查询
我们有一个表跟踪用户使用的语言信息。通常会查询数据库以查看用户 U 是否使用语言 L。使用(uid,language_id)作为缓存键看起来合理。如缓存未命中将为该 uid 和 language_id 查询数据库表。
因此将缓存键更改为仅使用 uid 确实有意义缓存值将是有关用户使用的所有语言的信息。
以上述方式更改缓存键会增加从库表中每次查询获取的数据量但它将 QPS 减少超过 90%。大多数用户只使用一或几种语言。 因此大多数情况新的查询并没有拉取比以前更多的数据这是一个显然的优化
③ 查询 A2A(ask to answer)表
这里我们处理 3 个实体间的关系即用户(谁提问或关注问题)、问题和回答者这比 2 个实体之间的关系更不常见。
通常产品逻辑是查询
用户已请求过的所有回答者使用缓存键 (question_id, user_id)请求过相同回答者回答一个问题的所有用户使用缓存键 (question_id, answerer_id)
综上A2A 表的 QPS 非常高这意味着上述缓存效果并不明显。上述两个缓存都在使用 2 个实体作为缓存键question_id 和 user_id(可以是提问者或回答者)。
潜在缓存键数量巨大因为它是问题数和用户数的乘积其中只有很少的组合实际上在表中有数据。所以它可看作一个稀疏的数据集有2维。
大多数问题的 A2A 请求数量相对较少但有少数问题的 A2A 数量要多得多。因此添加额外缓存该缓存包含问题的 A2A最多限制为 N 个以便我们捕获大多数问题。 该缓存的键只是 question_id。 如缓存列表大小小于N我们知道缓存是完整的。 否则缓存不完整我们不会使用缓存。
这额外缓存帮助显著减少 A2A 表上的 QPS(在 50% 到 66% 的范围内)。 还对产品逻辑进行了其他更改,以提高效率,但 QPS 的减少大部分来自额外缓存。
1.3 一维数据集中的稀疏数据
Quora 在缓存方面经常遇到的另一个问题是稀疏一维数据集。如可能需要查询数据库看某问题是否需重定向到另一问题(如同一个问题被重新发布就可能发生这种情况)。
绝大多问题不需要重定向所以 Quora 只会获取几个“重定向”而大量“不重定向”。
当他们只是缓存了 question_id 缓存中就会填满不用只有几个重定向。 这在缓存中占用大量空间且由于“重定向”数量如此稀疏也会导致大量缓存未命中。
相反他们开始缓存范围。 如 question id 123–127的任一问题都没重定向那么他们会将该范围缓存为所有问题均为 No而不是缓存每个单独的 question id。
这大大降低此类查询的数据库负载QPS 下降 90%。
2 优化表占用空间
由于以下几个原因表大小很重要
存储更多数据的成本更高随表增长适应数据库缓冲池的数据百分比会变小即IO会逐渐增加性能会逐渐下降备份和恢复时间会随表大小线性增长。虽然备份是从 MySQL 副本完成的但我们也会从副本读数据。在备份期间MySQL副本性能略有下降随表增长备份大小也在增长导致备份存储成本随时间增长
显然对不需要永久存储的数据制定最佳保留策略有助减少表大小 —— 使用 MyRocks 减少表大小
有一些表对于表所有者来说无法接受任何数据的删除。为此研究使用 MyRocks 来减小空间使用 MySQL 中的表可能使用更复杂的模式和查询。 所以他们希望谨慎使用 MyRocks。 作为分片项目的一部分已对 MySQL 中最大的表进行分片这是在 MySQL 在 Quora 的分片中记录此表是基于自增列范围进行分片的与基于时间的分片接近因为自增列值随时间增加大多数查询访问最近的分片。 包含 18 个月以上旧数据的较旧分片对日常业务相对不太关键
因此他们决定按如下方式将较旧的分片移至 MyRocks。 有个工具可将 MySQL 表从一个 MySQL 主服务器移动到另一个主服务器。 每个分片实际上是一个 MySQL 表。 他们能够使用该工具按如下方式将包含旧数据的 MySQL 分片转换为 MyRocks 分片
在 MyRocks 主服务器上使用相同的模式创建一个新的空表但使用 RocksDB 存储引擎使用该工具复制数据并从 MySQL 主服务器重放binlog二进制日志到 MyRocks 主服务器。 (该工具已被修改为跳过在目标主机上创建表,因为它已经在前一步中创建过。) 执行阴影读取测试以验证 MyRocks 分片返回的结果与 MySQL 分片的结果相同。 将流量切换到 MyRocks 分片。 (这类似于我们在将 MySQL 表从一个 MySQL 主服务器移动到另一个 MySQL 主服务器时执行的切换。 源主机上的表被重命名以停止新写入,然后在重放赶上后,该表的流量会切换到目标主机。) 对于非键值存储表使用 MyRocks 是我们的一个重大举措。 根据表的不同,空间使用量的减少也有差异。 对于上面提到的第一个表,我们看到每个已移动的分片使用的空间减少了 80% 以上! 对于第二个表,我们看到每个已移动的分片使用的空间只减少了约 50-60%。
3 优化写入
有时复制延迟警报因为 MySQL复制默认情况下会在副本上串行重放主服务器上的并发写。在主服务器上并行写入而在副本上串行重放写入并不适合扩展写入特别是如果他们使用带多核 CPU 的机器。
MySQL 提供两种方法实现这点如下所述。两种方法中都需使用 slave_parallel_workers 配置并行度。
slave_parallel_typeLOGICAL_CLOCK(从 MySQL 8.0.26 开始为 replica_parallel_type)
MySQL 5.7开始可用。即使所有表都在同一逻辑数据库中它也可以在副本上并行执行写。
slave_parallel_typeDATABASE(从 MySQL 8.0.26 开始为 replica_parallel_type)
这需要表位于多个逻辑数据库中才能并行执行写增强存储在 zk 中的数据库配置以跟踪表所在的逻辑数据库。将此信息保存在 zk 而非代码库或静态配置中允许动态更改现有表的逻辑数据库。大多数表都位于默认逻辑数据库因此只需要为不在默认逻辑数据库中的表保留此信息MySQL alter table 语句可用于更改表的逻辑数据库如 alter table logical_db1.table rename logical_db2.mytable。 它不复制数据只是将底层 ibd 文件从一个目录移动到另一个目录速度很快。移动表后我们还会在 zk 更新数据库配置以便应用程序可找到该表他们将一个表移动到其自己的逻辑数据库并启用并行复制。有助减少包含该表的 MySQL 副本上的复制延迟。
4 结论
学习了世界级大厂如何使用各种技术的组合来优化数据库中的读取、写入和空间使用。你们公司如何优化的呢欢迎和我一起交流。
参考
https://www.percona.com/blog/scaling-mysql-a-good-problem-to-have 本文由博客一文多发平台 OpenWrite 发布