缓存为王

计算机技术经过几十年的发展,无论是规模、性能还是容量都已经与往日大不相同,尤其是近年来互联网的不断普及,对以互联网为基础的系统架构提出了更多挑战。

而互联网架构系统与传统IT系统最大的区别就是对于缓存的使用。合理使用缓存可以提高系统的响应速度,扩大容量,减少成本,可以毫不夸张的讲,缓存是互联网架构中最关键的环节,是每一个互联网公司必须面对和攻克的一个难题。

今天,我来为大家介绍一本17年12月刚刚出版的新书《深入分布式缓存:从原理到实践》,这本书由来自蚂蚁金服、京东、网联、新浪、同程等一线架构师共同编写,他们结合自己的工作实践,对分布式缓存的基础概念、开源框架的使用、应用案例三个方面进行了详细讲解。

第一篇文章,我们先来学习书中关于缓存的基础概念。

在商业世界中有有一种说法是“现金为王”,现金流是否充足决定了一家企业的生死。而在互联网、移动互联网乃至整个软件世界中,有一个与之相近的说法是“缓存为王”,缓存是否使用得当,同样能决定系统的成败。那么究竟什么是缓存呢?

什么是缓存

缓存:存储在计算机上的一个原始数据复制集,以便于访问。                             ——维基百科

光看这个定义有些抽象,我们可以用实际生活中的买菜为例。

在一个城市有一座农贸市场,全城的居民都可以在这里来买菜,但是对于那些住的远的居民来说,每次买菜花在路上的时间太多了,不划算。怎么解决这个问题呢?一些有商业头脑的人会先到农贸市场去买一大堆菜,然后在居民区附近开一个菜店,居民们就可以在菜店中就近买菜了。

在这个例子里,菜店就是一个缓存系统,里面的菜就是缓存数据,菜店提前储备了居民要买的菜,节省了居民买菜的时间,当然居民们也要为此付出一点代价,那就是菜价比农贸市场贵了一点点。

在计算机系统中,缓存无处不在。比如常见的CPU缓存,就是位于CPU与内存之间的临时存储器,容量比内存小但是读取速度比内存快得多。有了CPU缓存,我们就可以解决CPU运算速度与内存读写速度不匹配的矛盾。

如果按照软件系统所处的位置给缓存分类,可以分为:

  • 客户端缓存
  • 网络缓存
  • 服务端缓存

如果按照规模和部署方式分类,又可以分为:

  • 单体缓存
  • 集群缓存
  • 分布式缓存

知道了什么是缓存之后,接下来一个问题就是:为什么要使用缓存?

为什么使用缓存

在回答这个问题之前,作者让我们先要思考另外一个问题:你认为一个成功的软件产品,最重要的因素是哪一点?

能解决用户的痛点? 能够为企业或个人带来利益? 具有不错的用户黏性?

这些都不是,作者认为成功的软件产品最重要的因素是良好的用户体验。

用户体验,就是用户在使用一个产品或者系统之前、使用期间和使用之后的全部感受。

说到感受,那又涉及到很多方面了,比如界面好不好看,操作是否人性化,系统响应速度是否够快等等。

那这些感受中,我们最在乎哪一点呢?要看最在乎哪一点,不是看有了什么我们会更好,而是得看少了什么会让我们无法接受。

以玩网络游戏为例,《传奇》很多人都玩过吧,那个游戏的画面我就不吐槽了,要多简陋有多简陋,但是即使现在仍然有不少人在玩类似《传奇》的游戏,因此界面好不好看不是最重要的感受。

操作人性化呢?要说电脑软件中操作最最不人性化的,非游戏软件莫属,尤其是《魔兽世界》这一类MMORPG游戏,当年我玩魔兽设置了几十个快捷键,恨不得把键盘里面的按键全部用上,这种设定一点也不人性化,但也没有阻挡玩家们对游戏的热爱。

最关键的感受是系统响应速度,也叫系统性能。其它问题都可以忍,但是如果让玩家放一个技能就在屏幕前等1分钟,还时不时出现卡顿、掉线的问题,那玩家是绝对不能忍。

缓存技术,可以说是提高系统性能的一剂灵丹妙药。作者在书中用了一个比喻,我觉得非常到位:如果说音乐是时间的艺术,那么缓存就是软件系统中关于时间的艺术

“缓存为王”本质上就是系统性能为王,对用户而言就是用户体验为王。

无处不在的缓存

如果用最简单的架构来描述互联网系统,它会是客户端 -> 代理服务器 -> 服务端 的三层结构。 jiagou

为了提高系统性能,程序猿们想尽了各种办法,在这三层结构中使用了各式各样的缓存。

客户端缓存

客户端是用户接触软件系统的唯一介质,用户上网时使用的浏览器,手机中安装的APP都可以被称为客户端。

比如优酷手机APP,在我的 -> 我的缓存 菜单里,可以看到所有下载到手机上的缓存(视频)信息。

为什么会有这个选项呢?其实就是我们可以提前将视频下载到手机上,这样当我们要看视频的时候,就不需要连接互联网,直接观看本地视频就可以了。

对于用户来讲,这样做可以减少对网络的依赖,即使没有联网也能回看聊天记录,提高了用户体验。

除了APP,浏览器中也有缓存。大家如果仔细观察可以发现,如果第一次打开一个页面,时间会比较长,但是第二次再打开的时候时间就缩短很多了。

