热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【openresty】如何处理DogPileEffect

在缓存系统中,缓存总有失效的时候,比如我们经常使用的Memcache和Redis,都会设置超时时间;而一旦缓存到了超时时间失

在缓存系统中,缓存总有失效的时候,比如我们经常使用的 Memcache 和 Redis ,都会设置超时时间;而一旦缓存到了超时时间失效之后,如果此时再有大量的并发向数据库发起请求,就会造成服务器卡顿甚至是系统当机。这就是 Dog Pile Effect 。

Dog Pile Effect

避免这样的 Dog Pile 效应,通常有两种方法:

使用独立的更新进程

使用独立的进程(比如 cron job)去更新缓存,而不是让 web 服务器即时更新数据缓存。举个例子:一个数据统计需要每五分钟更新一次(但是每次计算过程耗时1分钟),那么可以使用 cron job 去计算这个数据,并更新缓存。这样的话,数据永远都会存在,即使不存在也不用担心产生 Dog Pile 效应,因为客户端没有更新缓存的操作。这种方法适合不需要即时运算的全局数据。但对用户对象、朋友列表、评论之类的就不太适用。

使用“锁”

除了使用独立的更新进程之外,我们也可以通过加“锁”,每次只允许一个客户端请求去更新缓存,以避免 Dog Pile 效应。

处理过程大概是这样的:

A 请求的缓存没命中
A 请求“锁住”缓存 key
B 请求的缓存没命中
B 请求需要等待直到“锁”释放
A 请求完成,并且释放“锁”
B 请求缓存命中(由于 A 的运算)

lua-resty-lock - 基于共享内存的非阻塞锁实现。

首先,我们先来消除下大家对锁的抗拒,事实上这把共享内存锁非常轻量。第一,它是非阻塞的,也就是说锁的等待并不会导致 NGINX Worker 进程阻塞;第二,由于锁的实现是基于共享内存的,且创建时总会设置一个过期时间,因此这里不用担心会发生死锁,哪怕是持有这把锁的 NGINX Worker Crash 了。

那么,接下来我们只要利用这把锁按如下步骤来更新缓存即可:

  • 检查某个 Key 的缓存是否命中,如果 MISS,则进入步骤 2。
  • 初始化 resty.lock 对象,调用 lock 方法将对应的 Key 锁住,检查第一个返回值(即等待锁的时间),如果返回 nil,按相应错误处理;反之则进入步骤 3。
  • 再次检查这个 Key 的缓存是否命中,如果依然 MISS,则进入步骤 4;反之,则通过调用 unlock 方法释放掉这把锁。
  • 通过数据源(这里特是 Redis)查询数据,把查询到的结果缓存起来,最后通过调用 unlock 方法释放当前 Hold 住的这把锁。

具体代码实现请参考:lua-resty-lock#for-cache-locks

当数据源故障的时候怎么办?NO_DATA?

同样,我们以上面的代码片段为例,当 Redis 返回出现 err 的时候,此时的状态即不是 MISS 也不是 NO_DATA,而这里统一把它归类到 NO_DATA 了,这就可能会引发一个严重的问题,假设线上这么一台 Redis 挂了,此时,所有更新缓存的操作都会被标记为 NO_DATA 状态,原本旧的拷贝可能还能用的,只是可能不是最新的罢了,而现在却都变成空数据缓存起来了。

那么如果我们能在这种情况下让缓存不过期是不是就能解决问题了?答案是 yes。

lua-resty-shcache - 基于 ngx.shared.DICT 实现了一个完整的缓存状态机,并提供了适配接口
恩,这个库几乎解决了我们上面提到的所有问题:

  1. 内置缓存锁实现
  2. 故障时使用陈旧的拷贝 - STALE

所以,不想折腾的话,直接用它就是的。

 

参考:

[1] 如何处理 Dog Pile Effect

[2] 浅谈 ngx_lua 在 UPYUN 的应用


推荐阅读
  • 电商高并发解决方案详解
    本文以京东为例,详细探讨了电商中常见的高并发解决方案,包括多级缓存和Nginx限流技术,旨在帮助读者更好地理解和应用这些技术。 ... [详细]
  • 本文详细探讨了在Web开发中常见的UTF-8编码问题及其解决方案,包括HTML页面、PHP脚本、MySQL数据库以及JavaScript和Flash应用中的乱码问题。 ... [详细]
  • 本文详细介绍了在Windows系统中如何配置Nginx以实现高效的缓存加速功能,包括关键的配置文件设置和示例代码。 ... [详细]
  • 本文详细介绍了如何在Azure DevOps Services和Azure DevOps Server中调整时区设置,以及这些设置对不同功能的影响。 ... [详细]
  • 我的读书清单(持续更新)201705311.《一千零一夜》2006(四五年级)2.《中华上下五千年》2008(初一)3.《鲁滨孙漂流记》2008(初二)4.《钢铁是怎样炼成的》20 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 深入理解:AJAX学习指南
    本文详细探讨了AJAX的基本概念、工作原理及其在现代Web开发中的应用,旨在为初学者提供全面的学习资料。 ... [详细]
  • 实践指南:使用Express、Create React App与MongoDB搭建React开发环境
    本文详细介绍了如何利用Express、Create React App和MongoDB构建一个高效的React应用开发环境,旨在为开发者提供一套完整的解决方案,包括环境搭建、数据模拟及前后端交互。 ... [详细]
  • 本文详细介绍了HTTP协议中的缓存机制,包括ETag的使用方法和304状态码的意义,探讨了强缓存与协商缓存的区别及其工作原理,旨在帮助开发者更好地理解和优化网站性能。 ... [详细]
  • PHP面试题精选及答案解析
    本文精选了新浪PHP笔试题及最新的PHP面试题,并提供了详细的答案解析,帮助求职者更好地准备PHP相关的面试。 ... [详细]
  • 本文详细记录了腾讯ABS云平台的一次前端开发岗位面试经历,包括面试过程中遇到的JavaScript相关问题、Vue.js等框架的深入探讨以及算法挑战等内容。 ... [详细]
  • 从CodeIgniter中提取图像处理组件
    本指南旨在帮助开发者在未使用CodeIgniter框架的情况下,如何独立使用其强大的图像处理功能,包括图像尺寸调整、创建缩略图、裁剪、旋转及添加水印等。 ... [详细]
  • 探讨符合特定需求的个人网盘选择,包括分享功能、WebDAV支持及长期稳定性等。 ... [详细]
  • 在尝试通过自定义端口部署Spring Cloud Eureka时遇到了连接失败的问题。本文详细描述了问题的现象,并提供了有效的解决方案,以帮助遇到类似情况的开发者。 ... [详细]
  • Flutter 核心技术与混合开发模式深入解析
    本文深入探讨了 Flutter 的核心技术,特别是其混合开发模式,包括统一管理模式和三端分离模式,以及混合栈原理。通过对比不同模式的优缺点,帮助开发者选择最适合项目的混合开发策略。 ... [详细]
author-avatar
每天吃的饱饱的
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有