原文地址:http://www.infoq.com/cn/news/2017/01/Reddit-Memcached-3TB?utm_source=infoq&utm_medium=popular_widget&utm_campaign=popular_content_list&utm_content=homepage

Reddit如何使用Memcached来存储3TB的缓存数据

作者 薛命灯 发布于 2017年1月25日. 估计阅读时间: 0 分钟 | 讨论

  • 分享到: 微博 微信 Facebook Twitter 有道云笔记 邮件分享
  • 稍后阅读
  • 我的阅读清单

Reddit是著名的社交新闻网站,光是在2012年, 它的独立访客就达到了4000万,页面浏览量达到了370亿次。几年过去了,网站用户有增无减,而随着用户的增多,网站的响应速度却一直在改进。这要得益 于Reddit使用了大量的缓存。而随着网站规模不断增长,缓存数量也随着增加,那么Reddit是如何做到在增大缓存规模的同时又能保证它们的响应速度 的?

我们知道,缓存的命中率越高,整体速度就越快,因为不需要重新从数据源加载数据。除此之外,如何管理缓存,比如缓存的过期时间,新旧缓存的交换,以 及缓存的设计等等,它们对缓存的整体性能都有很大影响。来自Reddit的工程师Daniel Ellis在Reddit官方博客上分享了他们是如何使用Memcached集群来存储网站的缓存数据的。

Reddit的缓存规模和基本策略

Reddit目前使用了54个规格为r3.2xlarge的AWS EC2实例,每个实例拥有61GB内存,也就是说总的缓存大小差不多是3.3TB,而且这些缓存并不包括应用程序的本地缓存。Reddit的缓存包含了多 种类型的数据,包括数据库对象、查询结果集、函数调用,还有一些看起来不太像缓存的东西,比如限定速率、分布式锁等等。如何管理这么大规模的缓存是一件很 挑战性的事情,Reddit采用的是“不要把所有鸡蛋放在同一个篮子里”的基本策略。也就是说,他们并不是把3.3TB的内存看成一个总的大缓存池,而是 按照负载类型对缓存进行分类,每种类型占用一定数量的缓存空间。这样做有几个好处:

首先,按照负载类型对缓存进行分区,每种类型的缓存可以独立地伸缩。例如,对于数据库缓存来说,如果它的命中率降低,交换率变高,同时数据库变慢,那么就要考虑对数据库缓存进行扩展,而它的扩展不会影响到其它类型的缓存。

其次,按照负载类型对缓存进行分区,可以有针对性地对某种类型的缓存进行负载测试,从而预测该类型缓存的使用规模,并作出权衡。

第三个好处跟Memcached的内存分配模型有关系。Memcached按照板块(slab) 来分配内存,例如,1至96字节的对象可能被放到板块1,97至120字节的对象被放到板块2,并依此类推。这样做可以避免出现内存碎片。不 过,Memcached的这种分配机制不能动态变化,也就是说一旦设定好了这种模式就不能对其进行修改。如果一开始设定了用来存储1KB的对象,但后来想 用它来存储500KB的对象,那么交换率就会变得很高。而按照负载类型来区分缓存,那么就可以根据实际数据类型的大小类设定板块大小。

新版本的Memcached可能支持slab_automove功能,不过这是后话了。

Reddit的缓存类型

接下来我们来看看Reddit的几种缓存类型。

数据库对象缓存(thing-cache)

Instances 16 r3.2xlarge
Memcached Version

1.4.30

Total RAM 976 GB
Get Rate ~800k/s
Set Rate ~13k/s
Miss % 1.2-2%
Typical Object Size 384-1184 bytes

数据库对象缓存是Reddit最大的缓存池。这些对象是无schema的,开发人员可以很容易地对这些对象添加新属性,而无需对数据库schema进行变更。这些对象包括用户评论、链接和账户等等。该类型缓存是Reddit最繁忙也最有用的缓存,命中率高达99%。

主缓存(cache-main)

Instances 11 r3.2xlarge
Memcached Version

1.4.30

Total RAM

