Scaling Memcache at Facebook

Scaling Memcache at Facebook

概要:Memcached 是一个知名的,简单的,全内存的缓存方案。这篇文章描述了facebook是如何使用memcached来构建和扩展一个分布式的key-value存储来为世界上最大的社交网站服务的。我们的系统每秒要处理几十亿的请求,同时存储了几万亿的数据项,可以给全世界超过10亿的用户提供丰富体验。

1.摘要

1.1.文关注于memcached,这是一个全内存哈希表的开源实现,它以较低的开销提供了对共享存储的低迟延访问。有了这些特性我们可以构建数据密集的功能,否则是不可能的。

2综述

以下特点大大影响了我们的设计。第一,用户阅读的内容比他们创建的要多一个数量级,这种行为(读写的特点)所产生工作负载,显然让缓存可以发挥很大的优势。第二,我们是从多个来源读取数据的,比如MySQL数据库、HDFS设备和后台服务,这种多样性要求一个灵活的缓存策略,能够从各个独立的源中储存数据。

MemCached提供了一组简单的操作(set、get和delete),使它在一个大规模的分布式系统中成为注目的基础组件。开源版本提供了单机内存哈希表,在本文中,我们从这个开源版本开始,讨论我们是怎么使用这个基础组件,使它变得更有效,并用它来建一个可以处理每秒数十亿请求的分布式的键-值储存系统

图1:Memcache作为填补需求的旁路缓存系统。左半图说明了WEB服务器读取缓存时命中失败的读取路径,右半图说明其写路径。

查询缓存:我们依赖于memcache来减轻读取数据库的负担。特别的,我们使用memcache作为填补需求的旁路缓存系统,如图1。当一个Web服务器需要数据时,首先通过一个字符串的键在memcache中请求,如果没有找到,它会从数据库或者从后台服务中检索,再使用该键把结果存回memcache中。对于写的请求,Web服务器发送SQL语句到数据库,接着发送删除请求到memcache,使旧的缓存数据失效。因为删除是幂等运算,所以我们使用删除缓存的方式,而不是更新缓存。

在应对MySQL数据库繁重的查询通信的众多方法中,我们选择了memcache,在有限的资源与时间限制下,这是最好的选择。此外,缓存层与持久层分离,让我们可以在工作负载发生变化时快速地调整。

通用缓存:我们同样让memcache成为一个更加通用的键-值储存系统。比如说,工程师们使用memcache保存复杂的机器学习算法的中间结果,这些结果能被很多其它应用程序所使用。它只需要我们付出很少的努力,就可以让新增的服务利用现有的正在使用的基础设施,而无需调整、优化、调配和维护大型的服务器群。

正如memcached没有提供服务器到服务器的协同,它仅仅是运行在单机上的一个内存哈希表。接下来我们描述我们是如何基于memcached构建一个分布式键值储存系统,以胜任在Facebook的工作负载下的操作。

论文的结构主要描述了在三种不同的规模下出现的问题。当我们拥有第一个服务器集群时,频繁的读负载和广泛的输出是我们最大的担心。当有必要扩展到多个前端集群时,我们解决了集群间的数据备份问题。最后,我们描述了一种机制,这种机制让我们可以在全世界伸展集群的同时提供平滑的用户体验。不论在什么尺度上,容错性和操作复杂性总是很重要的。我们展示了重要的数据参考,这些数据指引我们做出了最终的设计决定,读者如需获得更多细节性的分析,请参看Atikoglu et al.[8]的工作。提纲挈领的解释参看图2,这是最终的架构,我们将并置集群组织起来,形成一个群体(region),指定一个主群体(master),由主群体提供数据流让非主群体保持数据同步。

在系统的发展中,我们将这两个重大的设计目标放在首位:

1. 只有已经对用户或者我们的运维产生影响的问题,才值得改变。我们极少考虑范围有限的优化。

2. 对陈旧数据的瞬态读取,其概率和响应度类似,都将作为参数来调整。我们会暴露轻度陈旧的数据以便后台存储和高强度负载绝缘。

3 集群之中: 延迟和负载

现在考虑集群中数以千计的服务器所带来的挑战。在这种规模之下,我们着眼于减少获取缓存时的负载,以及缓存不中时数据库的负载。

3.1 减少延迟

不论缓存是否命中,memcache的响应时间都是影响总响应时间的重要因素

