租约-分布式缓存一致性的高效容错机制

租约

租约被提议为一种基于时间的机制,可提供对分布式系统中缓存数据的有效一致访问。非拜占庭式故障会影响性能,而不是正确性,并通过短期租约将其影响降到最低。 缓存引入了确保缓存数据与其主要存储位置之间一致性的问题。一致的意思是,除了高速缓存的性能优势外,行为等同于仅存在单个(未缓存)数据副本。对于大型缓存,维持一致性所需的流量可能是缓存性能的主要因素。分布式系统可能会遇到部分故障:主机可能崩溃或消息可能丢失。 现有的缓存一致性方法分为两策略:假定可靠广播的方式,因此不能容忍通信故障,或者需要对每次读取进行一致性检查的策略,但是却无法提供良好的性能。建议使用租约作为一种一致性协议,该协议使用物理时钟来处理主机和通信故障。

租约基本原理

租约论文节选

租约就是指在一个限定的时间里面,给与其持有人一定特殊的处理权限。在缓存的情况下,租约授予其持有人控制在租约期间对所覆盖的数据进行写入的权限,从而使服务器必须先获得租户的批准,然后才能编写该数据。租约持有人授予写许可权时,会使本地副本的本地副本无效。

使用租约的缓存需要对数据进行有效的租约(除保留数据外),然后才响应读取而返回数据,或响应写而修改数据。从服务器(数据的主存储站点)获取数据时,服务器还会返回租约,以保证在租期内不会有任何客户端写入数据,除非服务器首先获得该租约持有人的批准。如果在租约期限内再次读取了数据(并且该数据仍在高速缓存中),则高速缓存将提供对数据的即时访问,而无需与服务器通信。租约到期后,读取数据需要高速缓存首先在数据上扩展租约,如果自从租约过期以来已经修改了基准,则更新缓存。当客户编写数据时,服务器必须将请求推迟到每个租约持有人都已批准或租约的期限届满为止。

我们在这里将自己限制为直写式缓存,因为这样做简化了解释; 直接扩展该机制以支持非直写式缓存。直写提供了清晰的失败语义:不会丢失任何客户端可见的写操作; 否则,应用程序必须准备好从丢失的写操作中恢复。尽管某些人认为文件高速缓存的直写成本过高,但是通过对临时文件进行特殊处理,可以大大降低成本,因为临时文件会收到大部分写操作。

为了说明使用租用的文件高速缓存的操作,请考虑将无盘工作站用于文档存储。工作站首次执行写操作时,它将在包含待写的二进制文件上获得租约,期限为(例如)10秒。5秒钟后访问同一文件的另一个客户端可以使用此文件的缓存版本,而无需与文件服务器联系。10秒期限到期后对该文件的访问需要缓存与服务器进行检查。当新的写操作发生时,写入将延迟到每个租约持有人都批准了写入为止。如果某些持有此文件租约的主机无法访问,则延迟将持续到租约到期为止。

在前面的示例中,最常见的读取和写入操作不仅限于对文件内容的操作。为了支持重复打开,高速缓存还必须保存名称到文件的绑定和权限信息,并且它需要对此信息进行租约才能使用该信息来执行打开操作。同样,修改此信息(如重命名文件)将构成写入。

短租期有几个优点。 一是它们最大程度地减少了由客户端和服务器故障(以及分区通信故障)导致的延迟。当服务器无法与客户端通信时,服务器必须延迟对失败的客户端持有租约的文件的写入,直到该租约到期为止。当服务器崩溃后恢复时,它必须履行崩溃之前授予的租约。如果它记录已授予租约的最大期限,并且在该期间延迟了对所有文件的写操作,这很容易做到,从而有效地增加了以最大期限完全恢复的时间。或者,服务器可以在持久性存储上维护更详细的租约记录,但是除非租约的期限比恢复时间长得多,否则额外的I / O流量不太可能是合理的。

短租约还可以最大程度地减少错误的写共享。错误共享是指在文件访问中不存在实际冲突时的租约冲突。从细节上讲,当一个客户端写入文件时,如果另一个客户端当前未访问该文件,则该错误被另一个客户端持有的租约所覆盖。在没有租约不会发生冲突的情况下,虚假共享会给租约所有者带来回调的开销(从而延迟了请求的客户端并加载了租约所有者和服务器)。在极端情况下,如果客户端在另一个客户端修改文件之前不访问文件,则租约期限应设为零。

