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

存储高性能[缓存]

虽然我们可以通过各种手段来提升存储系统的性能,但在某些复杂的业务场景下,单纯依靠存储系统的性能提升不够的,典型的场景如下。Cl)需要经过复杂运算后得出的数据,存储系统无能为力。

虽然我们可以通过各种手段来提升存储系统的性能,但在某些复杂的业务场景下,单纯依 靠存储系统的性能提升不够的,典型的场景如下 。
Cl )需要经过复杂运算后得 出的数据,存储系 统无能为力 。
例如,一个论坛需要在首页展示当前有多少用户同时在线,如果使用 MySQL 来存储当前
用户状态, 则每次获取这个总数都要“ count (*) ”大量数据,这样的操作无论怎么优化 MySQL, 性能都不会太高。如果要实时展示用户同时在线数,则 MySQL 性能无法支撑。
( 2 ) 读多写少 的数据,存储系统有心无力 。
绝大部分在线业务都是读多写少。例如,微博、淘宝、微信这类互联网业务,读业务占了
整体业务量 的 90% 以上 。以微博为例 : 一个明星发一条微博 ,可能几千万人来浏览 。如果使用 MySQL 来存储微博,用户 写微博只有一条 insert 语句,但每个用户浏览时都要 select 一次 ,即 使有索引, 几千万条 se lect 语句对 MyS QL 数据库的压力也会非常大。
缓存就是为了弥补存储系统在这些复杂业务场景下 的不足 , 缓存 的基本原理就是将可能重 复使用 的 数据放到内 存中 ,一次生成,多次使用, 避免每次使用都去访问存储系统。
以使用最广泛的 Memcache 为例,其基本的架构如下图所示 。

在这里插入图片描述

缓存能够带来性能的大幅提升, 以 Memcache 为例, 单台 Memcache 服务器简单的 key-value 查询能够达到 5 万以上的 TPS 。
缓存虽然能够大大减轻存储系统的压力,但同时也给架构引入了更多复杂性 。架构设计时
如果没有针对缓存的复杂性进行处理,某些场景下甚至会导致整个系统崩溃。接下来我们逐一分析缓存的架构设计要点。


缓存穿透

缓存穿透是指缓存没有发挥作用,业务系统虽然去缓存中查询数据,但缓存中没有数据, 业务系统需要再次去存储系统中查询数据。通常情况下有两种情况 : 存储数据不存在,以及生
成缓存数据需要耗费大量时 间或资源。
• 存储数据不存在
第一种情况是被访 问 的数据确实不存在 。一般情况下,如果存储系统中没有某个数据,则 不会在缓存中存储相应的数据,这样就导致用户查询 的 时候,在缓存中找不到对应的数据,每 次都要去存储系统中再查询一遍,然后返回数据不存在 。缓存在这个场景中并没有起到分担存 储系统访问压力的作用。
通常情况下, 业务上读取不存在的数据的请求量并不会太大,如果出现一些异常情况,例 如, 被黑客攻击 ,故意大量访 问某些不存在数据 的业务 , 有可能会将存储系统拖垮。
这种情况 的解决办法 比较简单, 如果查询存储系统的数据没有找到, 则直接设置一个默认 值( 可以是空值 ,也可以是具体的值)并存到缓存中, 这样第二次读取缓存时就会获取默认值, 而不会继续访 问 存储系统 。
缓存数据生成耗费大量时间或资源
第二种情况是存储系统中存在数据,但生成缓存数据需要耗费较长时间或耗费大量资源。
如果刚好在业务访 问 的时候缓存失效了,那么也会出现缓存没有发挥作用,访 问 压力全部集中 在存储系统上的情况。
典型 的就是电商 的商品分页,假设我们在某个电商平台上选择“手机”这个类别进行查看, 由于数据巨大,不能把所有数据都缓存起来,只能按照分页进行缓存 。 由于难 以预测用 户到底
会访 问哪些分页 ,因此业务上最简单 的就是每次点击分页 的时候按分页 计算和生成缓存。通常 情况下这样实现是基本满足要求的,但如果被竞争对手用爬虫来遍历的 时候,系统性能就可能 出现 问 题。
具体的场景如下 :
(1 )分页缓存的有效期设置为 l 天 , 因为设置太长时间,缓存不能反映真实 的 数据。
( 2 )通常情况下,用户不会从第 l 页到最后 l 页全部看完,一般用户访 问 集 中 在前 10 页, 因 此第 10 页 以后 的 缓存过期失效的可能性很大。
( 3 )竞争对手每周来爬取数据 ,爬虫会将所有分类的所有数据全部遍历 ,从第 1 页到最后l 页都会读取,此时很多分页缓存可能都失效了 。
(4 )由于很多分页都没有缓存数据 , 从数据库中生成缓存数据又非常耗费性能( o r d er by
limit 操作),因此爬虫会将整个数据库全部拖慢 。
这种情况并没有太好的解决方案,因为爬虫会遍历所有的数据,而且什么时候来爬取也是
不确定的 , 可能每天都来,也可能每周来一次,还可能一个月来一次,我们也不可能为了应对 爬虫而将所有数据永久缓存。通常的应对方案要么就是识别爬虫,然后禁止访问,但这可能影 响 SEO 和推广;要么就是做好监控,发现问题后及时处理,因为爬虫不是攻击,不会进行暴力 破坏,对系统的影响是逐步的,监控发现问题后有时间进行处理。


