【问题标题】:Using Redis to cache SQL result使用 Redis 缓存 SQL 结果
【发布时间】:2015-10-10 04:55:29
【问题描述】:

我有一个基于 SQL 的应用程序,我喜欢使用 Redis 缓存结果。您可以将应用程序视为具有多个 SQL 表的地址簿。该应用程序执行以下任务:

40% 的时间:

  • 创建新记录/更新现有记录
  • 批量更新多条记录
  • 查看现有记录

60% 的时间:

  • 根据用户条件搜索记录

这是我目前的做法:

  • 系统会在创建或更新记录时缓存记录。
  • 当用户进行搜索时,系统会缓存查询结果。

最重要的是,我有一个 Redis 查找表 (Redis Set),它存储 MySQL 记录 ID 和 Redis 缓存键。这样,如果 MySQL 记录已更改(例如,批量更新),我可以删除 Redis 缓存。

如果系统缓存搜索结果后创建了一条新记录怎么办?如果新记录与搜索条件匹配,系统将始终返回旧缓存(不包括新记录),直到缓存被删除(直到更新缓存中的现有记录才会发生)。

搜索由用户驱动,搜索条件的组合数不胜数。创建新记录时,无法评估应该删除哪个缓存。

到目前为止,唯一的解决方案是在创建记录时删除 MySQL 表的所有缓存。但是,这不是一个好的选择,因为每天都会创建大量记录。

在这种情况下,在 MySQL 之上实现 Redis 的最佳方式是什么?

【问题讨论】:

  • 我认为最好确定您最常见的查询并开始处理这些查询。您给出的描述过于抽象,如果您在数据结构和查询上添加更多详细信息,那么我可以尝试帮助您创建一些 redis 结构,这将帮助您对搜索给出非常快速的答案。
  • 希望能给你一个答案。不幸的是,搜索查询完全取决于用户偏好,并且组合数不胜数。我最终在页面级别执行缓存,即没有为每次页面加载运行两次相同的 SQL。

标签: mysql database caching redis


【解决方案1】:

当涉及到 PHP 和 MySQL(我不确定其他语言)时,这是一件令人惊讶的事情 - not 将内容缓存到 memcached 或 Redis 实际上更快。快多了。基本上,如果您只是构建您的应用程序并查询 MySQL - 您会从中获得更多收益。

现在是“为什么”部分。

InnoDB,默认引擎,是一个极好的引擎。具体来说,它的内存管理(分配和其他)优于任何内存存储解决方案。这是事实,你可以查一下或者相信我的话——它至少会和 Redis 一样好。

现在在您的应用程序中发生了什么 - 您查询 MySQL 并将结果缓存到 redis。然而,MySQL 也足够聪明,可以保存缓存的结果。您刚刚所做的是创建连接到 Redis 所需的附加文件描述符。您还使用了一些存储 (RAM) 来缓存 MySQL 已经缓存的结果。

这里还有另一个有趣的部分——提供 PHP 脚本的首选方式是使用php-fpm——它比任何mod_* 废话都快得多。归根结底,php-fpm 是一个生成子进程的主管进程。在提供脚本后它们不会关闭,这意味着它们会缓存与 MySQL 的连接——连接一次,使用多次。基本上,如果您使用php-fpm 提供脚本,它们将重用已经建立的与 MySQL 的连接,这意味着您不会为每个请求打开和关闭连接 - 这是非常资源友好的,它可以让您快速连接到mysql。 MySQL,内存效率高,缓存结果比 Redis 快得多。

现在所有这一切对您意味着什么 - 通过正确的设置,您可以编写简单、容易、不涉及 Redis 的小代码,并消除您在缓存失效方面可能遇到的所有问题,而您赢了不要浪费你的内存两次包含相同的数据。

您需要的成分:

  • php-fpm
  • MySQLInnoDB 基于表,最重要的是 - 足够的 RAM 和调整 innodb_buffer_pool_size 变量。它控制了 InnoDB 允许为其分配多少 RAM - 越大越好。

你从游戏中淘汰了 Redis,你让你的代码保持简单和易于维护,你没有复制数据,你没有在游戏中引入额外的系统,你让本应处理数据的软件来完成它工作。即使您从头开始编译所有软件,也要以相当便宜的代价换取最大的实用性 - 启动并运行它不会花费超过一个小时左右的时间。

或者,您可以忽略我写的内容并使用 Redis 寻找解决方案。

【讨论】:

  • 感谢您的建议。我们已经进行了各种优化,例如 MySQL 索引、Apache 配置等。但是,当谈到从具有数百万条记录的表中进行复杂搜索时,最好将它们缓存起来。事实上,我们发现在实现缓存后,整体时间从 5 秒减少到 1 秒。
  • 数百万条记录是沧海一粟,我使用的数据库要大得多,如果您正确设置软件,跨越 50 - 100m 条记录的数据库可以在几毫秒内搜索到。它需要 5 秒的事实很好地表明您的 MySQL 很可能正在运行默认配置 - 这意味着它只有 8MB 的内存分配给它。自然,redis 会胜过它。试试我的建议,调整你的 MySQL。两次做同样的工作不可能比做一次更快 - 如果你使用 redis,做两次就会发生。
  • 感谢您的评论。我们已经调整了 MySQL 数据库设置并升级了硬件。我的意思是(5 秒)是系统准备数据的总时间,其中包括对多个表运行数百个 SQL 查询。我们要缓存 SQL 结果的主要原因是因为它是瓶颈。如果正确实施(即在正确的时间清除缓存),它将显着提高整体性能并为我们节省大量硬件成本。
  • 所以您实际上是在建议水平扩展 Mysql 数据库与扩展 redis 一样容易,并且在数据库耗尽而不是添加缓存层的情况下添加 mysql 节点更有意义吸收实际 db 引擎的热量。这是否也适用于您的数据库为 TB 大小的情况?甚至可以轻松地添加数据库的廉价节点吗?想象一个 OSM postgres 场景,即使使用极其昂贵的硬件,构建索引也可能需要数周时间?我不认为我是在这里支持不合理偏好的人:)
  • 真的很抱歉让你这么不高兴。老实说,我不是想把你拖到任何地方。你似乎在这个问题上过热而无法真正争论它。我只是真的认为你的回答缺乏可信度。另一方面,如果您认为我的评论缺乏可信度,您可以忍受它。再次抱歉。不是有意激怒你或任何事情。
【解决方案2】:

我们遇到了同样的问题,我们选择做同样的事情:删除所有受表影响的查询缓存。它不像你说的那样理想,但幸运的是我们的“写”没有高达 40%,所以到目前为止还可以。 这就是基于查询的缓存的本质。作为替代方案,您可以添加基于实体的缓存。不要只缓存搜索结果,而是缓存整个表并在内存中进行搜索。我们使用 C# LINQ,因此我们可以在内存中进行非常常见的查询,但如果搜索过于复杂,那么您就不走运了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多