最后,短租期减少了服务器的存储需求,因为可以回收过期租约的记录。但是,用于跟踪服务器已授予的租赁的服务器的开销存储是适中的。服务器需要记录每个租赁所有者的身份以及所持有的租赁清单; 每个租约只需要几个指针。对于拥有约一百份租约的客户,每个客户的总租约约为一千字节。即使这是一个问题,也可以通过以较大的粒度记录租约来减少租约,从而使每个客户都持有很少的租约,但会增加竞争。稍后我们将说明如何消除最常见的广泛共享文件类别的每客户记录。

对于客户端和服务器而言,长期租赁对于重复访问且写入共享量相对较小的文件而言,效率显着提高。

租约的基本概述

通过对论文的阅读,可以得出大致思路,在分布式缓存中,还是会有一个中心化Server几点保存元数据,客户端读取数据的时候会去检查数据是否在本地缓存中,如果不在本地缓存中则去读取Server端的数据信息,然后Server会颁发一个过期时间给client,并且客户端会缓存从Server端获取到的内容,如果客户端的缓存是在有效期的缓存时间内的,则客户端直接读取数据,否则重新去Server端获取数据。示例图如下;

在这里插入图片描述

客户端查询过程

首先,服务端的架构图如上所示,初始状态下,ClientA、ClientB和ClientC都是本地Cache为空的状态,假如ClientA需要知道A的值得时候,此时ClientA先检查本地是否在租期有效期内拥有该值,如果没有则去Server端获取,获取之后的状态如下所示;

在这里插入图片描述

如果ClientA再次需要获取A的值得时候,假如租约在有效期里面的,本地就直接去返回A的值为2,并不会再去请求Server端数据,该整个流程的时序图如下;

用户ClientAServer查询A的值检查本地缓存是否有值,此时本地缓存没有向Server端请求A的数据内容返回有关A的值,设置租约时间获取数据之后,设置数据缓存指定的租约时间返回A的值查询A的值此时本地缓存中再租约期中有A的值直接返回A的值用户ClientAServer

大致流程如上图所示,此时有关本地的缓存值就缓存在了ClientA的本地中,并且设置了一个租约时间,在这个租约时间内,ClientA查询A的内容的时候,都是直接从本地缓冲中直接返回数据。

客户端数据修改流程

假如在ClientA和ClientB都是从Server查询了A的值,此时Server分别颁给了ClientA和ClientB有关A的值得租约,此时系统的状态如下;

在这里插入图片描述

此时ClientC需要修改A的值,根据论文的大致思路,此时Server所做的操作就是先阻塞其他客户端有关A的值得读取,然后Server会等待所有客户端的租约结束,即等待一分钟之后ClientA和ClientB的租约失效,接着就ClientC修改A的值就会执行成功,此时返回ClientC的值修改成功,此时被阻塞的有关A的数据读的请求就返回数据,此时ClientA和ClientB如果需要获取A的值得话,就需要重新向Server端去获取新的值,此时就获取的就是ClientC修改的值。该过程的流程图如下;

用户ClientCServerClientD修改A的值为5修改A的值为5此时Server阻塞有关A的读请求获取A的值此时所有客户端有关A的租约都过期修改A值修改A的值成功A的值为5用户ClientCServerClientD

该过程就保证了在客户端本地缓存值得情况下,保证了数据一致性。这种机制主要就是,Server对数据的处理都是根据对客户端发放的租约进行控制的,无论客户端是否收到该租约,服务端只要在租约内都不保证不修改该数据,从而可以使客户端能够安全的使用该数据,等到租约到期之后就修改该数据,所有新进来的请求都是获取该新的数据,从而保持数据的一致性。

总结

本文主要了解了有关租约的基本原理,租约的基本原理就是在分布式环境下,通过将读数据缓存在客户端本地,从而提升读的性能,减少对远端元数据服务器的访问请求,并且在数据一致性上面,采用服务端对数据进行颁发租约的方式,如果客户端需要元数据服务器修改数据,修改的操作需要等到所有发送给客户端的租约过期然后再进行数据的修改,从而保证了数据的一致性。在这个过程中,如果客户端与服务端的时钟不同步也可能会造成数据不一致的情况,并且元数据服务器也可能存在单点问题,如果前一种问题可能通过额外手段保证时钟同步并且将服务端的租约设置的比客户端的租约要长一些都可能降低由时钟不同步引起的问题,后一个问题可以参考像zookeeper一样将元数据服务器做成集群形式对外提供服务。有关该协议的一些其他的优化措施,需要根据具体的场景进行优化,大家有兴趣可自行查阅分析。由于本人才疏学浅,如有错误请批评指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章