使用Redis缓存SQL结果

9
我有一个基于SQL的应用程序,想使用Redis缓存结果。你可以把这个应用看作是一个带有多个SQL表格的通讯录。该应用执行以下任务:
40%的时间:
创建新记录/更新现有记录
批量更新多个记录
查看现有记录
60%的时间:
根据用户的条件搜索记录
这是我目前的方法:
当创建或更新记录时,系统会缓存记录。
当用户执行搜索时,系统将缓存查询结果。
此外,我还有一个Redis查找表(Redis Set),其中存储了MySQL记录ID和Redis缓存键。这样,如果MySQL记录已更改(例如,批量更新),我就可以删除Redis缓存。
如果系统在缓存搜索结果后创建了新记录怎么办?如果新记录符合搜索条件,系统将始终返回旧缓存(不包括新记录),直到缓存被删除(这将不会发生,直到缓存中的现有记录被更新)。
搜索由用户驱动,搜索条件的组合数是无数的。在创建新记录时,无法评估应删除哪个缓存。
到目前为止,唯一的解决方案是在创建记录时删除MySQL表格的所有缓存。然而,这不是一个好的选择,因为每天创建了很多记录。
在这种情况下,实现Redis在MySQL之上的最佳方法是什么?

我认为最好的做法是确定您最频繁的查询并开始处理它们。您提供的描述过于抽象,如果您在数据结构和查询上添加更多细节,那么我可以尝试帮助您创建一些Redis结构,以帮助您快速回答搜索问题。 - Liviu Costea
很抱歉,我无法给你一个确切的答案。搜索查询结果取决于用户的偏好和组合方式,因此可能有无数种可能性。最终,我在页面级别上执行了缓存,即每次页面加载时不会运行相同的SQL两次。 - Derrick C.
2个回答

10
关于PHP和MySQL(我不确定其他语言是否适用),有一件令人惊讶的事情 - 将东西缓存到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 MySQL和基于InnoDB的表,最重要的是足够的RAM和调整过的innodb_buffer_pool_size变量。该变量控制InnoDB允许为其目的分配多少RAM - 越大越好。
您从游戏中淘汰了Redis,使您的代码简单易懂,没有重复数据,没有引入其他系统,让软件来处理数据。即使您从头开始编译所有软件 - 它也不会花费超过一个小时的时间来启动和运行。
或者,您可以忽略我写的内容并寻找使用Redis的解决方案。

1
感谢您的建议。我们已经进行了各种优化,例如MySQL索引、Apache配置等。然而,当涉及到从拥有数百万条记录的表中进行复杂搜索时,最好将它们缓存起来。事实上,我们发现在实施缓存后,总时间从5秒减少到1秒。 - Derrick C.
数百万条记录只是沧海一粟,我处理的数据库规模要大得多,其中50-100m条记录的数据库如果正确设置软件,则可以在毫秒内进行搜索。如果需要5秒钟才能完成,则表明您的MySQL很可能正在运行默认配置 - 这意味着它只分配了8MB的RAM。自然而然,redis会表现得更好。请尝试我的建议,调整您的MySQL。同样的工作做两次比做一次更快是不可能的 - 如果使用redis,则会发生两次。 - N.B.
感谢您的评论。我们已经调整了MySQL数据库设置并升级了硬件。我所说的(5秒)是系统准备数据的总时间,其中包括运行数百个SQL查询到多个表。我们想要缓存SQL结果的主要原因是它是瓶颈。如果实现正确(即在正确的时间清除缓存),它将显着提高整体性能并为我们节省大量硬件成本。 - Derrick C.
2
所以你实际上建议水平扩展Mysql数据库就像扩展redis一样容易,并且在你的数据库耗尽时添加mysql节点比添加缓存层来减轻实际数据库引擎的压力更有意义。这对于TB大小的数据库也适用吗?是否可以轻松地添加廉价的数据库节点?想象一下OSM postgres场景,即使使用极其昂贵的硬件构建索引也可能需要数周时间?我不认为我是站在一个不合理的偏好背后的人 :) - LetsPlayYahtzee
3
非常抱歉让你感到如此沮丧。老实说,我并没有试图拖你到任何地方。你似乎对这个话题过于激动而无法真正地就它进行辩论。我只是真诚地认为你的回答缺乏可信度。如果你认为我的评论也缺乏可信度,那你可以选择接受它。再次道歉,我并不是想要挑起你的情绪。 - LetsPlayYahtzee
显示剩余5条评论

0

我们遇到了同样的问题,我们选择做与您想法相同的事情:删除所有受表影响的查询缓存。虽然不像您所说的那样理想,但幸运的是我们的“写入”并不高达40%,所以目前还可以接受。

这就是基于查询的缓存的本质。作为替代方案,您可以添加基于实体的缓存。不仅缓存搜索结果,而且缓存整个表格,并在内存中进行搜索。我们使用C# LINQ,因此我们可以在内存中执行相当常见的查询,但如果搜索过于复杂,则无能为力。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接