如果数据库已经提供缓存,为什么要使用应用程序级缓存?

时间:2010-06-03 06:49:18

标签: java database hibernate caching second-level-cache

现代数据库提供缓存支持。大多数ORM框架也会缓存检索到的数据。为什么这种重复是必要的?

8 个答案:

答案 0 :(得分:34)

因为要从数据库的缓存中获取数据,您仍然需要:

  1. 从ORM的“本机”查询格式生成SQL
  2. 执行到数据库服务器的网络往返
  3. 解析SQL
  4. 从缓存中获取数据
  5. 将数据序列化为数据库的线上格式
  6. 将数据反序列化为数据库客户端库的格式
  7. 将数据库客户端库的格式转换为语言级对象(即whatevers的集合)
  8. 通过在应用程序级别进行缓存,您不必执行任何操作。通常,它是对内存中哈希表的简单查找。有时(如果使用memcache进行缓存)仍有网络往返,但所有其他内容都不再发生。

答案 1 :(得分:8)

以下是您可能需要此选项的几个原因:

  • 应用程序缓存它所需要的内容,因此您应该获得更好的缓存命中率
  • 由于网络延迟,访问本地缓存可能比访问数据库快几个数量级 - 即使网络速度很快

答案 2 :(得分:6)

即使数据库引擎缓存数据,索引或查询结果集,它仍然需要往返数据库,以便您的应用程序从该缓存中受益。

ORM框架在与应用程序相同的空间中运行。所以没有往返。它只是一个内存访问,通常要快得多。

只要需要,框架也可以决定将数据保存在缓存中。当其他并发客户端发出使用缓存的请求时,数据库可能会决定在不可预测的时间使缓存数据到期。

您的应用程序端ORM框架也可能以数据库无法返回的形式缓存数据。例如。以java对象集合的形式而不是原始数据流的形式。如果您依赖数据库缓存,ORM必须将该转换重复到对象中,这会增加开销并降低缓存的好处。

答案 3 :(得分:6)

正确地指出了与网络往返有关的性能考虑因素。

为此,必须补充说,在dbms(非“数据库”)以外的任何地方缓存数据会产生可能过时的数据问题,这些数据仍然被呈现为“最新”。

屈服于改善绩效的诱惑是以牺牲绝对可靠和可保证的正确和一致数据的保证(水密或至少接近于保证)为代价的。

每次准确性和一致性至关重要时,请考虑这一点。

答案 4 :(得分:5)

此外,数据库的缓存可能不如人们想象的那么实用。我从http://highscalability.com/bunch-great-strategies-using-memcached-and-mysql-better-together复制了它 - 它是MySQL特定的,tho。

  

鉴于MySQL有缓存,为什么需要memcached呢?

     

MySQL缓存只与一个实例相关联。这会将缓存限制为一个服务器的最大地址。如果您的系统大于一台服务器的内存,那么使用MySQL缓存将无法正常工作。如果从另一个实例中读取相同的对象,则不会缓存它。

     

查询缓存在写入时无效。你构建了所有缓存,当有人写入时它会消失。根据使用模式,您的缓存可能根本不是缓存。

     

查询缓存是基于行的。 Memcached可以缓存您想要的任何类型的数据,并且不限于缓存数据库行。 Memcached可以缓存在没有连接的情况下可直接使用的复杂复杂对象。

答案 5 :(得分:4)

这里有很多好的答案。我还要补充一点:我知道我的访问模式,数据库没有。

根据我正在做的事情,我知道如果数据最终失效,那不是真正的问题。数据库没有,并且必须使用新数据重新加载缓存。

我知道我会在接下来的几次回到一段数据,所以保持身边很重要。数据库必须猜测缓存中要保留什么,它没有我所掌握的信息。因此,如果我一遍又一遍地从DB中获取它,如果服务器忙,它可能不在缓存中。我可以得到缓存未命中。有了我的缓存,我可以确定我受到了打击。对于非常重要的数据(即一些连接,一些组函数)而不是仅仅一行,尤其如此。获取主键为7的行对于数据库来说很容易,但如果它必须做一些实际的工作,则缓存未命中的成本要高得多。

答案 6 :(得分:3)

毫无疑问,现代数据库正在提供缓存功能,但是当您在站点上拥有更多流量时,那时您需要执行许多数据库事务,那么您将无法获得高性能。因此在这种情况下提高性能hibernate缓存将帮你, 通过优化数据库应用程序。缓存实际上存储了已经从数据库加载的数据,因此当应用程序想要再次访问该数据时,我们的应用程序和数据库之间的流量将减少。应用程序和数据库之间的访问时间和流量将减少。

答案 7 :(得分:2)

那就是说 - 缓存有时会成为负担,实际上会降低服务器的速度。当您有高负载时,缓存的内容和不适合的内容的算法可能不适合进入的请求......您得到的是一个缓存,它在加班时开始像FIFO一样运行...这开始让自己知道当位于缓存后面的表具有比将要缓存在内存中的记录要多得多的时候......

一个很好的权衡是将数据聚类为你想要缓存的内容。有一个主服务器为集群提供更新,根据TTL(生存时间)设置,应该能够为每个表定制发送/泵送更新的时间。

然后,用户节点上的逻辑和数据可以位于内存数据库中打开的同一台服务器上,或者如果必须获取数据,则可以将其设置为使用管道而不是网络调用...

这需要考虑如何使用数据以及何时/如果您是群集然后您必须知道分布式事务(多个数据库上的事务)...但是如果数据被缓存将自己更新,而无需链接到其他数据库空间,然后你可以逃脱这.... .... / / p>

ORM缓存的问题在于,如果数据库是通过另一个应用程序独立更新的,那么ORM缓存可能会变得过时...如果对某个集进行更新,它可能会变得棘手...更新可能更新你的缓存中的东西,它需要有某种算法来识别需要在内存中删除/更新哪些记录(减慢更新!?) - 然后这个算法变得非常棘手且容易出错!

如果使用ORM缓存,那么请遵循一个简单的规则...缓存几乎不会改变的简单对象(例如用户/角色详细信息),并且这些对象的大小很小,并且在请求中被多次命中...如果它除此之外,我建议将数据聚类以提高性能。