这背后的原因就是浏览器在第一次打开页面的时候,会将页面信息保存到缓存文件中,当用户第二次请求同一个页面地址时,浏览器会通过一个e-tag的标签询问后端服务器,页面信息是否有变化?如果有变化,则重新获取页面信息,如果没有变化,则直接取本地的缓存。

liuchengtu1

网络缓存

在客户端与服务端之间有一层代理服务器,它用来接收客户端的请求,然后转发给不同的服务端。

也许有人会问,干嘛要在中间多加一层,直接让客户端请求发给指定的服务端不好么?

如果要解释这个问题,那又可以写一本书了。这里只能简单解释一下,代理服务器存在的目的,是为了网络安全(防止恶意的网络攻击),负载均衡(让每一个服务端都能均匀的接收客户端请求,而不至于一些太多,一些太少)以及缓存等等。

说代理服务器是互联网系统架构中必不可少的一层,它是客户端与服务端之间的看门人。

网络缓存就是保存在这些代理服务器上的缓存,而代理服务器又分为正向代理和反向代理两种,因此网络缓存也就分为正向代理缓存和反向代理缓存。

zhengxiangproxy fanxiangproxy

不管是哪一种缓存,它们的工作原理都是相似的,就是将服务端返回给客户端的数据保存在代理服务器上,同时记录下客户端请求参数、缓存有效时间等关键信息,当客户端发送同样的请求时,代理服务器判断是到服务端重新拉取数据,还是直接返回本地缓存。

网络缓存的工作原理与客户端缓存比较接近,不同点在于代理服务器可以存储更多的缓存信息,性能比手机APP或者个人PC机要好很多。但对于用户而言,网络缓存增加了网络通信的开销。

服务端缓存

服务端缓存是整个缓存体系中的重头戏,因为相对于客户端和代理端的单一架构而言,服务端本身就是一个集合了数据库、中间件、应用系统等等一系列节点的复合体,而这每一个节点,都可以在缓存上大作文章。

关于一些重要的、应用广泛的服务端缓存,后续文章会做详细介绍,这里只做一个概要性描述。

  • 数据库缓存

数据库是整个服务端的心脏,所有的业务数据都保存在这里,软件系统中的功能又是基于这些业务数据才能正常运行,因此数据库属于IO密集型的应用,并发达到上千甚至上万都不足为奇。

为了提高数据库的性能,主流数据库自身都提供了完备的缓存机制。比如MYSQL就提供了查询缓存,它的工作原理如下:

  1. MYSQL在收到查询请求后,将查询语句的hash值与缓存中已有查询语句的hash值作比对。
  2. 如果hash值相同,则从缓存中直接获取查询结果。
  3. 如果hash值不同,则查询本地磁盘,并将结果放到缓存中。
  4. 根据提前设定的策略,定期清理超时、不常用的缓存数据。

MYSQL的查询缓存虽然能够减少IO,但是使用起来也有很多难点。

  1. 配置参数众多,不同场景下不同参数起到的效果也不一样。
  2. SQL语句、表结构设计、表数据量的大小对缓存使用效果都有影响,需要进行专门的调优测试。

不仅是MYSQL,其它主流数据库都有类似问题,缓存技能带来便利,用得不好也有可能成为魔鬼,它对研发人员技术能力的挑战比以往更高。

  • 平台级缓存

不同的开发语言平台带有自身的平台级缓存框架。它可以帮助开发人员实现简单的缓存功能,减少开发人员的工作量。

比如IOS的SDWebImage图片缓存框架,PHP的Smarty缓存模板库,Java的Ehcache,JBossCache等等。

平台级缓存的特点是小巧玲珑,常用于数据量不大、应用节点少、性能要求不高的场景。对于开发人员来讲,使用平台级缓存开发速度快,上手也简单。

但是不要忘记,我们使用缓存的目的是提高系统性能,一旦平台级缓存的性能达不到系统性能要求时,就要考虑使用应用级缓存了。

  • 应用级缓存

应用级缓存更庞大,更复杂,但是性能也更好。它独立于业务系统之外,需要有自己专门的服务器,提供了缓存操作的API,由开发人员自己通过代码来实现缓存机制。

近年来,应用级级缓存成为了NoSQL(非关系型数据库)的胜场,比如大名鼎鼎的Redis和MongoDB。

相比于关系型数据库,非关系型数据库功能更少,更专一。大部分情况下,非关系型数据库专注于提高数据查询性能,对于数据修改、事务的支持虽然不如关系型数据库,但是极高的查询性能正好契合了缓存的要求,因此成为应用级缓存的首选。

比如Redis,这是一款开源、基于BSD许可、高级键值对缓存和存储系统。它的数据存储结构极为简单,就是key-value,但是简单的结构保证了Redis可以支持高并发查询。

同时Redis还支持数据持久化,在高可用、水平扩展、数据同步方面做得都非常完善,是目前应用级缓存的首选。

最后,还是用书中作者的话来做一个总结。

“缓存为王”是因为在现代软件系统中,缓存无处不在,是一种以空间换时间的艺术。尽管缓存是一种非常复杂的技术,但是真正掌握缓存技术是保证软件系统性能的关键手段。

上篇分布式系统
下篇Internal server error 500 问题解决思路