经典分布式论文阅读:Memcache

本文是Memcached论文的阅读笔记,本文主要描述了如何使用memcached构建一个分布式键值存储系统。前端

一个社交网络的基础设施应该知足如下特性:数据库

  1. 容许几乎实时的通信;
  2. 从多个源头快速聚合内容;
  3. 可以访问和更新热门的共享内容;
  4. 每秒可以处理百万用户请求。

本文以memcached为基础构建分布式键值存储系统,在特定的规模之下,某些特性须要更多的努力去知足。后端

总览

如下两个特性影响了系统的设计:缓存

  1. 用户消费的内容比生产的内容多得多;
  2. 一个读取操做须要从多个源头获取数据。=-

下文使用memcached指代源代码或者运行中二进制文件,使用memcached指代分布式系统。性能优化

查询缓存memcache做为demand-filled look-aside缓存来使用,当某个Web请求数据的时候,首先尝试从缓存中获取,若是缓存中不存在,那么从后端获取数据并写回缓存,若是更新数据的话,须要将旧的数据从缓存中删除。服务器

通用缓存memcache也能够做为通用的键值存储来使用,例如保存机器学习计算结果等等。网络

本文描述了不一样尺度下的重点,可是始终强调两个设计目标:数据结构

  1. 任何改进必须解决用户或者运维问题;
  2. 将读取到短暂的过期数据的可能性做为能够调整的参数。

集群尺度:延迟和负载

memcache运行在集群尺度上的时候,主要考虑的问题是减小解析缓存数据延迟和缓存缺失带来的负载。多线程

下降延迟

memcache使用一致哈希将存储对象分散到各个服务器上,所以所有Web服务器短期内会链接全部的服务器。下降延迟的工做主要在客户端完成序列化、压缩、请求路由、错误处理和批量请求等工做并发

并行请求和批量:可使用有向无环图分析数据之间的依赖关系,使得一次请求获取尽量多的键值。

客户端-服务器通信:服务器之间不进行互相通讯,由客户端处理系统复杂性。客户端的逻辑由两部分组成:

  • 一个可以嵌入应用程序的库
  • 一个独立的代理mcrouter

get请求使用UDP协议来下降延迟和负载,若是数据包丢失或者乱序将被视为错误。Web服务器将客户端错误视为缓存缺失,可是从数据源获取数据不作写回。setdelete操做经过TCP协议进行。每一个线程建立一个链接很是浪费资源,运行在同一个机器上mcrouter将这些链接进行合并,提升网络利用率。

请求拥塞memcache使用流控制机制来限制请求拥塞,客户端使用滑动窗口来控制请求数量,窗口随着成功请求数据而扩大,随着未答复请求而减少。

太小的窗口会致使没必要要的等待,而过大的窗口会致使请求阻塞,须要找到平衡点。

下降负载

租期:系统使用了租期机制来解决过期数据惊群效应。并发更新乱序以后会产生过期的数据。频繁的写入操做会频繁地使得缓存失效,大量的读取操做会同时转向请求数据源。

当客户端请求的缓存缺失的时候,服务器分配一个和键绑定的租期,在写回数据的时候须要验证租期合法性。若是验证以前服务器收到过删除请求,那么租期就失效了。

惊群效应能够限制租期产生速率解决,例如10秒钟一个,若是其余客户端在这个10秒以前请求对应的键,那么让它等待一小会儿时间,当客户端再次尝试的时候,数据通常已经在缓存之中。

某些场景下过期数据是能够接受的,当数据被删除后被转移到一个保存最近删除数据的数据结构中,存活一小段时间,一个获取请求返回租期或者过期的数据。

Memcache池:不一样的应用程序使用同一个memcache会相互干涉产生负做用,所以能够考虑将memcached服务器分散到不一样的池中,将不一样读写特性的数据存入不一样的池中。

在池中多副本:若是知足如下特性,那么能够在池中创建多副本:

  1. 应用同时请求不少键
  2. 整个数据集可以放在一个或者两个memcached服务器中
  3. 请求速率远超一个服务器可以处理能力

若是使用了多副本,那么在使缓存失效时要对全部副本进行。

故障处理

咱们必须解决两种规模下的故障:

  1. 由于网络或者服务器错误致使少许主机不可达;
  2. 影响集群中大部分服务器的大规模宕机。

对于小规模的宕机,系统设置了少许称为Gutter的机器来暂时管理不可用机器的键范围,Gutter中的数据有效期很短,这样避免了须要使缓存失效的操做。

