You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
15 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 27 | 分布式数据之缓存技术:“身手钥钱”随身带
你好,我是聂鹏程。今天,我来继续带你打卡分布式核心技术。
不知不觉分布式数据存储这一站已经到了最后一讲。在前面几讲我与你分享了CAP理论、分布式存储系统的三要素顾客、导购和货架、数据分布式分片方法和数据复制技术其中数据分片方法和数据复制技术均是导购中的关键技术。
在这一讲,我将为你讲解分布式存储中“货架”的关键技术——缓存技术。
在计算机领域的各个方面,缓存都非常重要,是提升访问性能的一个重要技术。为什么这么说呢?
从单个计算机的体系结构来看,内存和处理器速度差异很大,如果不采用缓存技术,处理器的性能会受到很大的限制。
再看计算机应用,如果不采用缓存技术,对于每个请求,应用都要与后台数据库做一次交互,而数据库中的数据存储在磁盘上,因此每次请求都要和磁盘做交互,而磁盘访问的性能很低,造成访问延迟。
除此之外,还有网络访问,如果没有缓存机制,每次访问主机都要与远程机器做交互,速度又可想而知。
接下来,我们就一起打卡分布式缓存技术吧。
## 什么是分布式缓存?
打比方来说,缓存技术其实就像一个水缸,平时它会存储一定的水,而这些水就来自深井。如果每次都去深井打水,一方面井口比较小,导致一次能接收的用水请求有限;另一方面,井比较深,打水的工序比较复杂,导致所需时间比较长。
而有了这个水缸,我们就不需要去深井里打水,当水缸里没水时,水泵会将深井里的水抽到水缸中暂时存储起来。也就是说,“缓存技术”存储了满足人们一定时间内常用的“水量”,以提高用水效率。
在计算机领域,**缓存技术**一般是指,用一个更快的存储设备存储一些经常用到的数据,供用户快速访问。用户不需要每次都与慢设备去做交互,因此可以提高访问效率。
**分布式缓存**就是指在分布式环境或系统下,把一些热门数据存储到离用户近、离应用近的位置,并尽量存储到更快的设备,以减少远程数据传输的延迟,让用户和应用可以很快访问到想要的数据。这,是不是可以形象地理解为“身手钥钱”随身带呢?
其实,**我们通常说的分布式数据缓存,属于计算机应用中的缓存的一种**。而计算机应用中的缓存,一般指内存,即内存存储了用户经常访问的数据,用户或应用不再需要到磁盘中去获取相应的数据,大幅提高访问速度。
如下图所示数据A是应用经常访问的数据而数据B很少被应用访问因此当应用访问数据A时不需要到磁盘而直接访问内存即可得到对应的值速度较快相反访问数据B时由于内存中没有缓存数据B所以应用需要到磁盘中获取对应的值速度较慢。
![](https://static001.geekbang.org/resource/image/67/bf/67315610b5f0cb2b14588885a05335bf.png)
那么今天,我要与你分享的分布式数据存储相关的缓存技术,就是以内存做为磁盘的缓存。
## 分布式缓存原理
接下来我以主流的分布式缓存系统Redis和Memcached为例与你讲述分布式缓存技术以加深你的理解吧。
### Redis分布式缓存原理
Redis的全称是Remote Dictionary Server远程字典服务器。可以直观地看出它是以字典结构将数据存储在内存中应用可直接到内存读写Redis存储的数据。
Redis集群是一个典型的去中心化结构每个节点都负责一部分数据的存储同时每个节点还会进行主备设计来提高Redis的可靠性具体原理你可以再回顾下[第10篇文章](https://time.geekbang.org/column/article/149653)中的相关内容。
接下来我与你分享下Redis中与缓存关系最紧密的三个特性**:支持多数据结构、支持持久化和主备同步。**
**第一Redis支持多数据结构**。
Redis是一个基于内存的key-value数据库为了方便支持多应用的缓存比如缓存文本类型、数据库的查询结果字段与字段对应的值等等支持的数据结构不仅有简单的kv类型还可以支持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”类似于对象中的属性值。
![](https://static001.geekbang.org/resource/image/9f/1a/9f025bfd4d3731d378d01c4c19ede21a.png)
**第二Redis支持持久化。**
持久化是指将数据从内存这种易失性存储设备中写入磁盘从而让数据永久保存。Redis中存储的数据虽然是基于内存的但它也提供了持久化的机制主要有两种方式RDB和AOF。
**RDB**Redis DataBase也称快照方式简单来说就是Redis会定时将内存中的数据备份到磁盘中形成一个快照比如每天保存一下过去一周的数据。这样当节点出现故障时可以根据快照恢复到不同版本的数据。这种方式有一个明显的缺点是会造成数据丢失即当节点出现故障时新数据可能还未备份到磁盘中。
**AOF**Append Only File的出现主要弥补了RDB数据不一致的问题其思想与上一讲提到的数据库复制技术中binary log类似即记录下Redis中所有的更新操作。
在Redis中提供了三种实现AOF的策略
* AOF\_FSYNC\_NO (不同步),即不会自动触发写操作的同步;
* AOF\_FSYNC\_EVERYSEC (每秒同步),即每隔一秒都会将写操作同步到磁盘;
* AOF\_FSYNC\_ALWAYS (每次写都同步),即每次发生写操作会立即同步到磁盘。
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提供了两种同步模式即完整重同步和部分重同步。
**完整重同步**的流程如下所示:
1. 当备服务器启动时会向主服务器发送SYNC命令
2. 主服务器收到命令后会生成RDB快照文件并记录从现在起新执行的写操作
3. RDB生成后会发送给备服务器备服务器通过RDB文件进行数据更新
4. 更新完成后,主服务器再将新记录的写操作发送给备服务器,备服务器执行完这些新记录的写操作,便与主服务器的数据保持一致了。
![](https://static001.geekbang.org/resource/image/4c/fa/4cc71fd16815139a2af93b9721a586fa.png)
简单地说,**部分重同步**就是,当网络恢复后,主数据库将主备数据库断开连接之后的一系列写操作发送给备服务器,备数据库执行这些写操作,从而保证数据保持一致。
在这种方式的实现中,主备数据库会共同维护一个复制偏移量,这样主数据库就知道应该将哪些写操作发给备数据库,备数据库同步时也知道应该从哪里继续执行操作。
如图所示主数据库的复制偏移量为5000时向备数据库发送了100个字节的数据发送结束后复制偏移量为5100。
此时主备数据库连接断开备数据库没有接收到这100个字节的数据等到备数据库重新与主数据库连接上之后会给主数据库发送PSYNC命令并带上自己的复制偏移量5000主数据库接收到信息后根据接收到的复制偏移量将5000之后的数据发给备数据库从而完成数据的部分重同步。
![](https://static001.geekbang.org/resource/image/3d/93/3da4db478862a8643d278333fdff5e93.png)
以上就是分布式缓存系统Redis中涉及的关键技术包括支持的数据结构、数据持久化方法和数据同步方法相信通过上面的介绍你对分布式缓存技术已经有了一定的了解。
接下来我再带你学习另一个缓存数据库Memcached。
### Memcached分布式缓存原理
与Redis类似Memcached也是一个基于内存的高性能key-value缓存数据库。Memcached比Redis问世更早也有很多公司在使用比如Facebook、Vox、LiveJournal等。
其实Memecached的缓存原理和Redis类似。所以接下来的内容我会着重于你讲述这两个数据库在支持的数据结构、持久化和主备同步上的不同。这样你可以对比着学习这两个数据库也会理解得更全面、深入些。
首先我要先带你了解一下Memcached的集群结构。
Redis的集群结构是每个节点负责一部分哈希槽且每个节点可以设计主备。与Redis不同Memcached集群采用一致性哈希的思路使用的是Ketama算法。该算法的主要思想就是**带虚拟节点的一致性哈希算法**。
在实际应用中每个物理节点对应100~200个虚拟节点才能到达一个较好的存储均衡。这里为了方便理解我对Memcached的集群结构做了简化如下图所示物理节点1对应两个虚拟节点1-1、1-2物理节点2对应三个虚拟节点2-1、2-2和2-3。
![](https://static001.geekbang.org/resource/image/af/68/af2a8805451df9b15d18a8672bd98c68.png)
采用带虚拟节点的一致性哈希方法,有一个优点是,当添加或移除节点时,不会出现大规模的数据迁移。你可以再回顾下[第25篇文章](https://time.geekbang.org/column/article/168940)中的相关内容。
对于数据结构的支持Memcached仅支持简单的kv数据类型如果想要存储复杂的数据类型比如List、Set和Hash等需要客户端自己处理将其转化为字符串然后进行存储。这样就导致了一个缺点操作不灵活。比如Memcached存储的数组中有一个元素需要修改则需要将整个数组的数据取出来修改后再整体写入到数据库中 。
而对于持久化Memcached是不支持的。这意味着断电时Memcached中存储的数据将会全部丢失。因为内存是一种易失性存储设备断电后将不会存储数据。
在Memcached中服务器和服务器之间没有任何通信即自身不支持主备。如果想要实现高可用需要通过第三方实现。比如Repcached实现了Memcached的复制功能支持一主一备从而使Memcached满足高可用。
### 对比分析
上面我以Redis和Memcached这两个主流的分布式缓存系统为例带你学习了分布式缓存技术。接下来我以一个表格对它们进行分析对比以便于你理解和查阅。
![](https://static001.geekbang.org/resource/image/4b/91/4b3069a37873b26db686a439a1921691.jpg)
## 知识扩展:除了分布式存储中的缓存,还有计算机体系结构和网络中的缓存,它们又分别是什么呢?
**计算机体系结构中的缓存**通常是指专用的缓存设备。由于内存和CPU访问速度相差很大为了提高CPU的性能计算机内部在CPU与内存之间设置了相应的缓存。
现在大多数机器分为三级缓存L1高级缓存、L2高级缓存和L3高级缓存。就访问速度来讲L1高级缓存 > L2高级缓存 > L3高级缓存>内存。其中L1高级缓存的访问速度几乎和CPU中寄存器的访问速度一样快。
有了这三级缓存,很多数据不需要到内存中读取,而直接读取这三级缓存中的数据即可,缩短了数据访问的时间,使得计算机运行速度变得更快。
**网络访问中的缓存**,通常是指本地的“磁盘”。通过网络访问数据时,需要与远程服务器交互来进行传输,而网络间数据传输以及远程服务器对请求的响应,会耗费很多时间。如果本机器的磁盘可以对你经常访问的远程内容进行存储,这样就不用每次都与远程服务器交互,从而减少网络数据传输与服务器响应的延迟,极大地提高性能。
可以看出,**缓存的概念是相对的,基于不同的背景或应用场景,缓存所映射的存储设备是不一样的。**
## 总结
今天,我主要与你分享了分布式数据的缓存技术。
首先,我以水缸的例子带你直观了解了什么是缓存,并引出了什么是分布式数据缓存。分布式数据缓存是以内存作为磁盘的缓存,存储一些用户经常需要用的数据,以提高访问速度。
其次我以主流的Redis和Memcached为例与你介绍了分布式缓存技术中的关键技术包括支持的数据存储结构比如k/v、Set、List等、持久化技术包括快照方式等和数据同步技术具体技术原理可参见[第26篇文章](https://time.geekbang.org/column/article/168963))。
最后,我再通过一张思维导图来归纳一下今天的核心知识点吧。
![](https://static001.geekbang.org/resource/image/1e/45/1e625c22f729a87ea551f6bbc343f045.png)
相信通过本讲的学习你已不再觉得分布式缓存有多么神秘了不管是使用Redis还是看Redis等系统的源码一定会更容易理解和上手。加油行动起来吧
## 思考题
本讲我主要介绍了Redis和Memcached分布式数据缓存系统你还知道哪些主流的分布式数据缓存系统呢它们的缓存核心技术是什么呢
我是聂鹏程,感谢你的收听,欢迎你在评论区给我留言分享你的观点,也欢迎你把这篇文章分享给更多的朋友一起阅读。我们下期再会!