671 GB

Get Rate

~82k/s

Set Rate ~10k/s
Miss %

~75%

Typical Object Size <96 bytes

主缓存是Reddit第二大缓存池。这个缓存是一般性的缓存,里面存放的所有用来展示/r/all的结果集。不过从表格中可以看到,这个缓存的命中率并不高,大概只有25%左右。

渲染缓存(cache-render)

Instances 8 r3.2xlarge
Memcached Version

1.4.30

Total RAM

488 GB

Get Rate

~224k/s

Set Rate ~103k/s
Miss %

~45-55%

Typical Object Size 240-2320 bytes

第三大缓存用来存放渲染过的页面模板或页面片段。这个缓存相对安全,就算发生失效,也不会对系统造成太大影响。它的命中率只有大概50%左右,毕竟 页面信息需要不断更新,所以渲染过的页面模板或片段也需要更新。再则,就算这个缓存失效,也不会给数据库负载带来多大影响,因为用来渲染页面的上下文内容 已经在其它独立的缓存中加载过了。不过,因为缓存的key是基于上下文内容生成的,如果key发生变化,模板就需要重新缓存,这个需要消耗额外的CPU, 也会使页面响应时间变长。

持久缓存(cache-perma)

Instances 6 r3.2xlarge
Memcached Version 1.4.17
Total RAM

366 GB

Get Rate

24k/s

Set Rate 4k/s
Miss % <1%
Typical Object Size 96-120 bytes

最后一个要细说的缓存,也是命中率最高的缓存——持久缓存,它的命中率超过了99%。这个缓存用来存放数据库的查询结果,还有用户评论和链接。为什么管这个缓存叫持久缓存,因为他们使用了读-改-写(read-modify-write)的模式。例如,在用户新增一个评论时,他们会同时更新缓存和后端的数据库(Cassandra),而不是简单地让缓存失效,这样就避免了需要再次从数据库加载数据。

非缓存对象池

之前提过,除了上述的几种缓存,Reddit还使用了速率限定和分布式锁。

对于一个并发量很大的网站来说,采取速率限定是很重要的一个措施,它可以避免用户无限制地消耗网站的资源。他们按照时间段把不同的key存放在不同 的bucket里,每个key的TTL会随着每次调用逐步增加。通过检查这些TTL就可以确保它们不会超出限定的范围。因为一旦超过限定范围,该用户就无 法再做任何操作。

另一方面,得益于Memcached的“add”原子操作命令,他们可以实现分布式锁。因为“add”命令每次会产生一个新的key,只要这个 key原先不存在,那么就相当于获得了一把锁。锁用完了就会被移除,下一次调用“add”会生成新的锁。这个操作保证同时只有一个进程可以获得这个锁。不 过这也是他们的痛点之一。因为这里存在单点故障问题,一旦需要做迁移或维护,会让整个网站不可用。Reddit团队计划在未来逐步减少甚至避免使用这种 锁。

其它缓存池

除了上述几种缓存,Reddit还有一些小型的缓存池,比如对象关系的缓存、函数调用结果的缓存等等。因为这些缓存都不大,这里不一一赘述。

mcrouter

上面介绍了Reddit的缓存分区策略,以及各种缓存类型的特点。接下来,我们来看看Reddit是如何使用mcrouter来满足各种复杂的使用场景的。

mcrouter是由Facebook开源的Memcached连接池。为什么要用连接池?就像访问数据库要使用数据库连接池一样,使用连接池可以 对连接进行重用和管理,避免了重复创建和销毁连接的开销。Reddit有很多应用服务器,每个服务器上面运行着多个工作进程,如果这些进程独自向缓存集群 发起连接,那么连接数量会暴增。无法重用连接是一种资源浪费,同时会给缓存集群带来更大压力。通过在应用服务器上使用mcrouter,当前服务器上所有 进程到缓存集群的连接可以形成一个连接池,并通过mcrouter这个唯一的出口连接到相应的缓存上。

