目录(?)[-]缓存
- 背景和介绍
- 租约属性和管理
- 互联网的一致性问题
- 卷租约
- 租约的其余应用
- 到底租约是什么
背景和介绍
缓存是计算机里普遍使用的一种技术,对下降读取延迟、网络流量和服务器负载都很是有效,但也带来了一致性(Consistency)的问题。所谓一致就是客户端总能读到最新的数据,使用缓存后有可能服务器端的数据已经被修改,但客户端仍然从缓存中读取陈旧的数据。为了保证一致性,有两种常见的解决办法,第一种是轮询(Polling),即每次读取数据时都先询问服务器数据是否是最新的,若是不是就从服务器传输新数据,这种方法须要每次读取数据时都与服务器通讯。另外一种方法就是回调(Callback)或者无效化(Invalidation),就是由服务器记住有哪些客户端读取了数据,对数据作修改时首先通知全部这些客户端数据已经失效,这种方法的问题在于服务器须要记住全部读取过数据的客户端,这是很大的负担,更严重的是,一旦有客户端联系不上或者丢失了客户端的信息,修改操做就没法继续。安全
1989年斯坦福大学的Cary G. Gray和David R. Cheriton提出了利用
租约来维护缓存一致性的方法。所谓租约,其实就是一个合同,即服务器给予客户端在
必定期限内能够
控制修改操做的 权力。若是服务器要修改数据,首先要征求拥有这块数据的租约的客户端的赞成,以后才能够修改。客户端从服务器读取数据时每每就同时获取租约,在租约期限 内,若是没有收到服务器的修改请求,就能够保证当前缓存中的内容就是最新的。若是在租约期限内收到了修改数据的请求而且赞成了,就须要清空缓存。在租约过 期之后,客户端若是还要从缓存读取数据,就必须从新获取租约,咱们称这个操做为“
续约”。
在租约期限内,客户端能够保证其缓存中的数据是最新的。同时,租约能够容忍各类非拜占庭式失效(机器崩溃、网络分割等)。若是客户端崩溃或者网络中断,服务器只须要等待其租约过时就能够进行修改操做。若是服务器出错丢失了全部客户端的信息,它只须要知道租约的最长期限,就能够在这个期限以后安全的修改数据。与回调方式相比,服务器只需记住还拥有租约的客户端便可。服务器
租约与带期限的锁很是类似,但更加灵活,由于租约还提供了“寻求赞成”的机制(我以为能够称为“带期限可妥协的锁”)。服务器还能够实现多种租约,好比“写租约”和“读租约”,并保证一个时间段内只有一个写租约或者多个读租约,这就至关因而单写者多读者的锁协议。
因 为租约是基于时间的,所以其有效性须要系统时间来保证。若是服务器的时钟快而客户端时钟慢,那么有可能服务器认为一个租约已通过期而客户端仍然认为其有 效,就可能致使错误。对这种状况就必须经过时钟同步协议来解决了,不过这种状况不多见。通常状况下,咱们能够认为一个分布式系统的时间是同步在一个很小的 时间差e以内,只需把这个e考虑到租约期限内便可。
租约属性和管理
租约的属性和管理有多种选择,首先要考虑的就是租约期限的长短。网络
通常状况下,应当选择较短的租约期限。与长租约相比,短租约有三个优势。首先,在失效状况下修改操做每每须要等待租约过时,所以短租约就意味着更短的
失效延迟。其次,就算一个客户端已经再也不须要读取数据,但在其租约过时前,任何的修改操做仍然须要征求它的赞成,这种状况叫作“
假共享”,显然租约期限越长,这个问题就越严重。最后,短租约也使得服务器要维护的客户端信息更少。然而短租约也意味着更大的
续约开销, 所以对于要反复读取却不多修改的数据,长租约会更有效。所以,对租约期的选择要权衡失效延迟、假共享开销和续约开销等多个因素,服务器能够根据数据访问特 性和客户端的性质灵活设置期限。事实上,若是咱们把租约期限设为零,就至关与轮询,此时修改操做随时能够进行,而读取数据老是要联系服务器。若是把租约期 限设为无限长,就至关于回调。
除了期限的选择,还有不少管理选项。对客户端来讲,能够选择 是否续约、什么时候续约以及是否赞成修改等。好比为了减小读取延迟,客户端能够在租约过时前就续约,不过这样可能加剧服务器的负担。对服务器来讲,能够选择是 否发放租约、租约覆盖粒度以及对如何进行修改操做。好比在收到修改请求后,服务器能够不征求客户端赞成,而是简单的等待全部租约过时(等待时再也不发放新租 约以免无限期的延迟)。对于“
安装文件”,也就是修改极少的文件(好比头文件、库文件),服务器能够用一个租约来覆盖一批文件,同时按期广播续约通知来节省开销,若是须要修改数据,就中止广播并等待租约过时便可。
互联网的一致性问题
在互联网环境下,一致性问题更加复杂,由于网络延迟比局域网要大的多,客户端失效和网络分割都很常见。所以不少状况下,咱们都只保证缓存的弱一致性,也就是不保证客户端总能读到最新的数据,只是尽可能保证其读到的数据还不是很是滞后。相应的,咱们把前面使用的一致性称为强一致性。目前最经常使用的保证弱一致性的方法就是生存期(TTL), 即读取数据的时候会指定生存期,在生存期内客户端直接从缓存中读取数据,以后必须与服务器通讯验证缓存有效性或者获取最新数据。很显然,咱们能够给变化较 多的数据分配较短的生存期来尽可能减小客户端读取过时数据的概率,而给变化较少的数据分配较长的生存期来减小读取延迟和服务器负载。分布式
1992年CMU的Vincent Gate在Alex项目中实现了可变生存期(Adaptive TTL),这个技术基于这样的观察,就是新数据比旧数据更容易被修改。 在Alex中采用了更新阈值(update threshold)的概念,把生存期设定为其缓存时间的一个百分比。假设一个刚刚向服务器验证过的数据已经在缓存中存在了10个钟头,其更新阈值为 20%,那么其生存期就是2个钟头。采用可变生存期技术并不能减小网络流量,可是能够比普通的生存期技术减小服务器负荷。工具
虽然弱一致性模型已经知足咱们平常浏览网页的需求,但仍是有一些应用会要求强一致性。局域网状况下的方法很难直接扩展到互联网环境。轮询方法的读取延迟太 大。回调方法不但记录全部客户会使得服务器难以承受,常常出现的网络分割更使得修改操做没法继续。短租约致使的网络通讯和服务器负荷都太大,并且若是租约 期限小于网络延迟的话,那么除了增长服务器负荷外没有任何做用。长租约又相应的使得失效延迟和假共享的问题更加严重,并且服务器要记录大量客户端数据。既 然有可变生存期,那天然的也有了
可变租约(variable leases)的想法。1998年威斯康辛大学麦迪逊分校的Pei Cao和Chengjue Liu就提出了一种叫
two-tier的方案,就是区分只是偶然读取数据的客户端和真正须要强一致性的客户端,只对后者才发放租约(由客户端显示的提出请求)。更进一步的,他们分析了如何根据不一样状况调整租约属性,例如数据修改减小时增长租约期限,存储空间不够时则缩短租约期限甚至要求客户端放弃租约。
卷租约
在1999年的论文中,德克萨斯大学奥斯汀分校的Jian Yin等提出了互联网环境下保证强一致性的卷租约机制。
所谓
卷租约(volume leases), 与上面提到的针对“安装文件”的租约有点相似,即由一个租约会覆盖多个相关文件,其期限较短,通常是数十秒,通常要在过时前续约。卷租约由于期限短,续约 操做就比较频繁,但用户每每会同时读取一个卷下的多个文件,所以这个开销分摊到了多个文件上,依然是能够接受的。若是光采用卷租约,会带来很是严重的假共 享问题,由于拥有卷租约的客户端各自关注的数据可能很不相同。所以服务器还另外提供了
对象租约(object leases),就是只覆盖一个文件的普通租约,期限通常较长,能够是数小时甚至数天,以取得较小的续约开销。客户端要保证缓存有效,就必须
同时拥有对象租约和卷租约。修改操做须要征求同时拥有卷租约和对象租约的客户端的赞成,若是出现客户端机器失效或者网络分割的状况,最多只需等待卷租约过时,就能够安全的修改数据。
一旦卷租约过时,服务器就认为相应的对象租约也都过时,客户端从新获取卷租约时,会检查相应的对象租约的有效性,若是数据没有修改就续约,不然清空缓存。事实上,卷租约和对象租约相似于
心跳和回调,前者主要用来肯定客户端的状态,后者用来定位对数据有兴趣的客户端。经过两种租约的结合,能够较好的平衡失效延迟和通讯开销。实验数据代表,要取得一样的
失效延迟时间,卷租约机制能够比普通租约机制减小三成到四成的消息数。粗一想或许还会奇怪,加了一个租约怎么可以减小通讯呢?这是由于要取得一样的失效延迟,普通租约就必须把租约期限设定在延迟期限内(好比20秒),而若是使用卷租约,只需把卷租约的期限设定在延迟期限内,而对象租约的时间能够设的很长。由于卷租约的通讯开销有好几个对象分摊,而对象租约的开销由于期限很长事实上很是小,因此总的开销会小于只使用普通租约的状况。
租约的其余应用
以上咱们只讨论了如何用租约来维护缓存一致性,其实租约的应用范围很是普遍。
在 Frangipani分布式文件系统中实现了一个分布式的锁,客户端在获取锁以前,首先要获取一个租约,而且必须在租约过时前续约。这个客户端得到的锁都 与这个租约相关联,若是租约过时了,锁服务器就会自动的释放这些锁。这里的租约就是对锁有效性的一个保证,经过维护客户端租约,避免了为每一个锁维护期限的 开销。这里的租约就至关于心跳。
在gfs中,每一个文件块都有多个副本分布在多个chunkserver上,在 并行追加时必须有一个全局统一的追加顺序。固然这个顺序能够由master来肯定,可是这样会大大增长master的负荷。另外一种方法能够由多个 chunkserver经过一致性协议(好比Paxos)来达成一个一致,但这样开销太大。gfs使用了租约机制,就是对每一个文件块,由master向一 个chunkserver发放租约,在租约期限内就由它来负责并行追加操做的顺序。chunkserver正常运行时能够一直续约,若是出现了机器失效或 者网络分割的状况,master就在租约过时之后把租约交给另一个chunkserver。在某些状况下,master也会联系拥有租约的 chunkserver,请它们提早释放租约。
不少状况下,系统中已经有一个保证一致性的中心服务,如某个
单一服务器或者是
实现了Paxos协议的一组服务器,但若是全部的功能都须要经过这个中心服务,很容易形成性能瓶颈。为了提升效率和扩展性,能够经过租约把
一致性扩展到更多服务上。事实上用租约来维护缓存一致性也是至关于把服务器上的数据一致性扩展到了客户端。
到底租约是什么?
在不少时候,租约的定义彷佛很模糊,有的时候租约相似心跳,有的时候又相似于锁。到底租约的本质是什么呢?
回到租约最原始的定义:租约就是在
必定期限内给予持有者
特定权力的 协议。我以为这里的期限就是租约的根本特性,正是这一特性使得租约能够容忍机器失效和网络分割。在期限以内,租约其实就是服务器和客户端之间的协议,而这 个协议的内容能够五花八门。若是协议内容是服务器确认客户端还存活,那么这个租约的功能就至关于心跳;若是协议内容是服务器保证内容不会被修改,那么这个 租约就至关于读锁;若是协议内容是服务器保证内容只能被这个客户端修改,那么这个租约就至关于写锁。租约这种灵活性和容错性,使其成为了维护分布式系统一致性的有效工具。