为了减少数据库等的负担,我们准备了缓存集群,每个集群都由数百台memcache服务器组成。资源个体经hash后存于不同的memcache服务器中。因此,web服务器必须请求多台memcache服务器,才能满足用户的请求。由此导致在很短的时间里每个web服务器都要和所有的memcache服务器沟通。这种所有对所有的连接模式会导致潮涌堵塞(incast congestion)或者某台服务器不幸成为瓶颈。实时备份可以缓解这种状况,但一般又会引起巨大的内存浪费。

我们减少延迟的方法主要集中在memcache客户端,每一个web服务器都会运行memcache客户端。这个客户端提供一系列功能,包括:串行化、压缩、请求路由、错误处理以及请求批处理。客户端维护着一个对所以可获得的服务器的映射,对这个映射表的更新需要通过一个辅助的配置系统。

并行请求和批处理:我们构建web应用代码,目的是最小化对于页面请求回应所必要的网络往返数。我们构建了有向无环图(DAG)用来表示数据间的依赖。web服务器使用DAG来最大化可以并发读取的项目数。平均来说,这些批量请求对于每个请求包含24个主键

客户端使用UDP和TCP协议与memcached服务器通讯。我们依赖UDP来使请求的延迟和开销缩减。因为UDP是无连接的,web服务器中的每个线程都被允许直接与memcached服务器通信,通过mcrouter,不需要创建与维护连接因而减少了开销。UDP实现了检测出丢失的或失序接收(通过序列号)的包,并在客户端将它们作为异常处理。它没有提供任何试图恢复的机制。在我们的基础架构中,我们发现这个决定很实际。在峰值负载条件下,memcache客户端观察到0.25%的请求会被丢弃。其中大约80%是由于延迟或丢失包,其余的是由于失序的交付。客户端将异常作为缓存不命中处理,但是web服务器在查询出数据以后,会跳过插入条目到memcached,以便避免对可能超载的网络会服务器增添额外的负载

6 单个服务器的提升

多对多的通信模式隐含着单独的服务器将会成为集群的瓶颈。这章将会讲述性能调优和memcached内存效率的提高,这有利于集群更好的扩展。提升单个服务器缓存的性能是一个活跃的研究领域[9,10,28,25]。

6.1 性能调优

我们开始使用具有固定大小哈希表的单线程memcached。第一批主要的优化是:(1)允许哈希表自动扩展来避免查找时间漂移到O(n),(2)通过一个全局锁来保护多数据结构使得服务器多线程化,(3)赋予每个线程独立的UDP端口来减少发送副本和稍后传播中断处理开销的争用。前两个优化都贡献给了开源社区。下述章节将会探索还没在开源版本出现的进一步优化。

6.2 适应性的slab分配器

memcached使用一个slab分配器来管理内存。这个分配器将内存组织为slab类,每类包含预分配的均匀大小的内存块。memcached将数据项存储到可以适应数据项元数据、键和值大小的最小可能性的slab类。slab类从64byte开始,以1.07为因子指数性增加到1MB,以4byte对齐3。每个slab类维护一个可获得内存块的空闲列表,当它的空闲列表是空的,那么就从1MB slab中请求更多内存。一旦memcached服务器再也不能分配空闲内存,通过移除slab类中最近最少使用(LRU)的数据项来存储新的数据项。当工作负载改变时,原有分配给每个slab类的内存可能不再足够,这样将会导致低命中率。

6.3 临时条目的缓存

因为memcached支持过期时间,条目在它们过期之后仍可以驻留在内存中。 当条目被请求时或者当它们到达LRU的尾端时,Memcached会通过检查过期时间来延时剔除这些条目。 尽管在一般情况下很有效,但是这种模式允许那些偶尔活跃一下的短期键值占据内存空间,直到它们到达LRU的尾部。

所以我们引入一种混合模式,对多数键值使用延时剔除,而对过期的短期键值则立即剔除。我们根据短期条目的过期时间把它们放入一个由链接表构成的环形缓存区(花费几秒编入索引直到过期) – 我们称之为临时条目缓存区。每一秒钟,该缓存的头部数据格里的所有条目都会被剔除,然后头部向前移动一格。当我们给一个频繁使用的键值集合(它们对应条目的寿命很短)设置一个短超期时间后, 该键值集合使用的memcache缓冲池的比例从6%下降到0.3%,而没有影响到命中率

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值