写点什么

微博 CacheService 架构浅析

2014 年 4 月 18 日

微博作为国内最大的社交媒体网站之一,每天承载着亿万用户的服务请求,这些请求的背后,需要消耗着巨大的计算、内存、网络、I/O 等资源。而且因为微博的产品特性,节假日、热门事件等可能带来突发数倍甚至十几倍的访问峰值,这些都对于支撑微博的底层基础架构提出了比较严苛的要求,需要满足:

  1. 每秒数十万的用户请求
  2. 数据更新的实时性
  3. 服务请求的低响应时间
  4. 99.99% 以上的服务可用性

为了满足业务的发展需要,微博平台开发了一套高性能高可用的 CacheService 架构用于支撑现有线上的业务系统的运转。但“冰动三尺非一日之寒”,微博的 Cache 架构也是经历了从无到有,不断的演进过程。

基于 MySQL 的 Web 架构

最初的微博系统,系统的访问量都比较小,简单的基于数据库 (MySQL) 已经能够满足业务需求,开发也比较简单,简单的架构示意图如下:

随着微博的推广和名人用户入驻微博,带动了用户量的快速增长,访问量也与日俱增,这个时候,简单基于 MySQL 的架构已经略感吃力,系统响应也比较缓慢,因为 MySQL 是一个持久化存储的解决方案,数据的读写都会经过磁盘,虽然 MySQL 也有 buffer pool,但是无法根据业务的特性做到很细粒度的控制,而在微博这种业务场景下,配置了 SAS 盘的 MySQL 服务单机只能支撑几千的请求量,远小于微博的业务请求量。

基于单层 Cache+MySQL 的 Web 架构

针对请求量增大的问题,一般有几种解决方案:

  1. 业务架构改造,但是在这种场景下,这种方案的可行性不高。
  2. MySQL 进行从库扩容,虽然能够解决问题,但是带来的成本也会比较高,而且即使能够抗住请求量,但是资源的响应时间还是无法满足期望的结果,因为磁盘的读取的响应时间要相对比较慢,普通的 15000 转 / 分钟的 SAS 盘的读取延迟平均要达到 2ms 以上。
  3. 在 MySQL 之上架构一层缓存,把热门请求数据缓存到 Cache,基于 Cache+MySQL 的架构来提供服务请求。

考虑到整体的改动和成本的因素,基于方案 3) 比较适合微博的业务场景。而应该使用什么类型的 Cache 比较合适呢?

比较常见的 Cache 解决方案有:

  1. Local Cache,通过在 Web 应用端内嵌一个本地的 Cache,这种的优势是访问比较快,但是存在的问题也比较明显,数据更新的一致性比较难保证,因此使用的范围会有一定的限制。
  2. 单机版的远程 Cache,通过部署一套远程的 Cache 服务,然后应用端请求通过网络请求与 Cache 交互,为了解决应用的水平扩展和容灾问题,往往通过在 client 层面来实现数据的路由等。
  3. 分布式的 Cache,Cache 服务本身是一个大集群,能够提供给各种业务应用使用,并提供了一些基本的分布式特性:水平扩展、容灾、数据一致性等等。

从系统的简单性考虑和微博场景的适用问题,最终选择了 2) 的方式,基于开源的 Memcached 来作为微博的 Cache 方案。

Memcached 是一个分布式 Cache Server,提供了 key-value 型数据的缓存,支持 LRU、数据过期淘汰,基于 Slab 的方式管理内存块,提供简单的 set/get/delete 等操作协议,本身具备了稳定、高性能等优点,并在业界已经得到广泛的验证。它的 server 端本身是一个单机版,而分布式特性是基于 client 端的实现来满足,通过部署多个 Memcached 节点,在 client 端基于一致性 hash(或者其他 hash 策略) 进行数据的分散路由,定位到具体的 memcached 节点再进行数据的交互。当某个节点挂掉后,对该节点进行摘除,并把该节点的请求分散到其他的节点。通过 client 来实现一定程度的容灾和伸缩的能力。