缓存雪崩

缓存雪崩是指当缓存失效(过期)后引起系统性能急剧下降的情况。 当缓存过期被清除后, 业务系统需要重新生成缓存,因此需要再次访问存储系统,再次进行运算,这个处理步骤耗时
几十毫秒甚至上百毫秒。而对于一个高并发 的业务系统来说,几百毫秒 内 可能会接到几百上千 个请求。由于旧的缓存己经被清除,新的缓存还未生成,并且处理这些请求的线程都不知道另 外有一个线程正在生成缓存,因此所有的请求都会去重新生成缓存,都会去访问存储系统,从 而对存储系统造成巨大的性能压力。这些压力又会拖慢整个系统 , 严重的会造成数据库右机,
从而形成一系列连锁反应,造成整个系统崩溃。
缓存雪崩的常见解决方法有两种:更新锁机制和后台更新机制 。
. 更新锁
对缓存更新操作进行加锁保护,保证只有一个线程能够进行缓存更新,未能获取更新锁的 线程要么等待锁释放后重新读取缓存,要么就返回空值或默认值。
对于采用分布式集群的业务系统,由于存在几十上百台服务器,即使单台服务器只有一个 线程更新缓存,但几十上百台服务器一起算下来也会有几十上百个线程同时来更新缓存,同样 存在雪崩 的问 题。因此分布式集群的业务系统要完美实现更新锁机制,需要用到分布式锁,如
Zoo Keeper 。
• 后台更新
由后台线程来更新缓存,而不是由业务线程来更新缓存,缓存本身的有效期设置为永久, 后台线程定时更新缓存。
后台定时机制需要考虑一种特殊的场景,当缓存系统内存不够时,会“踢掉” 一些缓存数 据,从缓存被“踢掉”到下一次定时更新缓存的这段时间内,业务线程读取缓存返回空值,而 业务线程本身又不会去更新缓存,因此业务上看到的现象就是数据丢了 。 解决的方式有两种:
Cl )定时读取。
后台线程除了定时更新缓存,还要频繁地去读取缓存(例如, l 秒或 100 毫秒读取一次) ,
如果发现缓存被“踢了”就立刻更新缓存 ,这种方式实现简单,但读取时间间隔不能设置得太 长,因为如果缓存被踢了,缓存读取间隔时间又太长,则这段时间内业务访问都拿不到真正 的 数据而是一个空 的缓存值,用户体验一般。
(2 )消息队列通知。
业务线程发现缓存失效后 ,通过消息队列发送一条消息通知后台线程更新缓存。可能会出
现多个业务线程都发送了 缓存更新消息,但其实对后台线程没有影响,后台线程收到消息后更 新缓存前可以判断缓存是否存在,存在就不执行更新操作 。 这种方式实现依赖消息队列,复杂 度会高一些,但缓存更新更及时,用户体验更好。
后台更新既适应单机多线程的场景,也适合分布式集群的场景,相比更新锁机制要简单一些
后台更新机制还适合业务刚上线的时候进行缓存预热。缓存预热指系统上线后,将相关的 缓存数据直接加载到缓存系统,而不是等待用户访问才来触发缓存加载。


缓存热点

虽然缓存系统本身的性能比较高,但对于一些特别热点的数据,如果大部分甚至所有的业 务请求都命中同一份缓存数据,则这份数据所在的缓存服务器的压力也很大。例如,某明星微 博发布“我们、] ”来宣告恋爱了,短时间内上千万的用户都会来围观。
缓存热点 的解决方案就是复制 多 份缓存, 将请求分散到 多个缓存服务器上,减轻缓存热点 导致的单台缓存服务器压力。以新浪微博为例,对于粉丝数超过 100 万的明星,每条微博都可 以生成 100 份缓存,缓存的数据是一样的,通过在缓存的 key 里面加上编号进行区分,每次读 缓存时都随机读取其中某份缓存 。


推荐阅读
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • MySQL语句大全:创建、授权、查询、修改等【MySQL】的使用方法详解
    本文详细介绍了MySQL语句的使用方法,包括创建用户、授权、查询、修改等操作。通过连接MySQL数据库,可以使用命令创建用户,并指定该用户在哪个主机上可以登录。同时,还可以设置用户的登录密码。通过本文,您可以全面了解MySQL语句的使用方法。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了软件测试知识点之数据库压力测试方法小结相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • MySQL插入数据的四种方式及安全性分析
    本文介绍了MySQL插入数据的四种方式:插入完整的行、插入行的一部分、插入多行和插入查询结果,并对其安全性进行了分析。在插入行时,应注意字段的定义和赋值,以提高安全性。同时指出了使用insert语句的不安全性,应尽量避免使用。建议在表中定义相关字段,并根据定义的字段赋予相应的值,以增加插入操作的安全性。 ... [详细]
  • Explain如何助力SQL语句的优化及其分析方法
    本文介绍了Explain如何助力SQL语句的优化以及分析方法。Explain是一个数据库SQL语句的模拟器,通过对SQL语句的模拟返回一个性能分析表,从而帮助工程师了解程序运行缓慢的原因。文章还介绍了Explain运行方法以及如何分析Explain表格中各个字段的含义。MySQL 5.5开始支持Explain功能,但仅限于select语句,而MySQL 5.7逐渐支持对update、delete和insert语句的模拟和分析。 ... [详细]
author-avatar
手机用户2602879695
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有