对缓存的一些简单理解

1. 缓存

提起 缓存(cache),一般会想到cpu高速缓存、内存缓存。缓存的本质是将部分的数据使用另一种存取速度更快的介质存储,使系统更快的操作和响应。比如我们将部分的数据从磁盘放到内存中,直接操作内存的数据,这样比从磁盘读取数据要快上几千几万倍。

既然高速的介质这么好用,那为什么不全部使用高速的介质呢,这里直接用我们平常用的内存和磁盘做对比。

首先是价格差异巨大,目前市场价磁盘的价格大概在几毛钱到几块钱1GB,而内存则需要几十块,甚至接近百块1GB,两者价格相差甚远。全部使用内存来存储数据,这口袋的钱顶不住啊。如果是cpu高速缓存的造价跟磁盘比,那根本就是一个天一个地,而且CPU的缓存是按MB单位来算的。英特尔i9-9900K处理器,缓存16MB。

另一个很重要的原因是内存和磁盘的定位不一样,内存是为了系统中能够快速处理数据而设立的,它是即时的,并不具有持久性。开机通电之后内存才会起作用,一旦关机或者停电,数据就消失。这个数据不能永久保存,这也不不是个办法啊。而磁盘就不一样,它虽然比较慢,但是数据是持久保存的。

因为内存和磁盘的定位和特点,导致了它们各自有适合的使用场景,一般情况都是共同使用的。

2.使用缓存的问题

这里开始,只讲内存和数据库相关的东西,缓存数据指的是存储在内存中的副本数据。

平时我们编写的服务器中,因为内存大小的限制,会将常用的部分数据从数据库缓存到内存中,以此来加快服务器的处理速度,增大服务的吞吐量。但是缓存的使用并不是那么简单的,里面含有很多坑,就等着你们来踩。

1. 数据一致性问题

使用缓存最大的问题就是 数据不一致,在复杂的环境下,就更明显,更难处理。

缓存中的数据是数据库的副本,如果是只读操作,那么不会出现什么问题,如果涉及到修改删除等操作,就会存在数据不一致的问题。

举个例子,一个用户的名称为nameA,此时他将名称改为nameB,这时只操作缓存或者数据库,都会导致缓存和数据库数据不一致的问题。

那么有人就说了,同时操作数据库和缓存不就可以了。思路是可以的,但是在并发条件下实现起来可是会出现问题的。

假设有两个线程t1和t2,线程t1是修改操作,线程t2是读取操作,线程t1先修改了数据库,还没来得及修改缓存,此时线程t2读取缓存数据,那么t2读取的数据就不是最新的数据。

那么这时候又有人说,加个锁不就好了,可以用读写锁,并且将锁的粒度变小,以用户id来作为锁。在读的操作所有线程都可以读,但是写操作时,只有一个线程可以操作,这样既保证了数据一致性,又能满足服务器的高性能要求。

这是保证缓存一致性的一个解决方案,但是并不是说这种方法就是完美的,也不一定适合其他应用场景。

在使用缓存的时候,没有最完美最通用的解决方案,只有最适合该场景的方案。

2. 命中率

缓存毕竟只是部分数据的副本,在数据读取的时候,首先会读取缓存中的数据,如果缓存中没有,就会去读取数据库的数据。如果说请求需要的数据缓存中都没有,这时候缓存就没有一点作用。在平时使用缓存的时候,要评估哪些是常用的数据。

在提高命中率时,有一个较为通用的方法。当一个数据不在缓存中时,此时线程会读取数据库,在读取完后将该数据存入缓存中,下次读取的时候,直接读取缓存就行了。

3. 空间整理

内存的空间是比较小的,在使用的过程中缓存的数据会越来越多,这时候就要进行数据清理了,将不常用,不必要的数据删除。那么用什么方法找出不常用的数据呢,这里列出比较常用的几种缓存清除策略。

FIFO ( first in first out)

先进先出策略,很简单粗暴,在清除的时候,最开始存入的数据,将先被清除。这在某些特定场合下是可以的,但是一般情况下使用这个策略会显得程序非常死板,不够"智能"。

LFU(less frequently used)

最少使用策略。指的是某些数据使用次数最少,将最先被清除。常用的做法是标记数据的命中次数,以此来判断数据是否比较常用。

一般来说命中次数还得加上一个时间段的限制,记录某个时间段内数据的命中次数,防止出现某些数据在一开始是常用,后来根本不会被使用到。

比如某个玩家一开始沉迷某舰娘,毕竟那么大,哦不对,是那么好玩,该玩家天天登录,理所当然的他个人信息命中次数很高。但某一天他氪不动也肝不动,弃坑了,之后都没登录过,那么这个数据其实是不常用的了。

LRU (less recently used)

最近最少使用策略,标记数据最近一次使用的时间,在清除时,将释放太久没有被使用的数据。这个适用热点数据场景中。

设置过期时间

添加缓存的时候,就给该数据标记存活时间,超过了这个时间,该数据将被释放。这个Redis中挺经常用到的。

随机清理

如它的名称一样,清除的时候随机清理。多么粗暴的清理方法,可能会有程序会使用,的吧(我并不确定)。我的阅历少,还没见过使用这种方法的应用场景,如果有,麻烦告诉我一声。

4. 缓存雪崩

缓存雪崩是指大量的请求直接透过了缓存层请求数据库(缓存穿透),导致数据库压力过大,严重的会出现数据库宕机。

缓存穿透出现可能是由于原缓存过期(或其他原因被清除),新的缓存未存放,导致请求穿透到数据库。也有可能是服务器刚启动,还来不及缓存数据。

解决方案就是要避免大量缓存在同一时刻过期,还有在服务器启动时,将请求量从小到大的引导到服务器中。

3. 总结

为什么要使用缓存

因为它速度快,仅此而已

使用缓存的问题

这里就不总结了,看文章吧

其实还想写一写在具体的业务场景中缓存的设计以及在设计时考虑和抉择,不过写起来挺长的,还是放到另一篇文章里好了。

参考文章

猜你喜欢

转载自juejin.im/post/5da577cce51d4524f007f363
今日推荐