除了作为连接池,mcrouter还能处理很多复杂的场景。mcrouter提供了多种路由类型,比如PrefixSelectorRoute,它通过匹配key的前缀来决定应该到哪个缓存上获取数据。这样就可以把特定功能的操作路由到特定的缓存上。

如果要往缓存集群里增加新的缓存实例,那么可以使用WarmUpRoute。 新加入的缓存实例被称为“冷”缓存,而原先的实例叫作“热”缓存。WarmUpRoute的工作原理是说,把所有写操作路由到“冷”缓存上,而把未命中的 读操作路由到“热”缓存上,然后把在“热”缓存上命中的缓存结果异步地更新到“冷”缓存上,那么下次同样的读操作就也可以在“冷”缓存上命中。通过拷贝 “热”缓存里的数据可以避免操作数据库,保证性能不会受到影响。

mcrouter还提供了FailoverRoute,顾名思义,这个特性可以避免缓存的单点故障,因为它会为一种类型的缓存创建多个缓存池,如果其中一个失效了,请求会被路由到另一个备份的缓存实例上。

Reddit还使用了影子缓存。不同于WarmUpRoute,WarmUpRoute只是把未命中的读操作拷贝到新实例上,而影子缓存会把读操作 和写操作都拷贝一份到新的实例上,但前提是不改变数据源。通过影子缓存,他们可以对缓存的负载情况进行观察,因为新加的实例作为旧实例的“影子”而存在, 在不影响旧实例的前提下可以看到整个缓存的工作情况。

mcrouter还支持数据复制,这个功能不仅为缓存提供了高可用性,同时防止出现缓存热点。

自定义监控

缓存有时候会变成一个黑盒,所以对它们进行监控是很有必要的。GitHub上有一个叫做Diamond的 Python脚本可以收集Memcached的基本统计信息,比如对象的交换和命中率等等。不过这些信息还太简单,Reddit团队需要知道在发生对象交 换时,缓存内部还发生了其它什么状况。因为通过Memcached的“stats slabs”命令可以看到板块的度量指标,于是他们基于这些命令自己写了一个追踪板块度量指标的工具。他们还开发了一个简陋的可视化仪表盘:

Reddit团队还开发了另外一个工具,叫作mcsauna。这个工具被部署在每个缓存服务器上,它可以检测网络流量,并根据配置规则把不同的key保存在不同的bucket里,然后把结果输出到文件上。FilesCollector会收集这些文件,分析里面的key,并以图形化的方式呈现出来。从这些图形上可以看出那些热点的key。

展望

缓存为提升网站的响应速度做出了不可磨灭的贡献。而在如何使用缓存方面,Reddit还有很长的路要走。接下来,他们可能要想着如何通过服务发现来 对配置进行自动化,从而实现缓存的自动扩展,而不需要人工的介入。而随着Memcached版本的不断改进,他们也要针对现有系统进行调整,从而最大化缓 存的性能。

转载于:https://www.cnblogs.com/davidwang456/articles/6362310.html

