网站高性能架构设计——高性能缓存架构

  从公众号转载,关注微信公众号掌握更多技术动态

---------------------------------------------------------------

一、缓存基础

1.缓存简介

    缓存提升性能的幅度,不只取决于存储介质的速度,还取决于缓存命中率。为了提高命中 率,缓存会基于时间、空间两个维度更新数据。在时间上可以采用 LRU、FIFO 等算法淘汰 数据,而在空间上则可以预读、合并连续的数据。如果只是简单地选择最流行的缓存管理 算法,就很容易忽略业务特性,从而导致缓存性能的下降。

(1)命中率

命中率=命中数/(命中数+没有命中数)

    当某个请求能够通过访问缓存而得到响应时,称为缓存命中。缓存命中率越高,缓存的利用率也就越高。

(2)最大空间

    缓存中可以容纳最大元素的数量。当缓存存放的数据超过最大空间时,就需要根据淘汰算法来淘汰部分数据存放新到达的数据。

    ⼤容量缓存是能带来性能加速的 收益,但是成本也会更⾼,⽽⼩容量缓存不⼀定就起不到加速访问的效果。⼀般来说,建议把缓存容量 设置为总数据量的15%到30%,兼顾访问性能和内存空间开销。

(3)淘汰算法

    缓存的存储空间有限制,当缓存空间被用满时,如何保证在稳定服务的同时 有效提升命中率?这就由缓存淘汰算法来处理,设计适合自身数据特征的淘汰算法能够有效提升缓存命中率。常见的淘汰算法有:

  • FIFO(first in first out)「先进先出」。最先进入缓存的数据在缓存空间不够的情况下(超出最大元素限制)会被优先被清除掉,以腾出新的空间接受新的数据。策略算法主要比较缓存元素的创建时间。「适用于保证高频数据有效性场景,优先保障最新数据可用」。

  • LFU(less frequently used)「最少使用」,无论是否过期,根据元素的被使用次数判断,清除使用次数较少的元素释放空间。策略算法主要比较元素的hitCount(命中次数)。「适用于保证高频数据有效性场景」。

  • LRU(least recently used)「最近最少使用」,无论是否过期,根据元素最后一次被使用的时间戳,清除最远使用时间戳的元素释放空间。策略算法主要比较元素最近一次被get使用时间。当遇到爬虫时,缓存的数据变成非热点数据。「比较适用于热点数据场景,优先保证热点数据的有效性。」

LRU策略更加关注数据的时效性,⽽LFU策略更加关注数据的访问频次。

(4)缓存的使用场景

  • 经常需要读取的数据

  • 频繁访问的数据 热点数据缓存

  • IO 瓶颈数据

  • 计算昂贵的数据

  • 无需实时更新的数据

  • 缓存的目的是减少对后端服务的访问,降低后端服务的压力

(5)缓存更新策略

    缓存中的数据会和数据源中的真实数据有一段时间窗口的不一致,需要利用某些策略进行更新,下面会介绍几种主要的缓存更新策略。

①LRU/LFU/FIFO算法剔除:剔除算法通常用于缓存使用量超过了预设的最大值时候,如何对现有的数据进行剔除。例如Redis使用maxmemory-policy这个配置作为内存最大值后对于数据的剔除策略。

②超时剔除:通过给缓存数据设置过期时间,让其在过期时间后自动删除,例如Redis提供的expire命令。如果业务可以容忍一段时间内,缓存层数据和存储层数据不一致,那么可以为其设置过期时间。在数据过期后,再从真实数据源获取数据,重新放到缓存并设置过期时间。例如一个视频的描述信息,可以容忍几分钟内数据不一致,但是涉及交易方面的业务,后果可想而知。

③主动更新:应用方对于数据的一致性要求高,需要在真实数据更新后,立即更新缓存数据。例如可以利用消息系统或者其他方式通知缓存更新。

有两个建议:

  • 低一致性业务建议配置最大内存和淘汰策略的方式使用。

  • 高一致性业务可以结合使用超时剔除和主动更新,这样即使主动更新出了问题,也能保证数据过期时间后删除脏数据。

(6)缓存粒度控制

    缓存粒度问题是一个容易被忽视的问题,如果使用不当,可能会造成很多无用空间的浪费,网络带宽的浪费,代码通用性较差等情况,需要综合数据通用性、空间占用比、代码维护性三点进行取舍。

    对于缓存的使用,需要对其存储的内容和数量严格限制,并对大小进行估算,通过文档进行维护。

