分布式存储中“货架”的关键技术——缓存技术。 在计算机领域的各个方面,缓存都非常重要,是提升访问性能的一个重要技术。
从单个计算机的体系结构来看,内存和处理器速度差异很大,如果不采用缓存技术,处理器的性能会受到很大的限制。 计算机应用如果不采用缓存技术,对于每个请求,应用都要与后台数据库做一次交互,而数据库中的数据存储在磁盘上,因此每次请求都要和磁盘做交互,而磁盘访问的性能很低,造成访问延迟。还有网络访问,如果没有缓存机制,每次访问主机都要与远程机器做交互,访问速度也会很慢。
缓存技术其实就像一个水缸,平时它会存储一定的水,而这些水就来自深井。 如果每次都去深井打水,一方面井口比较小,导致一次能接收的用水请求有限;另一方面, 井比较深,打水的工序比较复杂,导致所需时间比较长。
有了这个水缸,不需要去深井里打水,当水缸里没水时,水泵会将深井里的水抽到水缸中暂时存储起来。“缓存技术”存储了满足了一定时间内常用的“水量”,以提高用水效率。
在计算机领域,缓存技术一般是指,用一个更快的存储设备存储一些经常用到的数据,供用户快速访问。用户不需要每次都与慢设备去做交互,因此可以提高访问效率。
分布式缓存就是指在分布式环境或系统下,把一些热门数据存储到离用户近、离应用近的位置,并尽量存储到更快的设备,以减少远程数据传输的延迟,让用户和应用可以很快访问到想要的数据。
分布式数据缓存,属于计算机应用中的缓存的一种。而计算机应用中的缓存,一般指内存,内存存储了用户经常访问的数据,用户或应用不再需要到磁盘中去获取相应的数据,大幅提高访问速度。
如下图所示,数据 A 是应用经常访问的数据,而数据 B 很少被应用访问,因此当应用访问数据 A 时,不需要到磁盘,而直接访问内存即可得到对应的值,速度较快;相反,访问数据 B 时,由于内存中没有缓存数据 B,所以应用需要到磁盘中获取对应的值,速度较慢。
Redis 的全称是 Remote Dictionary Server(远程字典服务器)。它是以字典结构将数据存储在内存中,应用可直接到内存读写 Redis 存储的数据。
Redis 集群是一个典型的去中心化结构,每个节点都负责一部分数据的存储,每个节点还会进行主备设计来提高 Redis 的可靠性。
Redis 中与缓存关系最紧密的三个特性:支持多数据结构、支持持久化和主备同步。
Redis 支持多数据结构
Redis 是一个基于内存的 key-value 数据库,为了方便支持多应用的缓存,比如缓存文本类型、数据库的查询结果(字段与字段对应的值)等等,支持的数据结构不仅有简单的 k/ v 类型,还可以支持 List、Set、Hash 等复杂类型的存储。
以 Hash 这种复杂类型的存储为例,Redis 将 Hash 视作一个整体当作数据库的 value(可以是一个对象,比如结构体对象)进行存储。如果把 Hash 结构的整体看作对象的话,Hash 结构里的 key-value 相当于该对象的属性名和属性值。
比如,插入 Hash 数据类型的命令:HMSET test field1 “Hello” field2 “World”中, 如下图所示,test 为 key 值, field1 “Hello” field2 “World” 为 value 值,如果把整 个 Hash 结构看做对象的话,则 field1、field2 类似于对象中的属性名,“Hello”“World”类似于对象中的属性值。
Redis 支持持久化
持久化是指将数据从内存这种易失性存储设备中写入磁盘,从而让数据永久保存。Redis 中存储的数据虽然是基于内存的,但它也提供了持久化的机制,主要有两种方式:RDB 和 AOF。
RDB(Redis DataBase),也称快照方式, Redis 会定时将内存中的数据备份到磁盘中,形成一个快照,比如每天保存一下过去一周的数据。这样当节点出现故障时,可以根据快照恢复到不同版本的数据。这种方式有一个明显的缺点,是会造成数据丢失,即当节点出现故障时,新数据可能还未备份到磁盘中。
AOF(Append Only File)的出现主要弥补了 RDB 数据不一致的问题,其思想与数据库复制技术中 binary log 类似,即记录下 Redis 中所有的更新操作。
在 Redis 中,提供了三种实现 AOF 的策略:
Redis 中默认采用 AOF_FSYNC_EVERYSEC(每秒同步)的策略,因为这种策略的性能很不错,而且一旦出现故障,最多只会丢失一秒的数据。
Redis 支持主备同步
在 Redis 中,采用的是异步复制技术,但 Redis 可以通过配置 min-replicas-to-write 和 min-replicas-max-lag 这两个参数来有效地保证数据一致性。
比如,设置 min-replicas-to-write=3、min-replicas-max-lag=10,表示当至少有 3 个备数据库连接主数据库的延迟时间小于 10s 时,主数据库才可以执行写操作。延迟时间是从最后一次收到备数据库的心跳开始计算,通常每秒发送一次心跳。
除了上面对写操作的同步,在 Redis 中,还有两种情况是需要进行数据同步的:
针对这两种情况,Redis 提供了两种同步模式,即完整重同步和部分重同步:
完整重同步的流程:
部分重同步:当网络恢复后,主数据库将主备数据库断开连接之后的一系列写操作发送给备服务器,备数据库执行这些写操作,从而保证数据保持一致。
在这种方式的实现中,主备数据库会共同维护一个复制偏移量,这样主数据库就知道应该将哪些写操作发给备数据库,备数据库同步时也知道应该从哪里继续执行操作。
如图所示,主数据库的复制偏移量为 5000 时,向备数据库发送了 100 个字节的数据,发送结束后复制偏移量为 5100。 此时主备数据库连接断开,备数据库没有接收到这 100 个字节的数据,等到备数据库重新与主数据库连接上之后,会给主数据库发送 PSYNC 命令,并带上自己的复制偏移量 5000,主数据库接收到信息后,根据接收到的复制偏移量,将 5000 之后的数据发给备数据库,从而完成数据的部分重同步。
Memcached 也是一个基于内存的高性能 key-value 缓存数据库。 Memcached 比 Redis 问世更早,也有很多公司在使用,比如 Facebook、Vox、 LiveJournal 等。
Redis 的集群结构是每个节点负责一部分哈希槽,且每个节点可以设计主备。与 Redis 不同,Memcached 集群采用一致性哈希的思路,使用的是 Ketama 算法。该算法的主要思想就是,带虚拟节点的一致性哈希算法。
在实际应用中,每个物理节点对应 100~200 个虚拟节点,才能到达一个较好的存储均衡。如下图所示,物理节点 1 对 应两个虚拟节点 1-1、1-2,物理节点 2 对应三个虚拟节点 2-1、2-2 和 2-3。
采用带虚拟节点的一致性哈希方法的优点:当添加或移除节点时,不会出现大规模的数据迁移。
对于数据结构的支持,Memcached 仅支持简单的 k/v 数据类型,如果想要存储复杂的数据类型,比如 List、Set 和 Hash 等,需要客户端自己处理,将其转化为字符串然后进行存储。缺点是操作不灵活。比如,Memcached 存储的数组中有一个元素需要修改,则需要将整个数组的数据取出来,修改后再整体写入到数据库中 。
对于持久化,Memcached 是不支持的。断电时 Memcached 中存储的数据将会全部丢失。因为内存是一种易失性存储设备,断电后将不会存储数据。
在 Memcached 中,服务器和服务器之间没有任何通信,即自身不支持主备。如果想要实现高可用,需要通过第三方实现。比如,Repcached 实现了 Memcached 的复制功能,支持一主一备,从而使 Memcached 满足高可用。
计算机体系结构中的缓存,通常是指专用的缓存设备。由于内存和 CPU 访问速度相差很大,为了提高 CPU 的性能,计算机内部在 CPU 与内存之间设置了相应的缓存。
现在大多数机器分为三级缓存:L1 高级缓存、L2 高级缓存和 L3 高级缓存。访问速度:L1 高级缓存 > L2 高级缓存 > L3 高级缓存 > 内存。其中,L1 高级缓存的访问速度, 几乎和 CPU 中寄存器的访问速度一样快。 有了这三级缓存,很多数据不需要到内存中读取,而直接读取这三级缓存中的数据即可,缩短了数据访问的时间,使得计算机运行速度变得更快。
网络访问中的缓存,通常是指本地的“磁盘”。通过网络访问数据时,需要与远程服务器交互来进行传输,而网络间数据传输以及远程服务器对请求的响应,会耗费很多时间。如果本机器的磁盘可以对经常访问的远程内容进行存储,就不用每次都与远程服务器交互, 而减少网络数据传输与服务器响应的延迟,极大地提高性能。