2

缓存(4) —— 结构化缓存

 3 years ago
source link: https://www.cyningsun.com/02-18-2021/high-concurrency-cache-design.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

缓存(4) —— 结构化缓存

在众多应用中,缓存都是标配,使用缓存都能获得非常巨大的性能提升。然而却少有人能把缓存用好,使用缓存的服务,随着需求的迭代都会不可避免的陷入一种怪圈:
业务侧

  1. 为了优化接口性能增加缓存
  2. 同一接口复杂度高、性能差、缺少可维护性,无法开发新需求

运维侧

  1. 提高存储和查询容量应对使用压力
  2. 成本压力倒逼业务再次优化,提高缓存使用率

在反复的折腾之下,系统难以维护,最终不得不走向整体“重构”。

以微博为例,当打开微博时,页面主要数据构成有:分类列表(左侧);微博列表(中间);个人信息;关注、粉丝、微博数(最右侧)。
weibo.png

按照一般的后台设计准则,假设页面所需的数据拆解如下:
structure.png

需要重点说明几点:

  1. 微博不等于微博正文

    微博指微博ID,微博正文指微博的内容。

  2. 微博列表也是一种数据

    微博列表代表的是微博ID的集合

《如何设计RPC接口》 中我们提到过一个观点:所有的数据都等于 ID + Content,同时 ID 又可以以集合的形式存在。

假设查询微博列表是一个单独的API接口,各种数据在系统中的表达分别为:post(微博)、profile(个人信息)、stat(点赞、评论等计数、点赞)。那么通常的实现是:

SELECT ... FROM post LEFT JOIN profile LEFT JOIN stat ...

两张大表直接进行关联。如果扛不住,就添加缓存,将查询结果缓存。

那么,在开发过程中是否真的无法逃出这一怪圈?答案当然是否定的,本文的目的就是承接 《系统设计之概念与关系》《如何设计RPC接口》 ,谈谈如何设计,才能让数据落地到缓存。

结构化缓存

具体来看怎么做的,实际上可以将以上查询进行拆分:

SELECT * FROM post WHERE ...
SELECT * FROM profile WHERE id in (...)
SELECT * FROM stat WHERE id in (...)

很多人看到这里会直摇头,这不就直接会导致一次API调用,会直接导致 N 次数据库查询。那你怎么能这样拆分呢?

事实上并非如此,由于缓存的存在,后两个数据库查询都会命中应用缓存,最终只会有一次简单查询到数据库。考虑最差的情况应用缓存没有命中,后两个数据库查询也会极大概率命中数据的缓存。同时,随着业务的迭代,可以放心使用组合模式,不断组合其他数据,而不用担心复杂度的高度。再次,考虑 KOL 的微博访问量大,可以沿着结构树不断向上添加缓存(例如:在微博列表层添加缓存)。最后,如果分布式缓存压力太大,还可以组合本地缓存使用。

最重要的是,所有以上提到的所有优化点,都可以使用组合模式实现,而不用大幅度调整代码,避免陷入开发、优化、重构的怪圈。

再看拆分前,由于使用SQL关联操作,会在业务的发展过程中不断面临挑战:

  1. 关联查询可能导致大范围的扫表,频繁磁盘IO,性能差
  2. 缓存命中率低
  3. 业务迭代,额外查询其他数据,复杂度不断叠加

在本文末尾,再次总结提及的几个关键观点:

  1. 数据查询有且仅有三种模式
    1. 根据条件,分页查询 ID 列表
    2. 根据 ID 查询内容
    3. 根据 ID 列表批量查询内容
  2. 所有的结构仅仅存在两种关系
    1. 并列(兄弟)关系
  3. 结构化和组合模式是应对复杂性有效方法

    缓存不过是一种形式的复杂性

当然此种实现并非没有代价。显然,如果数据的访问频率很低,极少的结果才会命中缓存,那么效果就微乎其微。而梳理数据关系、结构,以及按照拆分的形式实现代码,将花费不少的时间,在讲究快速开发、先撑住再优化的今天,很容易让开发者采取非此即彼的决策。

本文作者:cyningsun
本文地址https://www.cyningsun.com/02-18-2021/high-concurrency-cache-design.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-ND 3.0 CN 许可协议。转载请注明出处!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK