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

vbe*_*nar 23 java database caching hibernate second-level-cache

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

Dea*_*ing 35

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

  1. 从ORM的"本机"查询格式生成SQL
  2. 对数据库服务器进行网络往返
  3. 解析SQL
  4. 从缓存中获取数据
  5. 将数据序列化为数据库的线上格式
  6. 将数据反序列化为数据库客户端库的格式
  7. 将数据库客户端库的格式转换为语言级对象(即whatevers的集合)

通过在应用程序级别进行缓存,您不必执行任何操作.通常,它是对内存中哈希表的简单查找.有时(如果使用memcache进行缓存)仍然有一个网络往返,但所有其他的东西不再发生.


Vla*_*cea 13

使用强一致性缓存扩展读写事务

通过添加更多副本节点可以相当轻松地扩展只读事务

但是,这不适用于主节点,因为它只能垂直缩放:

这就是缓存发挥作用的地方。对于需要在 Primary 节点上执行的读写数据库事务,缓存可以通过将查询定向到强一致性缓存来帮助您减少查询负载,例如 Hibernate 二级缓存:

扩展读写事务

使用分布式缓存

由于多种原因,将应用程序级缓存存储在应用程序的内存中是有问题的。

首先,应用程序内存有限,因此可以缓存的数据量也有限。

其次,当流量增加并且我们想要启动新的应用程序节点来处理额外的流量时,新节点将以冷缓存启动,这使得问题变得更糟,因为它们会导致数据库负载激增,直到缓存填充数据:

内存中的应用程序缓存

为了解决这个问题,最好让缓存作为分布式系统运行,比如 Redis。这样,缓存的数据量就不受单个节点上内存大小的限制,因为可以使用分片将数据分割到多个节点上。

分布式缓存

并且,当自动缩放器添加新的应用程序节点时,新节点将从同一分布式缓存加载数据。因此,不再存在冷缓存问题。


Rob*_*tie 8

以下是您可能需要此操作的几个原因:

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


Bil*_*win 6

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

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

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

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


Erw*_*out 6

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

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

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

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


mon*_*tux 5

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

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

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

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

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


MBC*_*ook 5

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

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

我知道我会在接下来的一段时间内多次回到某个数据,因此保持原状很重要。DB 必须猜测要在缓存中保留什么,它没有我所做的信息。因此,如果我一遍又一遍地从数据库中获取它,如果服务器繁忙,它可能不在缓存中。我可能会遇到缓存未命中。使用我的缓存,我可以肯定我会成功。对于非平凡获取的数据(即一些连接、某些组函数)而不是单行数据尤其如此。获取主键为 7 的行对于 DB 来说很容易,但如果必须做一些实际工作,缓存未命中的成本要高得多。