2.缓存如何提高性能

图片

    缓存指的将数据存储在相对较高访问速度的存储介质中,以供系统处理。内存是半导体元件。对于内存而言,只要给出了内存地址,就可以直接访问该地址取出 数据。内存的访问速度很快但价格昂贵。而磁盘是机械器件。磁盘访问数据时,需要等磁盘盘片旋转到磁头下,才能读取相应的数 据。尽管磁盘的旋转速度很快,但是和内存的随机访问相比,性能差距非常大。一般来说,如果是随机读写,会有 10 万到 100 万倍左右的差距。但如果是顺序访问 大批量数据的话,磁盘的性能和内存就是一个数量级的。磁盘的最小读写单位是扇区,目前常见的磁盘扇区是 4K 个字节。操作系统一次会读写多个扇区,所以操作系统的最小读 写单位是块(Block),也叫作簇(Cluster)。当要从磁盘中读取一个数据时,操作系 统会一次性将整个块都读出来。因此,对于大批量的顺序读写来说,磁盘的效率会比随机读 写高许多。

    一方面缓存访问速度快,可以减少数据访问的时间,另一方面如果缓存的数据是经过计算的处理得到的,那么被缓存的数据无需重复计算即可直接使用,因此缓存还起到减少计算时间的作用。例如,一个论坛需要在首页展示当前有多少用户同时在线,如果使用 MySQL 来存储当前用户状态,则每次获取这个总数都要“count(*)”大量数据,这样的操作无论怎么优化 MySQL,性能都不会太高。如果要实时展示用户同时在线数,则 MySQL 性能无法支撑。

    缓存的本质是一个内存的Hash表,网站应用中,数据缓存以一对key、value的形式存储在内存Hash表中。Hash表数据读写的时间复杂度为O(1)。缓存主要用来存放读多写少、很少变化的数据,比如商品的类目信息,热门词的搜索列表信息,热门商品信息等。应用程序读取数据,先到缓存中读取,如果读取不到或数据已失效,再访问数据库并将数据写入到缓存。

    网站数据访问通常遵循二八定律(80%访问落在20%数据上),因此利用Hash表和内存的高速访问特性,将这20%的数据缓存起来,可很好改善系统性能,提高数据读取速度,降低存储访问压力,提高吞吐量。以微博为例:一个明星发一条微博,可能几千万人来浏览。如果使用 MySQL 来存储微博,用户写微博只有一条 insert 语句,但每个用户浏览时都要 select 一次,即使有索引,几千万条 select 语句对 MySQL 数据库的压力也会非常大。

    获取缓存的时候千万不用通过服务调用获取缓存,调用服务花费的时间远远大于获取缓存,这样意义不大

3.缓存失效的方式

  • 被动失效,主要处理如模板变更和一些对时效性不太敏感数据的失效,采用设置一定时间 长度(如只缓存 3 秒钟)这种自动失效的方式。当然,你也要开发一个后台管理界面, 以便能够在紧急情况下手工失效某些 Cache。

  • 主动失效,一般有 Cache 失效中心监控数据库表变化发送失效请求、系统发布也需要清 空 Cache 数据等几种场景。其中失效中心承担了主要的失效功能,这个失效中心的逻 图如下:

图片

    

    失效中心会监控关键数据表的变更(有个中间件来解析 MySQL 的 binglog,然后发现有 Insert、Update、Delete 等操作时,会把变更前的数据以及要变更的数据转成一个消息发 送给订阅方),通过这种方式来发送失效请求给 Cache,从而清除 Cache 数据。

二、缓存带来的复杂性

缓存避免再高峰刷新,避免连接数占满

1.合理使用缓存

①频繁修改的数据不应该使用缓存

当数据的读写的比例很大的时候才推荐使用缓存。

②对于访问频率低的数据不应该使用缓存

因为缓存以内存为存储,内存资源宝贵,不可能将所有数据都进行缓存。

③数据一致性要求的访问不应该使用缓存

一般会对缓存设置过期时间,而当缓存没到过期时间更新了数据这时可能出现数据不一致与脏读

缓存往往针对的是“资源”,当某一个操作是“幂等”的和“安全”的,那么这样的操作就可以被抽象为对“资源”的获取操作,那么它才可以考虑被缓存。有些操作不幂等、不安全,比银行转账

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值