本文进行对于Scaling Memcache at Facebook一文的部分内容摘取
旁路缓存(look-aside cache)的场景
系统的架构是不断衍化的,在初期,可能通过一个服务器即能够撑住所有的静态页面,动态资源,数据等资源的提供,但是随着用户量和需求的不断变动,逐渐单机承载不下,就需要不断的扩展各个服务的性能。其中,对于储存服务的一种较好扩展,自然也就是旁路缓存(look-aside cache).
下面先将对应的数据规模局限在有数千个服务器组成的集群上
在如此大规模的集群之下,对应的应用侧的请求也具有一定的特征,其对于一个页面的拉取,通常来说并不像个人搭建的小网站一样只拉取几个资源。此时对应的一个热门页面的请求的元素拉取量甚至于能够到达500+的数量级。在这种数量级下,如果去减少对应的获取item的延迟将会是提高用户体验至关重要的一环。
在这种情况下,势必需要引入缓存,即MemCache层,对应的应用侧的服务器也需要不断与这些服务器之间通信来获取可能存在的缓存信息。但是可以想象,如果每个应用侧服务器都需要与MemCache服务器通信,对应的状态管理将会膨胀到N*M的程度,此时对于网络来说,如果存在一端的错误,容易导致incast congestion。同时,在这种多对多的情况下,任意一个节点的抖动,都容易导致成为整个系统的瓶颈。在这种系统中,replication不一定能够解决问题,获取其能够解决一个单点瓶颈的场景,但是同时其也会引入更为复杂的状态管理。所以我们需要一种更加合适或者说更加详细的机制来补偿当前为了提供大规模服务的缺陷。
Reducing Latency
由于服务的本质问题,对于一个webServer与各个MemCache之间的通信,我们是无法避免的,但是这些庞杂的通信中,存在着一些无用的通信,如果能够在应用侧发起的时候就检测到,那么就不必向没有数据的服务器发起信息了,自然能够减少一些网络压力。此时就需要一种方法,来让应用侧了解到其如果想获取一个数据,其需要去往哪个MemCache服务器能够直接获取。在论文中,为了实现这一种视图,使用了多种方法协同。其中,在数据分布方面,其使用一致性哈希来保证数据的分布可追踪,但是这种机制不是其索引对应的key所在的MemCache的服务器的机制。严格来说,可能是我对于论文阅读不够深入,我没有找到对应的关于这方面的描述。
不过就我个人猜测而言,其可能存在一种通过一致性哈希产生的结果来形成的表,其中储存的是一个key与储存的MemCache之间的映射关系。在McRouter需要去查找一个key时,可以通过该类数据机构来直接向某个MemCache定向发送,不必再向全部的MemCache服务器广播请求。
Items are distributed across the memcached servers through consistent hashing [22].Thus web servers have to routinely communicate with many memcached servers to satisfy a user request. As a result, all web servers communicate with every memcached server in a short period of time.This all-to-all communication pattern can cause incast congestion [30] or allow a single server to become the bottleneck for many web servers. Data replication often alleviates the single-server bottleneck but leads to significant memory inefficiencies in the common case.
批处理
在减少延迟这一方面,论文中提出了使用合并请求来提高响应的做法,其思路也很清晰,就是通过在Client侧维护一个DAG图。图中储存的是哪些key可以并发的获取,Client侧可以根据这个信息来合并key请求,这种批处理的思想很常见,不过这里的这种应用场景倒是给了我们一个启发。就是对于一些零散的请求,寻找一种方式来尝试合并,更直白点,批处理的方式是一种提高资源的利用率的不错方法。
协议选择
如果以网络中的层次来看,上面的批处理是在应用层上的优化。接下来,论文中提出了在网络层上的优化,相对来说也很简单,就是更具重要程度,来对于各种操作所使用的协议来进行抉择。对于一些不敏感的操作,就比如get操作,其使用了UDP,对于set和delete操作,其使用了TCP。相对来说,确实引入了一定的复杂度,不过这种复杂度实现起来倒也还行,而且相对来说,其所提高的那几个百分点的性能,是非常重要的,回顾一下前文提到的系统体量和用户量,这小小几个百分点所实际上代表的数据量其实已经很大了。
拥堵控制
恰如计算机网络一书中的阐述流程,在前面进行了一定的分析后,系统进入了流量大小的分析。由于系统体量太大,内部的通信是否会存在拥堵的现象。为了能够缓解或者限制这种Incast congestion现象,论文中提出了与TCP中流量控制的相似机制,滑动窗口。通过对应的窗口来实现流量的控制。此处如果系统学过计网,应该能够了解这种机制以及在应用层自己来封装一层额外的滑动窗口机制的好处所在。此处不必赘诉。
总的来说,在Reducing Latency这里,给我所带来的最大启发为,在我们遇到一些问题时,我们可以尝试在已经了解到的领域中去查找是否存在类似问题的解决方案,对于一个CSer来说,计算机网络就是一个非常完善且存在大量可以借鉴经验的宝库。
Reducing Load
下文进入另外一个有趣的方面,论文3.1节在考虑如何减小延迟,其中涉及到一些分布式中常规的一些场景,但是其给出了更加详细的场景以及实际的解决方案。
对于缓存这种基础设施,其不免会存在几个常见的场景,当缓存数据失效时,当为了恢复缓存失效时。针对这些个问题,需要根据实际的场景来分析,本论文中给出了一些个针对于这些问题的解决方案。
缓存失效
在论文中,关于缓存失效,其可能是由于一个web server发起了set请求,但是并发存在对于该key的update请求而导致的竞态,也可能是由于一些替换策略,一些delete操作等。此时就可能由于缓存数据的丢失,而导致cache miss,此时对应的请求就会转向一些代价更加昂贵的路径(eg:数据库,分布式储存等)。此时如果存在大量的请求都走了这种路径,那么对应的端点的压力自然就会很大。此时,如何来缓解这种惊群现象就成了一种重要的优化思路。
一如在其他分布式系统中对于缓存失效/缓存穿透的分析,论文中也提出了一种Lease机制。类似与其他一些系统,FB中的租约由MemCache服务器来进行生成与管理。其他方面与其他的实现中也大差不差,都是在一个key失效时,只给后续对于这些key的并发请求中的一个颁发Lease,此时获取Lease的Client将会负责重新构建缓存,而其他的Client,则会在获取Lease失败后休眠一会,减少惊群效应的影响。
除此之外,论文中对于一些缓存失效场景进行了一些优化。其中是当缓存失效是由delete操作引起时的操作。当Client发起一次delete操作后,该key在MemCache实际上不一定会被删除,而是会进入一种特殊的数据结构,其中储存了近期被删除的部分key。此时对于这种临界key的访问仍然正常。但是注意到的是,这其实是一种对于stale data的查找,所以其是强依赖与应用场景的。在论文中,其也说明了这是对于部分数据所进行的优化,同时这种优化对于其服务来说确实给到了一定的性能优势。
此时不难可以猜想这种优化可能的原因,就比如,当我对于一个FaceBook的条目点赞时,此时会触发set操作来进行更新,此时会使得MemCache中的数据失效(delete操作)。对于这种场景来说,实际上用户即使看到了一些过时的数据,也不会存在太大的疑惑,就比如你看到你朋友圈中一个人点赞或者俩个人点赞其实影响不大。所以实际上这种设计是强依赖于业务场景实现的。
请注意,论文中此处的delete操作,是指前文中对于一个Key进行更新(set/…)时会产生的delete请求(个人理解)
Our experience has shown that since the cached value tends to be a monotonically increasing snapshot of the database, most applications can use a stale value without any changes.
缓存池
文中给出了一种其在实际的场景中发现的一种现象。对于MemCache不同类型的数据,其对于一个MemCache服务器的适应性和影响都不竞相同。
Different applications’ workloads can produce negative interference resulting in decreased hit rates.
文中给这种现象提供了一种解决方案,将具有相同性质的数据进行聚合,如下文。
For example, we may provision a small pool for keys that are accessed frequently but for which a cache miss is inexpensive. We may also provision a large pool for infrequently accessed keys for which cache misses are prohibitively expensive.
这种聚合管理的思路在现实中倒也比较常见,不过将这种思路运用到实际的设计中倒是很灵活。而且后续的数据提供的数据测量也不得不让人认可其的实际可行性。
单点瓶颈
前文从集群的MemCache的较高层视图来分析了一些场景,接下来将视角聚集到较高粒度的