区域尺度:副本

随着负载规模增大,简单地扩充机器是不够的。做者将Web服务器和memcached服务器分为多个前端集群,和一个存储集群组成一个区域

区域失效

存储集群保存着最新数据,用户请求将数据副本写入到前端服务器。存储集群负责发送缓存失效命令,来保持数据的一致性。对数据产生修改的SQL会附上须要失效的mamcache键,应用更改以后由mcsqueal将缓存失效消息发送给各个前端集群中的服务器。

下降数据包率:若是直接将失效缓存消息会浪费网络资源,所以须要将缓存失效消息批量发送给每一个前端集群中的mcrouter,再由mcrouter转发给集群内的服务器。

经过Web服务器失效:之因此不让Web服务器直接发送缓存失效消息是由于:

  • 经过Web服务器进行批量处理比较低效
  • 在消息路由错误时候方便补救

区域池

集群独立地缓存数据,一个数据可能在多个集群上有副本,能够经过让两个集群共享memcached服务器,这种形式称为区域池。能够根据访问速率、数据集大小和访问用户数量来决定是否将数据存入区域池。

集群冷启动

若是上线一个新的集群,那么刚开始负载都会指向数据库。做者经过冷启动预热机制解决,容许Web服务器从其余集群获取数据并写回。

固然这样会带来不一致的问题,例如当一个客户端更新了数据,同时另一个客户端恰好转向其余集群获取数据,恰好缓存失效消息尚未到达。做者采用删除拖延解决这个问题,在收到删除消息两秒以内禁止写回。当客户端写回被拒绝后,说明数据已经被更新,须要从数据库获取。

跨区域:一致性

在多个地理位置部署数据中心有如下好处:

  1. 将Web服务器放在距离用户近的位置能够减小延迟
  2. 地理分散能够缓解天然灾害和断电事故
  3. 新的地点可能会提供更廉价的电力以及其余经济效益

跨区域方式设计成一个区域管理主数据库,其余区域保存只读副本。这样带来的一个问题就是:副本数据和主数据库之间存在一些延迟。系统在强调性能和可用的同时,提供尽最大力的最终一致性。

写入主区:使用mcsqueal传输失效消息能够避免失效信息先于数据更新到达。

写入非主区:若是一个非主区域的用户更新了数据,那么若是它接着从本地区域读取数据可能看不到更改。这种状况下要求必须在本地数据库遇上以后才能重来填充缓存,做者使用了远程标记来解决这个问题。

当Web服务器更新键值k时:

  1. 在区域创建一个远程标记r_k
  2. 在主区域进行写操做,并指示使k和r_k失效
  3. 删除本地集群上的k

这样当k缺失的时候,若是客户端看到r_k,那么就去从主区域获取数据。

运维考虑:跨区域通讯代价高,所以删除消息和副本同步共用一个信道。

单机优化

性能优化memcached主要的性能优化为:

  1. 容许哈希表自动展开,避免查询时间退化到O(n)
  2. 让多线程服务器使用全局锁来保护多种数据结构
  3. 分配给线程独立的UDP端口来避免数据传输竞争

自适应的slab分配器

memcached使用slab分配器管理内存,将内存空间块组织成slab类,为数据分配内存的时候会寻找符合其大小最小的块,若是内存块不足则继续申请。当机器内存不足以分配新的内存块是,淘汰类中的LRU内存块。

做者优化了slab分配器来调整slab中内存块数量来适应负载。若是某个类正在淘汰内存块而且下一个要被淘汰的数据比每一类平均要淘汰的数据新20%,那么说明这个类须要更多的内存块。从当前保存全局LRU的slab中回收内存分配给这个slab。

短周期数据缓存:短期活动产生的短命键会浪费内存,做者使用混合策略来解决这个问题:对大多数键进行惰性回收,对短命键进行主动回收。把短命键数据放在一个按照过时时间排序的链表里面,每秒钟回收头部的短命键。

软件更新:为了在软件更新过程尽量减小中断时间,做者修改了memcache,将缓存和数据结构保存在System V共享内存区域中,避免在更新时丢失数据。

参考文献

  1. Nishtala, Rajesh, et al. "Scaling memcache at facebook." Presented as part of the 10th {USENIX} Symposium on Networked Systems Design and Implementation ({NSDI} 13). 2013.
相关文章
相关标签/搜索