Java高级——缓存的使用场景
当你的应用扛不住,知道要使用缓存了,应该怎么做呢?
场景1:和数据库中的数据结构保持一致,原样缓存
这种场景是最常见的场景,也是很多架构使用缓存的适合,最先涉及到的场景。
基本就是数据库里面啥样,我缓存也啥样,数据库里面有商品信息,缓存里面也放商品信息,唯一不同的是,数据库里面是全量的商品信息,缓存里面是最热的商品信息。
每当应用要查询商品信息的时候,先查缓存,缓存没有就查数据库,查出来的结果放入缓存,从而下次就查到了。
这个是缓存最最经典的更新流程。这种方式简单,直观,很多缓存的库都默认支持这种方式。
场景2:列表排序分页场景的缓存
有时候我们需要获得一些列表数据,并对这些数据进行排序和分页。
例如我们想获取点赞最多的评论,或者最新的评论,然后列出来,一页一页的翻下去。
在这种情况下,缓存里面的数据结构和数据库里面完全不一样。
如果完全使用数据库进行实现,则按照某种条件将所有的行查询出来,然后按照某个字段进行排序,然后进行分页,一页一页的展示。
但是当数据量比较大的时候,这种方式往往成为瓶颈,首先涉及的数据库行数比较多,而且排序也是个很慢的活,尽管可能有索引,分页也是翻页到最后,越是慢。
在缓存里面,就没必要每行一个key了,而是可以使用Redis的列表方式进行存储,当然列表的长短是有限制的,肯定放不下数据库里面这么多,但是大家会发现其实对于所有的列表,用户往往没有耐心看个十页八页的,例如百度上搜个东西,也是有排序和分页的,但是你每次都往后翻了吗,每页就十条,就算是十页,或者一百页,也就一千条数据,如果保持ID的话,完全放的下。
如果已经排好序,放在Redis里面,那取出列表,翻页就非常快了。
可以后台有一个线程,异步的初始化和刷新缓存,在缓存里面保存一个时间戳,当有更新的时候,刷新时间戳,异步任务发现时间戳改变了,就刷新缓存。
场景3:计数缓存
计数对于数据库来讲,是一个非常繁重的工作,需要查询大量的行,最后得出计数的结论,当数据改变的时候,需要重新刷一遍,非常影响性能。
因此可以有一个计数服务,后端是一个缓存,将计数作为结果放在缓存里面,当数据有改变的时候,调用计数服务增加或者减少计数,而非通过异步数据库count来更新缓存。
计数服务可以使用Redis进行单个计数,或者hash表进行批量计数
场景4:重构维度缓存
有时候数据库里面保持的数据的维度是为了写入方便,而非为了查询方便的,然而同时查询过程,也需要处理高并发,因而需要为了查询方便,将数据重新以另一个维度存储一遍,或者说将多给数据库的内容聚合一下,再存储一遍,从而不用每次查询的时候都重新聚合,如果还是放在数据库,比较难维护,放在缓存就好一些。
例如一个商品的所有的帖子和帖子的用户,以及一个用户发表过的所有的帖子就是属于两个维度。
这需要写入一个维度的时候,同时异步通知,更新缓存中的另一个维度。
在这种场景下,数据量相对比较大,因而单纯用内存缓存memcached或者redis难以支撑,往往会选择使用levelDB进行存储,如果levelDB的性能跟不上,可以考虑在levelDB之前,再来一层memcached。
场景5:较大的详情内容数据缓存
对于评论的详情,或者帖子的详细内容,属于非结构化的,而且内容比较大,因而使用memcached比较好。
欢迎关注笔者,笔者持续更新中