Reddit如何使用Memcached来存储3TB的缓存数据--转相关推荐

  1. 微信小程序数据存储长时间缓存数据,数据存储本地

    安卓和小程序体验 小程序体验 安卓版本体验 安卓体验download 数据存储 使用场景 许多时候我们需要将用户的数据保存到本地,以便以后的调用.比如说openid,如果每次打开小程序都需要发送cod ...

  2. memcached java 客户端优化,分布式缓存技术memcached学习系列(五)—— memcached java客户端的使用...

    Memcached的客户端简介 我们已经知道,memcached是一套分布式的缓存系统,memcached的服务端只是缓存数据的地方,并不能实现分布式,而memcached的客户端才是实现分布式的地方 ...

  3. Memcached命令-存储命令-查找命令-清理命令

    Memcached set 存储命令 Memcached set 命令用于将 value(数据值) 存储在指定的 key(键) 中. 如果set的key已经存在,该命令可以更新该key所对应的原来的数 ...

  4. Memcached:高性能的分布式内存缓存服务器

    Memcached:高性能的分布式内存缓存服务器 特征: u 协议简单: n 基于文本行的协议 u 基于libevent的事件处理: n 程序库,能实现连接数的增加,O(1)性能 u 内置内存存储方式 ...

  5. SpringBoot整合(四)整合Ehcache、Redis、Memcached、jetcache、j2cache缓存

    ​ 企业级应用主要作用是信息处理,当需要读取数据时,由于受限于数据库的访问效率,导致整体系统性能偏低. ​ 为了改善上述现象,开发者通常会在应用程序与数据库之间建立一种临时的数据存储机制,该区域中的数 ...

  6. DNA存储,拯救人类数据危机的良方?

    来源:脑极体 开一个脑洞:如果地球正在面临一场马上到来的毁灭性星际灾害,人类又想尽可能地保存地球的生命和文明,在现有条件下,该怎么办? 像大刘一样让地球停止自转然后逃离太阳系,这恐怕来不及了.而如果像 ...

  7. 数据存储(1):从数据存储看人类文明-数据存储器发展历程

    传统文本存储 泥版/钟鼎/甲骨/莎草纸/羊皮纸等文字存储 传统的考古学家和历史学家认为,楔形文字起源于美索不达米亚特殊的渔猎生活方式.这是较为通行的看法,西方的各种百科全书大都持这一观点.约在公元前3 ...

  8. innodb一页为什么要存储两行记录_innodb数据记录存储结构

    innodb页 数据存储在磁盘上:数据处理的过程发生在内存中,需要把磁盘的数据加载到内存中:处理写入或修改请求时,需要把内存中的内容刷新到磁盘上: innodb存储引擎,不是一条一条从磁盘读取记录,而 ...

  9. java的知识点45——CLOB 存储大量的文本数据与 BLOB 二进制大对象

    CLOB(Character Large Object) 用于存储大量的文本数据 大字段有些特殊,不同数据库处理的方式不一样,大字段的操作常常是以流的方式来处理的. 测试CLOB 文本大对象的使用   ...

最新文章

  1. 2016年3月23日作业(项目进度管理、项目成本管理)
  2. 我能不能理解成 ssh中service就相当于与jsp+servlet+dao中的servlet???
  3. 解决Android Device Chooser 找不到设备问题
  4. java 编辑我的世界_Editing Java版1.13 (section)
  5. 【转载】如何做一份突出的PPT
  6. python isinstance和issubclass区别
  7. 【活动回顾】Edge X Kubernetes,探索云原生新边界
  8. mac给服务器传送文件
  9. 前端学习(3319):undefine和null
  10. 在线颜色拾取器 - 资源篇
  11. PHP7内核基础知识之变量类型
  12. [Java] 蓝桥杯ADV-213 算法提高 3-2求存款
  13. [转]C#用SHA对密码加密
  14. spark成长之路(1)spark究竟是什么?
  15. 关于raw_input()和sys.stdin.readline()的区别
  16. 【人话版】WEB3黑暗森林中的隐私博弈
  17. MMDet——基于Chamfer Distance评估点集
  18. 【软考 系统架构设计师】计算机组成与体系结构⑥ 流水线
  19. iTron3学习笔记(一) System Calls of Memory Pool Management Functions
  20. 【学堂上新】大规模动画模拟的一种实现方法

热门文章

  1. 计算MATLAB时间复杂度的例子,学编程数学到底有多重要?线性代数能否视为一门程序语言呢?...
  2. 自考计算机及应用笔记,自考“计算机及应用”专业论文参考范文
  3. mysql 唯一索引 性能_普通索引和唯一索引的区别、性能差异,以及其他索引简介...
  4. 融云php sdk下载安装,LICENSE · 融云 RongCloud/server-sdk-php-composer - Gitee.com
  5. java标注释_跪请JAVA高手帮忙标一下注释
  6. MySQL中的char和varchar类型
  7. java 中while编译之后_从APK反编译的Java-while循环什么也不做
  8. css匹配title,解决css中的匹配问题
  9. zip()和zip(*)的区别与使用
  10. caffe的prototxt文件