这种架构经过一段时间的蜜月期后,也逐步遇到了一些问题。

  • 节点挂掉导致的瞬间的峰值问题

    比如部署有 5 个 Memcached 节点,对 key 做一致性 hash 将 key 散落分布到 5 个节点上,那么如果其中有 1 个节点挂掉,那么这个时候会有 20% 原本 Cache hit 的请求穿透到后端资源 (比如 DB)。对于微博而言,多数核心资源的 Cache hit 的比例是 99%,单组资源的 QPS 可能就达到 100W 以上的级别,如果这个时候有 20% 的穿透,那么相当于后端资源需要抗住 20W 以上的请求,这对于后端资源来说,明显压力过大。

  • 某组资源请求量过大导致需要过多的节点

    微博的 Feed 业务是 Cache 资源的消耗大户,几十万的 QPS,GB(Byte) 级别以上的带宽消耗,这个时候,至少需要十几个 Memcached 节点单元才能够抗住请求,而过多的 Memcached 节点请求会导致 multiget 的性能有弱化,因为这个时候 keys 分散到的 Memcached 节点会比较多,因此当进行拉取聚合的时候,性能会受影响,同时 mutliget 的响应时间受最慢的那个节点的影响,从而无法达到服务的 SLA 要求。

  • Cache 的伸缩容和节点的替换动静太大

    对于微博这种会在热点事件、节假日等发生时会有一些变态峰值 (往往是数倍或者数十倍) 的场景而言,实时的动态伸缩容很是必要,而因为通过 client 端实例化的 Memcached 资源节点相对比较固定,因此要进行伸缩容需要:

    1. 进行一次代码的线上变更,进行节点配置的变更,而如果依赖该某组资源的应用系统比较多,比如底层的认证资源,那么需要对多个业务系统变更,这一动静不可谓不小,特别是遇到紧急情况,这个会导致操作的执行很缓慢。
    2. 需要解决读写导致的一致性问题,假如有一些业务系统在读取 Cache,有一些业务系统在写入 Cache,而正常的变更是比较难让这些系统在某一刻全部执行节点的配置切换。
    3. 需要使用新的节点替换老的节点 (比如更换物理机),面临和上面类似的问题。
  • 过多资源带来的运维问题

Cache 资源组是按业务去申请,当业务特别多的时候,Cache 资源组也会很多,这个时候要对这些资源进行运维管理如调整,将会变得不容易。而且随着时间的演进,一些比较古老的资源年老失修的情况,要进行运维调整就更为不容易。

  • Cache 架构要用得好的复杂度

会用和用得好是两个不同概念。如果 Cache 架构需要每个业务开发很熟练才能够用得好,而不会因为 Cache 的不当使用而导致线上服务出现稳定性问题、以及成本的浪费等各种问题的话,这种对于需要陆续补进新人的团队现状而言,出问题将会是一种常态。 因此要解决这种问题,那么需要提供一种足够简单的 Cache 使用方式给业务应用方,简单到只有 set/get/delete 等基本命令的操作,而无需要他们关心底层的任何细节。

分布式 CacheService 架构

为了解决这些问题,微博的 Cache 服务架构进行了演进,通过把 Cache 服务化,提供一个分布式的 CacheService 架构,简化业务开发方的使用,实现系统的动态伸缩容、容灾、多层 Cache 等相关功能。

CacheService 架构示意图如下:

系统由几个模块组成:

  • ConfigService

    这一模块是基于现有微博的配置服务中心,它主要是管理静态配置和动态命名服务的一个远程服务,能够在配置发生变更的时候实时通知监听的 config client。

  • proxy 层

    这一模块是作为独立的应用对外提供代理服务,用来接收来自业务端的请求,并基于路由规则转发到后端的 Cache 资源,它本身是无状态的节点。它包含了如下部分:

    • 异步事件处理 (event handler): 用来管理连接、接收数据请求、回写响应。
    • Processor: 用来对请求的数据进行解析和处理。
    • Adapter:用来对底层协议进行适配,比如支持 MC 协议,Redis 协议。
    • Router: 用来对请求进行路由分发,分发到对应的 Cache 资源池,进而隔离不同业务。
    • LRU Cache: 用来优化性能,缓解因为经过 proxy 多一跳 (网络请求) 而带来的性能弱化。
    • Timer: 用来执行一些后端的任务,包含对底层 Cache 资源健康状态的探测等。

    Proxy 启动后会去从 config Service 加载后端 Cache 资源的配置列表进行初始化,并接收 configService 的配置变更的实时通知。

  • Cache 资源池

    这一模块是作为实际数据缓存的模块,通过多层结构来满足服务的高可用。 其中 Main-node 是主缓存节点,Ha-Node 是备份节点,当 Main-node 挂掉后,数据还能够从 Ha-Node 节点获取避免穿透到后端资源,L1-node 主要用来抗住热点的访问,它的容量一般比 Main-node 要小,其中 L1-node 可支持多组,方便进行水平扩容以支撑更高的吞吐。

  • Client 客户端

    这一模块主要是提供给业务开发方使用的 client(sdk 包),对外屏蔽掉了所有细节,只提供了最简单的 get/set/delete 等协议接口,从而简化了业务开发方的使用。

    应用启动时,Client 基于 namespace 从 configService 中获取相应的 proxy 节点列表,并建立与后端 proxy 的连接。正常一个协议处理,比如 set 命令,client 会基于负载均衡策略挑选当前最小负载的 proxy 节点,发起 set 请求,并接收 proxy 的响应返回给业务调用端。

    Client 会识别 configService 推送的 proxy 节点变更的情况重建 proxy 连接列表,同时 client 端也会做一些容灾,在 proxy 节点出现问题的时候,把 proxy 进行摘除,并定期探测是否恢复。

