精华内容
下载资源
问答
  • 我想把查询结果缓存在一个地方(网上说mencached可以,但是我看了也不知道怎么用),当再次使用时不再连接数据库取数据.比如说我查询到所有姓赵的用户,结果有两页,我把结果缓存起来,然后从缓存中取出第一页数据,当点击...
  • 原标题:如何优化你的MySQL查询缓存优化你的MySQL查询缓存在MySQL服务器上进行查询,可以启用高速查询缓存。让数据库引擎在后台悄悄的处理是提高性能的最有效方法之一。当同一个查询被执行多次时,如果结果是从缓存...

    原标题:如何优化你的MySQL查询缓存

    优化你的MySQL查询缓存

    在MySQL服务器上进行查询,可以启用高速查询缓存。让数据库引擎在后台悄悄的处理是提高性能的最有效方法之一。当同一个查询被执行多次时,如果结果是从缓存中提取,那是相当快的。

    但主要的问题是,它是那么容易被隐藏起来以至于我们大多数程序员会忽略它。在有些处理任务中,我们实际上是可以阻止查询缓存工作的。

    1、// query cache does NOT work

    2、$r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()");

    3、// query cache works!

    4、$today = date("Y-m-d");

    5、$r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'");

    6、// query cache does NOT work

    7、$r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()");

    8、 // query cache works!

    9、$today = d

    更多干货关注老男孩教育公众号返回搜狐,查看更多

    责任编辑:

    展开全文
  • 显示行号|选择喜欢的代码风格默认GitHubDuneLakeSidePlateauVibrantBlueEightiesTranquil有时缓存代码中的单个对象会很有用,比如有些需要很大开销获取的数据或者一些结果集不怎么变化的数据库查询。你可以使用一些...

    显示行号

    |

    选择喜欢的代码风格

    默认

    GitHub

    Dune

    LakeSide

    Plateau

    Vibrant

    Blue

    Eighties

    Tranquil

    有时缓存代码中的单个对象会很有用,比如有些需要很大开销获取的数据或者一些结果集不怎么变化的数据库查询。你可以使用一些缓存软件将这些数据存放在内存中以便下次高速获取。如果你获得数据后把他们存起来,下次请求直接从缓存里面获取数据,在减少数据库负载的同时能极大提高性能。

    许多流行的字节码缓存方案也能缓存定制化的数据,所以更有理由好好使用它们了。APCu、XCache 以及 WinCache 都提供了 API,以便你将数据缓存到内存中

    最常用的内存对象缓存系统是 APCu 和 Memcached 。APCu 对于对象缓存来说是个很好的选择,它提供了简单的 API 让你能将数据缓存到内存,并且很容易设置和使用。APCu 的局限性表现在它依赖于所在的服务器。另一方面,Memcached 以独立的服务的形式安装,可以通过网络交互,这意味着你能将数据集中存在一个高速存取的地方,而且许多不同的系统能从中获取数据。

    值得注意的是当你以 CGI(FastCGI) 的形式使用 PHP 时,每个进程将会有各自的缓存,比如说,APCu 缓存数据无法在多个工作进程中共享。在这种情况下,你可能得考虑 Memcached 了,由于它独立于 PHP 进程。

    通常 APCu 在存取速度上比 Memcached 更快,但是 Memcached 在扩展上更有优势。如果你不希望应用程序涉及多个服务器,或者不需要 Memcached 提供的其他特性,那么 APCu 可能是最好的选择。

    使用 APCu 的例子:

    // 检查缓存里,是否有数据存储为 'expensive_data'

    $data = apc_fetch('expensive_data');

    if ($data === false) {

    // 没有被缓存,则存储到APC中为之后使用

    apc_add('expensive_data', $data = get_expensive_data());

    }

    print_r($data);

    注意在 PHP 5.5 之前,APC 同时提供了对象缓存与字节码缓存。APCu 是为了将 APC 的对象缓存移植到 PHP 5.5+ 的一个项目,因为现在 PHP 有了内建的字节码缓存方案 (OPcache)。

    更多PHP 缓存扩展阅读

    发表评论

    展开全文
  • 缓存是什么?这是一种无需重复计算或者...这些都需要占用大量资源,所以最好是把结果缓存起来,以备未来快速重复使用。为什么要进行缓存?在这里,我认为有必要聊聊之前提到的这些任务到底需要多少资源成本。现代...

    缓存是什么?这是一种无需重复计算或者反复获取,即可快速得到反馈的方法,用于提升性能水平并优化资源成本。下面咱们马上进入正题,聊聊缓存的实现方式。

    我们假设这里需要调用某个 API、查询某数据库服务器或者只是选取几个高达数百万位的数字并进行相加。这些都需要占用大量资源,所以最好是把结果缓存起来,以备未来快速重复使用。

    为什么要进行缓存?

    在这里,我认为有必要聊聊之前提到的这些任务到底需要多少资源成本。现代计算机中存在多个缓存层。举例来说,我们建立一个 Web 服务器,其中配备英特尔至强 E5-2960 v3 CPU 以及 2133 MHz DIMM。缓存访问的实质,就是计算需要占用处理器的“多少个周期”;因此在使用这块主频为 3.06 GHz(性能模式)的处理器时,可以推导出相关延迟(这里使用的英特尔处理器皆为 Haswell 架构):

    • 一级缓存(每核心):4 个周期,约 1.3 纳秒——12x 32 KB + 32 KB
    • 二级缓存(每核心):12 个周期,约 3.92 纳秒延迟——12x 256 KB
    • 三级缓存(共享):34 个周期,约 11.11 纳秒延迟——30 MB
    • 系统内存:约 100 纳秒延迟——8x 8 GB

    各个缓存层的存储容量越大,距离也就越远。这是处理器设计当中做出的取舍,旨在实现最佳平衡。举例来说,各个核心的内存量越大,则其一般来讲与核心芯片间的距离越远,意味着延迟、机会成本以及功耗成本都将随之上升。在这方面,电荷的实际运行距离会造成重大的影响;每一秒,该距离都相当于增加了数十亿倍。

    另外,这里我没有提到磁盘延迟,因为我们很少使用磁盘。为什么?这个嘛,我可能需要解释一下……在 Stack Overflow,除了备份或者日志服务器的其它一切生产负载都在 SSD 上实现。我们的本地存储通常分为以下几层:

    • NVMe SSD: 约 120 微秒
    • SATA 或 SAS SSD: 约 400 至 600 微秒
    • 机械磁盘:2 至 6 毫秒

    具体性能一直在变化,所以大家不用关注这些数字。我们需要了解的是这些存储层之间的差异量级。下面,让我们整理出一份更明确的比较清单(全部使用最佳性能数字):

    • L1: 1.3 纳秒
    • L2: 3.92 纳秒 (延迟为 3 倍)
    • L3: 11.11 纳秒 (延迟为 8.5 倍)
    • DDR4 RAM: 100 纳秒 (延迟为 77 倍)
    • NVMe SSD: 12 万纳秒 (延迟为 92307 倍)
    • SATA/SAS SSD: 40 万纳秒 (延迟为 30 万 7692 倍)
    • 机械磁盘: 2–6 毫秒 (延迟为 153 万 8461 倍)
    • Microsoft Live 登录: 12 次转发,5 秒 (延迟约为 38 亿 4615 万 3846 倍)

    如果大家对这些数字没啥概念,那么下图使用滑块整理出了可视化版本的比较结果(可以看到各缓存层的变化趋势):

    cd382144096f0fb25ae3aeebb5ed10a7.png

    由于性能数字和量级差距过大,让我们再添加一些日常环境中经常出现的重要指标。假设我们的数据源为 X——这个 X 究竟是什么无所谓,可以是 SQL、微服务、宏服务、leftpad 服务、Redis 或者磁盘文件等,最重要的是需要将源性能与内存性能进行比较。下面来看源性能:

    • 100 纳秒(来自内存——快!)
    • 1 毫秒(延迟为 1 万倍)
    • 100 毫秒(延迟为 100 万倍)
    • 1 秒(延迟为 1 亿倍)

    看到这里,相信大家已经能够理解,即使延迟仅为 1 毫秒,其速度也要远低于内存的速度。这里的单位分别为毫秒、微秒与纳秒,三者皆为 1000 进位——1000 纳秒 =1 微秒。

    但是,并不是所有缓存都属于本地缓存。例如,我们会在自己的 Web 层之后利用 Redis 建立共享缓存(后文将具体介绍)。假设我们正在打算通过内部网络进行访问,整个往返需要 0.17 毫秒,此外我们还要发送一些数据。对于小型数据包,延迟大约在 0.2 毫秒到 0.5 毫秒之间。虽然这样的延迟仍是本地内存的 2000 至 5000 倍,但仍比大多数数据源快得多。请注意,这些数字看起来比较小,是因为我们设定的是一套小型本地局域网。云端延迟通常会更高,实际延迟水平需要自行测量。

    在获取数据的同时,我们可能还打算以某种方式进行处理。也许我们需要进行相加、过滤、对其进行编码等。总而言之,我们希望只对〈x〉进行一次处理,后续直接提取处理结果。

    有时候,我们希望降低延迟;有时候则希望节约 CPU 资源。这两项因素基本上构成了引入缓存机制的全部理由。接下来,我们会从反方向进行论证。

    为什么不使用缓存?

    我知道很多朋友最讨厌缓存,这部分一定特别符合您的心意。是的,我这人就是典型的墙头草。

    前面说了这么多好处,为什么有时候不适合用缓存呢?这是因为任何一项决策都需要进行利弊权衡。是的,任何一项决策。即使是面对简单如时间成本或者机会成本之类的问题,权衡也仍有必要。

    在缓存方面,添加缓存可能带来以下成本:

    • 在必要时清除缓存值(缓存失效——我们将在后文中具体说明)
    • 缓存占用内存
    • 访问缓存造成的延迟(与直接访问数据源相比)
    • 系统结构更为复杂,因此调试工作将面临更高的时间与精力成本

    每当有新功能可能需要配合缓存时,我们都需要进行评估……而且评估工作难度很大。

    在 Stack Overflow,我们的架构遵循一项总体性的原则:尽可能简单。所以简单,就是易于评估、推理、调度以及变更。只有在必须复杂时,才允许其复杂。缓存当然也要遵循这一原则。因为缓存会带来更多工作量与精力投入,所以除非必要,否则不用。

    所以,我们得首先回答以下几个问题:

    • 使用缓存能够显著提高速度吗?
    • 我们能够节约哪些资源?
    • 这些数据值得存储吗?
    • 存储的数据是否值得清理(例如使用垃圾收集机制)?
    • 这是否会立刻带来大型对象堆?
    • 我们需要多久进行一次清理?
    • 每个缓存条目会有多少次命中?
    • 缓存失效是否会影响到其它功能?
    • 未来会出现多少变种?
    • 我们的缓存分配是否被用于计算密钥?
    • 采用本地还是远程缓存?
    • 不同用户之间是否共享同一缓存?
    • 不同站点之间是否共享同一缓存?
    • 管理以及调试过程是否非常困难?
    • 缓存属于什么级别?

    这些都是缓存决策当中必须搞清楚的问题。本文也将尽可能将其纳入讨论。

    Stack Overflow 的缓存分层

    在 Stack Overflow,我们也有自己的“一级 / 二级”缓存。但为了避免与真正的名词相混淆,这里我会强调更准确的术语表达。

    • “全局缓存”:内存内缓存(全局、每 Web 服务器、未命中时由 Redis 支持)
    • 其对应用户顶栏,在整个网络中共享使用。
    • 命中本地内存(共享键空间),而后是 Redis(共享键空间,使用 Redis database 0)。
    • “站点缓存”:内存内缓存(每站点、每 Web 服务器,未命中时由 Redis 支持)
    • 通常为各站点的问题列表或者用户列表。
    • 命中本地内存(第站点键空间,使用前缀),而后使用 Redis(每站点键空间,使用 Redis 数据库)
    • “本地缓存”:内存内缓存(每站点、每 Web 服务器、无后备任何支持)
    • 通常为易于获取的内容,且规模过大但又不足以动用 Redis 堆。
    • 仅命中本地内在(每站点键空间,使用前缀)。

    这里说的“每站点”是什么意思?Stack Overflow 与 Stack Exchange 站点网络是一套多租户架构。Stack Overflow 只是数百个站点中的一个。这意味着 Web 服务器上的单一进程托管着全部站点,因此我们只在必要时才会进行缓存拆分。另外,我们必须对缓存进行清理(后文将具体介绍如何清理)。

    Redis 之前,我们讨论过了服务器与共享缓存的工作原理。接下来让我们再快速了解一下共享内容的实现基础:Redis。那么,Redis 是什么?这是一套开源键 / 值数据存储方案,其中包含多种实用数据结构,大量发布 / 订阅机制以及坚如磐石的稳定性水平。

    为什么要选择 Redis,而非其它解决方案?答案很简单,因为 Redis 就够了。它表现得很好,能够充分满足我们对于共享缓存的需求。另外,它的稳定性令人稀奇,速度表现也无可挑剔。我们很清楚要如何使用 Redis、如何进行监控、如何加以维护。而且在必要时,我们也能对 Redis 库做出调整。

    Redis 成为我们整体基础设施中最不用操心的组成部分。我们基本上已经将其视为一种理所当然的解决方案(当然,我们也设置有高可用性副本)。在选择基础设施时,我们不仅需要根据潜在价值进行调整,同时也要考虑调整可能带来的成本、时间投入以及风险。如果现在的解决方案就能很好地完成任务,我们为什么要投入大量时间与精力,甚至承担由此引发的风险?当然没必要。时间总是宝贵的,拿来做点有意义的事情不是更好?例如——讨论哪种缓存服务器更强!

    下面,我们通过几个 Redis 实例对应用问题进行具体剖析(但这些应用都处于同一组服务器上)。先从下图开始:

    2b306ca549d2fcc8d40f75e3b39611af.png

    我们首先把从上周二(2019 年 7 月 30 日)以来的一些快速统计数据整理出来。这些数据涵盖了各大主要设备上的全部实例(这里按组织方式进行分类,而非按性能分类……单一实例可能就足以承载我们的全部日常负载):

    • 我们的 Redis 物理服务器拥有 256 GB 内存,但实际使用量只有不足 96 GB。
    • 每天共需处理 15 亿 8655 万 3473 条命令(由于需要复制备份,实际命令量为 37 亿 2658 万 897 条,峰值期间每秒 8 万 6982 条命令)。
    • 整体服务器的 CPU 平均利用率为 2.01%(峰值期间为 3.04%)。其中最活跃的实例,资源占比也不足 1%。
    • 共计 1 亿 2441 万 5398 个活动键(计入复制操作,则为 4 亿 2281 万 8481 个)。
    • 这些数字贯穿 3 亿 806 万 5226 次 HTTP 命中(其中 6471 万 7337 次命中问题页面)。

    备注:Redis 并未限制性能水平,我们也没有设定任何限制。这里只列出实例当中的实际活动情况。

    除了缓存需求之外,我们选择 Redis 还有其它一些理由:我们还使用其中的发布 / 订阅机制实现 websockets 的实时计分及复制等功能。Redis 5.0 还添加了 Streams,它非常适合我们的 websocket。所以在其它基础设施组件更新到位之后(主要受到 Stack Overflow 企业版的限制),我们可能会进行一波全面迁移。

    内存内与 Redis 缓存

    之前提到的所有实例,都包含一个内存内缓存组件,有一些还由 Redis 服务器负责提供后备。

    内存内非常简单,我们就是把数据缓存在……内存里面。以ASP.NET MVC 5 为例,以往的作法是HttpRuntime.Cache 。如今,我们已经做好ASP.NET Core 的迁移准备,所以现在的方法变成了 MemoryCache 。二者之间的区别不大,也不是很重要;它们都提供了一种能够在特定时间段内缓存对象的方法。这就足够了,我们需要的就是这个。

    对于以上几种缓存方式,我们会选择一个“数据库 ID”,具体与我们在 Stack Exchange Network 上的站点相关,因此由我们的 Sites 数据库表决定。Stack Overflow 为 1,Server Fault 为 2,Super User 为 3 等等。

    对于本地缓存,大家可以通过多种方式实现。我们的方法非常简单:ID 为缓存态的一部分。对于全局缓存(共享),ID 为 0。我们进一步(出于安全)为每个缓存添加前缀,以避免这些应用级缓存与可能存在的任意其它键名称发生冲突。下面来看一个示例键:

    prod:1-related-questions:1234

    这是 Stack Overflow(ID 为 1)上关于问题 1234 的侧栏相关问题。如果只使用内存内缓存,那么序列化将不再重要,因为我们可以直接缓存任何对象。但是,如果我们将某个缓存对象发送至某处(或者由某处发回),则必须对其快速进行序列化。正因为如此,我们才编写出自己的 protobuf-net。Protobuf 是一种二进制编码格式,在速度与分配方面都非常高效。我们希望缓存的简单对象可能如下所示:

    public class RelatedQuestionsCache{public int Count { get; set; }public string Html { get; set; }}

    在利用 protobuf 属性控制序列化之后,则如下所示:

    [ProtoContract]public class RelatedQuestionsCache{[ProtoMember(1)] public int Count { get; set; }[ProtoMember(2)] public string Html { get; set; }}

    现在,假设我们希望将该对象缓存在站点缓存当中。那么整个流程将如下所示(代码稍微简化了一点):

    public T Get(string key){var cacheKey = GetCacheKey(key);var local = memoryCache.Get(cacheKey);if (local != null){return local.GetValue();}if (redisCache.CanRead(cacheKey)){var remote = redisCache.StringGetWithExpiry(cacheKey)if (remote.Value != null){var wrapper = RedisWrapper.From(remote);memoryCache.Set(key, wrapper, remote.Expiry);return remote.Value;}}return null;}

    当然,这里的代码经过了大大简化,但我们不会遗漏任何重要的内容。

    为什么要使用 RedisWrapper?因为类似于 Redis,它通过将值与 TTL(生存时间)搭配起来实现了平台概念同步。它还允许我们对 null 值进行缓存,且无需使用特殊的处理方式。换句话说,这样我们就能分辨“内容没有经过缓存”和“经过缓存的内容为 null”之间的区别。如果大家对 StringGetWithExpiry 抱有兴趣,我再多提几句。它属于 StackExchange.Redis 方法,负责将多项命令整合起来以通过一次调用同时返回值与 TTL(不再消耗双倍时间)。

    使用 Set 对值进行缓存的方式完全相同 :

    1. 将该值缓存在内存当中。
    2. 将该值缓存在内存 Redis 当中。
    3. (可选)提醒其它 Web 服务器该值已经更新,并指示各服务器刷新副本。

    整合流水线

    这里我打算花点时间聊聊非常重要的一点:我们的 Redis 连接(通过 StackExchange.Redis)并整合为一条流水线。大家可以把它想象成一条传送带,每个人都可以向其中添加点什么,之后它会转到某个地方,最终再转回来。在第一项传送物品抵达终点或者被发回期间,我们可以已经向流水线添加了成千上万的其它内容。但如果一次性添加的物品过大,大家就得等它先处理完成,之后才能继续添加其它物品。

    这些内容可以是独立的,但传送带本身是共用的。在我们的示例当中,传送带就是连接,而物品就是命令。如果有大规模负载进入或者传回,那么传送带就会被暂时占用。具体来说,如果当前大家正在等待某项结果,但有个讨厌的大玩意把整条流水线堵塞了一、两秒,就有可能造成负面影响——这就是超时。

    我们经常看到有人建议向 Redis 注入少量多次负载,用以降低超时问题的发生机率;但这么干其实没什么用——除非您的流水线非常非常快。这种作法虽然减少了超时现象,但也只是把超时换成了排队等待。

    最重要的,是要意识到计算机中的流水线就像现实世界中的流水线一样。无论最窄处在哪里,这都是约束通量的瓶颈所在。只不过计算机中的流水线是一种动态通道,更像是一条可以扩展、弯曲或者扭结的软管,因此其瓶颈也不是一成不变的。它的瓶颈可能是线程池耗尽(注入了太多命令,或者是需要发出太多结果),可能是网络传输带宽,也有可能是某些东西影响到了我们对网络带宽的使用。

    需要注意的是,在这样的延迟级别之下,我们不能再以秒作为看待问题的时间单位。对我来说,我考虑的不会是每秒 1 Gb,而是每毫秒 1 Mb。如果我们能够在大约 1 毫秒或者更短的时间内完成网络传输,则证明该负载确实很重要,会带来能够实际测量到且具备现实影响的传输时耗。换言之,关注延迟时尽量从小单位入手。在处理较短的持续时长时,我们必须把系统限制与同一持续时间内的相对约束条件进行等比例比较。面对毫秒级的延迟,再去谈那些通常以秒为单位的计算概念及指标,恐怕只会搞乱我们的思维以及决策方式。

    流水线:重试

    流水线自身的性质,使我们很难自信地使用重试命令。在这个残酷的世界里,我们的流水线更多变成了机场里运送行李的传送带——缓慢,而且只能等待。

    大家可能都遇到过这样的情况,我们去机场,早早办好了行李托运,看着自己心爱的小箱子消失在传送带尽头。这时,我们突然发现候机厅旁边就有更划算的行李运送服务站。没问题,机场服务人员超有耐心,答应把行李退回来,转交给外面的第三方托运商。然后……行李不见了。去哪儿了?没人知道。

    也许我们的包裹被交到了地勤管理员手上,但在回程的时候不知哪去了——也有可能连地勤那关都没到。我们不知道,我们也不清楚该不该重新发送一次。如果再发一次,包裹还是消失了,该怎么办?对方知不知道我们的担心?我们不想把情况弄得太复杂,但现在我们确实感到困惑而无助。好了,下面我们来聊聊另一个问题:缓存失效。

    缓存失效

    在前文当中,我一直反复提到清理,缓存清理是如何起效的?Redis 拥有一项发布 / 订阅功能,您可以在这里推送消息,所有订阅方都将收到您的消息(消息也会发送至所有副本位置)。利用这个简单的概念,我们可以轻松建立起一条订阅缓存清理流水线。当我们打算提前删除某个值(而非等待 TTL 自然消失)时,我们只需要将该键名发送至流水线与监听程序(比如事件处理程序),即可将其从本地缓存当中清理出去。

    具体步骤包括:

    1. 通过 DEL 或者 UNLINK 将该值从 Redis 当中清理出去。或者,利用新的值替代该值。
    2. 将该键广播至清理频道。

    其中的顺序非常重要,因为顺序错乱会发生争用,最终甚至有可能重新获取旧值。请注意,我们并没有推送新值。我们的目的并不是推送新值。我们所做的就是在需要时,从 Redis 处获取该值。

    将一切组合起来:GetSet根据前文所述,我们的操作基本上可以归纳为以下形式:

    var val = Current.SiteCache.Get(key);if (val == null){val = FetchFromSource();Current.SiteCache.Set(key, val, Timespan.FromSeconds(30));}return val;

    但是,我们可以大大改进具体方式。首先,这里有不少重复,更重要的是代码会在缓存过期时产生数百项同时针对 FetchFromSource() 的调用。如果负载强度过大,该怎么办?而且根据之前选择使用缓存的情况来看,其强度显然不可能太小。所以,我们需要更好的计划。

    下面来看最常用的方法:GetSet()。好的,命名是个难题,很多人可能已经想打退堂鼓了。那我们到底想在这里实现什么目标:

    • 如果存在,获取该值。
    • 如果值不存在,则计算或者获取该值(并将其注入缓存当中)。
    • 避免对同一值进行多次计算或者获取。
    • 确保尽可能缩短用户的等待时长。

    我们可以使用一部分属性来实现优化。假设您现在正在加载网页,或者是 1 秒或 3 秒之前开始加载,这很重要吗?Stack Overflow 中的问题及结果是否会发生很大变化?答案是:确实会发生变化,但并不一定很重要。也许您只是参与了一项投票、进行了一项编辑、或者发布了一条评论。对于这些能够引起用户关注的部分,我们需要利用缓存确保其及时更新。但对于正在同时加载该页面的数百位其他用户而言,这一点差别就显得无足轻重了。

    也就是说,我们拥有一定的浮动空间。下面,就让我们利用这点空间改善性能效果。

    以下为目前我们 GetSet中的内容(是的,另有一个等效异步版本):

    public static T GetSet(this ImmediateSiteCache cache,string key,Func lookup,int durationSecs,int serveStaleDataSecs,GetSetFlags flags = GetSetFlags.None, Server server = Server.PreferMaster)

    其中的关键参数为 durationSecs 以及 serveStaleDataSecs。调用则通常如下所示(这里假设一个简单例子以供讨论):

    var lookup = Current.SiteCache.GetSet>("User:DisplayNames
    展开全文
  • 将第一次查询的空值缓存起来, 同时设置一个比较短的过期时间 2、使用布隆过滤算法(BloomFilter) 用于检查一个元素是否存在, 返回结果有两种: 可能存在或一定不存在 缓存击穿 缓存击穿是指在高并发情况下, 同时...

    对于使用分布式缓存实现大数据的存储,可能会遇到缓存穿透、 缓存击穿、 缓存雪崩等问题,这些是什么呢,该如何解决呢

    缓存穿透

    缓存穿透是指大量查询没有命中缓存, 直接去到数据库中查询, 如果查询量比较大, 会导致数据库的查询流量大, 对数据库造成压力。
    解决
    1、缓存空值
    将第一次查询的空值缓存起来, 同时设置一个比较短的过期时间
    2、使用布隆过滤算法(BloomFilter)
    用于检查一个元素是否存在, 返回结果有两种: 可能存在或一定不存在

    缓存击穿

    缓存击穿是指在高并发情况下, 同时查询一个key时, key值由于某种原因突然失效(设置过期时间或缓存服务宕机) , 就会导致同一时间, 这些请求都去查询数据库了
    解决
    使用排斥锁来实现有序地请求数据库, 减少数据库的并发压力。

    缓存雪崩

    缓存雪崩一般是指发生大规模的缓存失效情况, 例如, 缓存的过期时间同一时间过期了, 缓存服务宕机了
    解决
    1、采用分散过期时间来解决
    2、采用分布式集群来实现缓存服务

    展开全文
  • 有时系统的瓶颈在I/O操作上,比如你不想重复的查询数据库,你想把结果缓存起来,只在数据发生变化时才去数据查询来更新缓存。 与上面的情况类似,有些场合下我们需要进行快速的查找来决定如何处理新来的请求
  • 缓存是什么?这是一种无需重复计算或者反复获取,即可...这些都需要占用大量资源,所以最好是把结果缓存起来,以备未来快速重复使用。为什么要进行缓存?在这里,我认为有必要聊聊之前提到的这些任务到底需要多少资...
  • 14. Yii 2.0 数据缓存

    2016-09-03 03:08:27
    这里以 Yii 2.0 高级版为例,介绍如何使用 Yii 的数据缓存机制(一般用 memcache 作为缓存介质),将及时性要求不高的数据缓存起来,提高页面的响应速度。 首先,修改数据库配置文件 /advanced/common/config/main...
  • 一般面试中考察的题目通常是由三类组成的,基础面试题、进阶面试题、...因为是海量数据,所以我们就无法将每个键值都存起来,然后再从结果中检索数据了,比如数据库中的 select count(1) from tablename where id='...
  • 5.3.2 查询结果和路径表达式 93 5.3.3 OQL的其他特性 95 5.4 C++语言绑定概述 98 5.5 对象数据库概念设计 99 5.5.1 ODB与RDB概念设计的区别 99 5.5.2 EER模式到ODB模式的映射 100 小结 101 ...
  • 5.8.4 如何创建数据字典 160 5.9 使用静态数据字典视图 160 5.10 与数据库对话 161 5.10.1 连接Oracle 161 5.10.2 OEM 161 5.10.3 SQL*Plus 162 5.11 Oracle实用程序 162 5.11.1 数据泵的导出和导入...
  • 发现查询结果起来仍是通过缓存来查询的 因为sql没有打印两次 [code="java"] package com.vavi.test; import org.hibernate.Session; import com.vavi.dao.HibernateSessionFactory; import ...
  • 4.2.3 块缓冲区缓存 135 4.2.4 共享池 141 4.2.5 大池 143 4.2.6 JAVA池 144 4.2.7 流池 145 4.2.8 自动SGA内存管理 145 4.2.9 自动内存管理 147 4.3 小结 148 第5章 Oracle进程 149 5.1 服务器进程 149 ...
  • 11.2 结果缓存 385 11.2.1 运行机制 386 11.2.2 何时使用 391 11.2.3 缺陷与谬误 391 11.3 并行处理 392 11.3.1 运行机制 392 11.3.2 何时使用 408 11.3.3 缺陷与谬误 408 11.4 直接路径插入 412 ...
  • 把数据缓存起来,可以避免在查询或更新数据时花费多余的时间,而这时间通常是从磁盘获取数据时用来等待磁盘寻址的。把执行计划缓存起来,可以避免重复分析执行计划时带来额外的CPU及各种资源的开销。通过在内存中...
  • 成都 2K+ <strong>问题补充</strong><br/><div class="quote_title">wuxianjun 写道</div><div class="quote_div">你把sql打印出来去数据库查询下看需要多长时间。 如果时间很长的话分析出查询耗时...
  • MySQL 调优之性能监控

    2020-06-07 15:35:54
    查询缓存:当执行查询语句的时候,先去查询缓存中的数据,如果能找到结果则直接返回,如果没有,再去数据库中进行查询。如果数据更新比较频繁,只要表更新,缓存就会被清空,此时不建议使用缓存,命中率会比较低
  • 2.3.8 查询结果 35 2.3.9 关系数据库的体系结构小结 35 2.4 MySQL数据库系统 35 2.4.1 MySQL系统体系结构 36 2.4.2 SQL接口 37 2.4.3 解析器 38 2.4.4 查询优化器 39 2.4.5 查询的执行 40 2.4.6 ...
  • 当我们想取出某个分类的子分类树的时候,基本思路就是递归,当然,出于效率问题不建议每次递归都查询数据库,通常的做法是先讲所有分类取出来,保存到PHP数组里,再进行处理,最后还可以将结果缓存起来以提高下次...
  • 和传统的 t-sql书籍不同,本书以独特的 “技巧 ”形式来介绍知识点,涵盖了数据处理(增删改、视图、索引、存储过程、触发器等)、数据应用(web服务、 clr集成、分布式查询等)和数据库配置(主体、安全、数据库...
  •  诚然,这个数据的确显示数据库的内存命中率低得可怜,但是我想告诉你的是,这是一个在线分析(OLAP)系统的数据库,运行着很多非常大的查询,每个查询搜索的范围都在上亿条记录以上,那这个结果不是很正常吗?...
  • 他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7...
  • 他认为对于SQL的学习是永无止境的,相信每一个查询Oracle数据库的人都需要精通SQL语言,才能写出高效的查询。他参与本书的编写就是为了帮助别人实现这一目标。 目录 封面 -11 封底 -10 扉页 -9 版权 -8 版权声明 -7...

空空如也

空空如也

1 2 3 4 5
收藏数 96
精华内容 38
关键字:

数据库查询结果如何缓存起来