初创期应用架构实践 (4):缓存选型

叁叁肆2018-11-14 09:20

欢迎访问网易云社区,了解更多网易技术产品运营经验。


3.1.3 缓存选型


数据是互联网业务的核心价值,一个应用的绝大部分功能都用于对数据库进行增删改 查。数据库系统需要通过文件系统对数据进行持久化,因此大量的数据库操作,会使数据 库的性能压力,特别是 I/O 性能压力增大。


在某些场景下,我们可以通过引入一个缓存中间层,来减少对数据库的操作和对数据 库的访问压力。


缓存概念 

在电商业务中,商品的基本信息变更较少,更多的情况是对信息的查询。由于其数据 变更远远小于数据信息被查询的次数,因此一种可能的方案,就是将其信息直接缓存到应 用服务器的内存中。但是如果将数据缓存到内存中,会有一些问题:首先缓存数据会随着 应用服务器的重启而全部失效,再次,当服务器多点部署的时候,某一台服务器上的更新 操作需要通知到其他的服务器,这里会有缓存一致性问题,因此一个独立的缓存系统是必 要的。目前常用的缓存系统,一般都支持 KV 键值对型,使用简单方便,易于理解。在使 用缓存系统的情况下,对数据的库的访问流程通常如图 3-9 所示。


当需要获取数据的时候,会先访问缓存,如果在缓存中查询到,则直接返回,省去 了对数据库的读查询开销。如果在缓存中没有查询到,则还是需要访问具体的数据库, 在获取到数据后,更新缓存,然后返回结果。当需要更新数据的时候,通常情况下,可 以直接将数据写入数据库,然后主动失效缓存。当下一次数据库查询时,会从数据库中 获取到最新的数据,然后再更新到缓存中。在查询请求非常多,而更新频率比较低的场 景下,绝大部分的查询请求会直接在缓存中命中,减少了直接访问数据库的次数,减轻 了数据库的压力。同时由于缓存系统逻辑简单,处理起来更快,也可以加速数据的读取, 减少获得数据的时间。


使用缓存,除了可以加速数据的访问,减轻数据库的压力外,缓存系统还可以用来 保存应用的运行时状态。像 PHP 这样的语言,无法保存临时数据在内存,而如果把所有 数据都放到数据库中,有时候又是不必要的,显得太笨重,这个时候,就可以将这些临 时数据放到缓存中。还有,当我们的应用服务器多点部署的时候,往往多个应用服务部 署实例要共享一些运行时的临时状态数据,比如 Session 信息。将这类数据放到数据库中, 既没必要,又会影响访问性能,我们同样可以将这样的状态数据放到统一的缓存中,既实现了状态数据共享,又提高访问效率。目前比较流行的缓存系统有 Memcached 和 Redis, 下面将分别介绍。 

图 3-9 带缓存系统的数据库访问流程


Memcached 简介 

Memcached 是一个高性能的分布式内存对象缓存系统,用于动态 Web 应用以减轻数据 库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据 库驱动网站的速度。Memcached 服务器端内部可以理解为一张巨大的 Hashmap,数据保存 在内存中,通过网络访问。Memcached 守护进程(服务器端)是用 C 语言实现的,而客户 端(驱动程序)几乎可以支持任何语言,并通过 Memcached 协议通信。

Memcached 可以用于数据库的缓存系统,把数据库热点数据(如上面说的商品基本信 息)保存在 Memcached 中,大大减少系统读取数据的时间。Memcached 一出现就和 PHP 结合得非常紧密,使用了 Memcached 后,PHP 可以将无法在内存中保存的临时数据保存到 Memcached 中,这也让 Memcached 红极一时。同样,在多实例部署的情况下,多个应用服 务部署的实例可以通过 Memcached 共享运行时状态数据。


Redis 简介

Redis 是一个高性能的 Key-Value 数据库,和 Memcached 类似,Redis 支持存储的 value 类型更加丰富,包括字符串(string)、链表(list)、集合(set)、有序集合(zset)、哈希表 (hash)等,除支持增加、删除、更改、查询等基本操作外,还支持取交集、差集和并集, 以及排序等其他更丰富的操作,而且这些操作都是原子性的。它的出现,很大程度补偿了 Memcached 这类比较基础的 Key-Value 存储的不足,在部分场合可以对关系型数据库起到 很好的补充作用。它的客户端(驱动程序)几乎支持所有的主流编程语言,其通信协议 Redis 也很简单,易于实现。