目前微博平台部分业务子系统的 Cache 服务已经迁移到了 CacheService 之上,它在实际的运行过程中也取得了良好的性能表现,目前整个集群在线上每天支撑着超过 300W 的 QPS,平均响应耗时低于 1ms。

它本身具备了以下特性:

  • 高可用保证

    所有的数据写入请求,CacheService 会把数据双写到 ha 的节点,这样,在 main-node 挂掉的时候,会从 ha-node 读取数据,从而防止节点 fail 的时候给后端资源 (DB 等) 带来过大的压力。

  • 服务的水平扩展

    CacheService proxy 节点本身是无状态的,在 proxy 集群存在性能问题的时候,能够简单的通过增减节点来伸缩容。而对于后端的 Cache 资源,通过增减 L1 层的 Cache 资源组,来分摊对于 main-node 的请求压力。这样多数热点数据的请求都会落 L1 层,而 L1 层可以方便的通过增减 Cache 资源组来进行伸缩容。

  • 实时的运维变更

    通过整合内部的 config Service 系统,能够在秒级别做到资源的扩容、节点的替换等相关的运维变更。

  • 跨机房特性:

    微博系统会进行多机房部署,跨机房的服务器网络时延和丢包率要远高于同机房,比如微博广州机房到北京机房需要 40ms 以上的时延。CacheService 进行了跨机房部署,对于 Cache 的查询请求会采用就近访问的原则,对于 Cache 的更新请求支持多机房的同步更新。

目前微博的分布式 CacheService 架构在简化了业务开发使用的同时,提高了系统的可运维性和可用性。接下来的架构的改造方向是提供后端 Cache 资源的低成本解决方案,从单机的存储容量和单机的极限性能层面不断优化。因为对于微博的业务场景,冷热数据相对比较明显,同时长尾数据请求的比例也不小,因而如果减少了 Cache 的容量,那么会导致后端资源无法抗住请求,而扩大 Cache 的容量,又会导致成本的浪费。而全内存的解决方案相比而言成本相对比较高,所以热数据存放到内存,基于 LRU 的策略把冷数据交换到固体硬盘 (SSD),这是一种可能选择的方向。

感谢崔康对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014 年 4 月 18 日 21:278476

评论

发布
暂无评论
发现更多内容

京东Java高开岗三面算法+数据库+设计模式,复习1个月成功拿offer

互联网架构师小马

数据库 面试 算法 设计模式 Java 分布式

架构师训练营第二周命题作业

hifly

设计模式 极客大学架构师训练营 UML 依赖倒置原则 接口隔离原则

设计原则

GalaxyCreater

架构

【漫画】云通信企业公众号,打造私域流量的利器

巨侠说

云通信

作业

chenzt

架构师训练营第二周命题作业

兔狲

作业

编程的本质

GalaxyCreater

架构

软件的本质与设计原则

dony.zhang

第二周作业

极客大学架构师训练营

DIP和SIP的理解和学习

拈香(曾德政)

极客大学架构师训练营 面向对象设计原则 DIP 设计原则 SIP

学习总结 -- Week2

吴炳华

极客大学架构师训练营

7-ELEVEn工作法

wujunmin

管理 零售

设计一个软件框架的关键点

dony.zhang

视频豪横时代,应用如何快速构建视频点播能力?

巨侠说

音视频 CDN 直播 点播

架构师0期week2-作业

小高

架构师训练营第二周总结

时来运转

架构师训练营2 ——框架设计

默默

0期架构Week2作业1

Nan Jiang

架构师训练营第二周学习总结

whiter

极客大学架构师训练营

架构师训练营第二周作业

时来运转

透过本质和发展看编程

拈香(曾德政)

架构师 面向对象设计 极客大学架构师训练营 面向对象设计原则

第 02 周学习总结

夏秋

银行业数据治理之「数据资产管理」

数据司令

大数据 数据仓库 金融科技 数据治理 数据资产

第 02 周作业

夏秋

极客大学架构师训练营

豆瓣9.0,35万读者“搜不到信息”的神秘作者,我们帮你找到了

华章IT

JVM 虚拟机 深入理解JVM Java 25 周年 周志明

架构师 0 期 | 架构师怎样实现架构目标?

刁架构

设计模式 极客大学架构师训练营

你不会还不懂依赖倒置吧?赶紧来看看

hellohuan

设计模式 极客大学架构师训练营 设计原则

江帅帅:精通 Spring Boot 系列 05

奈学教育

Spring Boot

【架构师第二周作业】依赖倒置

浪浪

江帅帅:精通 Spring Boot 系列 05

古月木易

Spring Boot

设计原则——依赖倒置原则

GalaxyCreater

架构

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

微博CacheService架构浅析-InfoQ