Redis 支持主从部署,并且节点会从主从复制数据,保证主从节点数据的一致。Redis 官方还自带了高可用组件 sentinel,通过 sentinel 对主、从 Redis 节点的监控,在 master 出 问题后,自动选取一个 slave 成为新的 master。客户端可以通过 sentinel 获取最新的 master, 从而提供高可用的访问。


Redis 还支持数据的持久化,可以将内存中数据持久化到硬盘中,保证数据不丢失。 Redis 提供了两种持久化机制,rdb 的方式是内存快照,aof 的方式是基于写操作日志的。通 过将缓存中的数据持久化到硬盘中,可以在缓存发生重启的时候,尽快完成缓存预热,而 不会因为缓存重启造成所有缓存的数据全部失效。


Redis 发展到 3.0,还提供了集群功能,多个 Redis 节点可以组成一个集群,同时对外 提供服务,每个提供服务的节点还可以有自己的 slave 节点,在节点宕机后,slave 会顶替 它的位置,从而提供可升缩、高可用的集群服务。


Memcached 和 Redis 比较 

下面分别从性能、内存利用率、监控信息、功能对比和扩展性 5 个方面分别比较 Memcached 和 Redis。

性能:图 3-10 是 Redis 作者对 Redis 和 Memcached 性能比较结果,可以看到两者 性能不分伯仲。 

图 3-10 Redis 作者对 Redis 和 Memcached 性能比较


内存利用率:我们进行了如下测试,往 Redis 和 Memcached 分别插入 50000 条记 录,key 为“test_”加上 0 到 50000 的编号,value 为 1024 个 x,即 1KB 数据。实 际 Redis 使用的内存为 68M,Memcached 使用内存为 58M,由于系统本身会使用 一些内存和每条记录还有些其他信息,所以实际使用的内存会大于 key 加上 value 使用的内存总数。Redis 由于数据的信息比 Memcached 多,因此使用了更多的内 存,但总体来说,内存利用率表现都非常不错。


 监控信息:Redis 的 info 命令和 Memcached 的 stats 命令都能监控系统的运行状态, 两者都提供了非常丰富的监控数据。


功能对比:前面在介绍 Memcached 和 Redis 命令的时候就能看出来,Redis 提供了比 Memcached 更多的功能,除了具备 Memcached 的 string 字符串功能外,还支 持更多的数据结构、更丰富的数据操作,有很多类似数据库的功能。


扩展性:Redis 3.0 版本增加了集群功能,可动态增加节点;也支持配置的自动修改, 可动态增加单个节点的内存容量,而 Memcached 无法做到纵向和横向扩容,只能 借助第三方提供的扩展功能完成。


另外,Redis 和 Memcached 发展了这么多年,Memcached 的功能一直没有更大的突破, 更新大都在修复 bug 和系统优化,而反观 Redis 的作者一直保持对 Redis 的更新,最近 Redis 已经确定了 3.2 版本的新功能,又会有更多的功能加入 Redis。


通过对比 Memcached 和 Redis 的各个方面,可以看出 Redis 整体表现优于 Memcached, 但由于 Memcached 出现得更早,很多应用只需要简单的缓存系统,它们把数据库的记录序 列化到缓冲中,以加速访问性能,它们也不急迫需要更换系统,这个时候 Memcached 基本 上能满足需求;而如果新应用做选型的话,Redis 会是更好的选择,特别是它的高可用、高 可靠等特性,以及极其丰富的数据结构,为后续的扩展、运维和新功能增加带来便捷。


云上的缓存服务 

云计算服务提供商,一般都会提供缓存服务,云服务提供商会提供相关缓存服务的资 源分配及运维,保证可靠性,当我们需要使用的时候,只需要申请使用,然后按需付费即 可。云服务提供商在提供缓存服务的时候,一般都会基于 Memcached/Redis 来提供,这样, 用户在使用的时候对应用程序几乎不用改动,包括 AWS、阿里云及网易云在内都提供了类 似的缓存服务。网易云提供了兼容 Redis 协议的线上 Key-Value 缓存服务,支持 Redis 的主 从热备,自动容灾,当主节点发生故障的时候,可以实现秒级自动切换,同时也会提供高 质量的运维服务保证。


文章节选自《云原生应用架构实践》 网易云基础服务架构团队 著 


网易云计算基础服务深度整合了 IaaSPaaS 及容器技术,提供弹性计算、DevOps 工具链及微服务基础设施等服务,帮助企业解决 IT、架构及运维等问题,使企业更聚焦于业务,是新一代的云计算平台。点击可免费试用