加入收藏 | 设为首页 | 会员中心 | 我要投稿 辽源站长网 (https://www.0437zz.com/)- 云专线、云连接、智能数据、边缘计算、数据安全!
当前位置: 首页 > 服务器 > 安全 > 正文

从优化性能到应对峰值流量:微博缓存服务化的设计与实践

发布时间:2021-01-08 20:36:23 所属栏目:安全 来源:网络整理
导读:《从优化性能到应对峰值流量:微博缓存服务化的设计与实践》要点: 本文介绍了从优化性能到应对峰值流量:微博缓存服务化的设计与实践,希望对您有用。如果有疑问,可以联系我们。 导读: 高可用架构 8 月 20 日在深圳举办了『互联网架构:从 1 到 100』为主
副标题[/!--empirenews.page--]

《从优化性能到应对峰值流量:微博缓存服务化的设计与实践》要点:
本文介绍了从优化性能到应对峰值流量:微博缓存服务化的设计与实践,希望对您有用。如果有疑问,可以联系我们。

导读:高可用架构 8 月 20 日在深圳举办了『互联网架构:从 1 到 100』为主题的闭门私董会研讨及技术沙龙,本文是陈波分享的微博缓存服务的演进历程.

陈波,08 年加入新浪,参与 IM 系统的后端研发.09 年之后从事新浪微博的系统研发及架构工作,在海量数据存储、峰值访问、规模化缓存服务及开放平台等方面参与技术架构改进,当前主要负责微博平台的基础设施、中间件的研发及架构优化工作,经历新浪微博从起步到成为数亿用户的大型互联网系统的技术演进过程.

在所有介绍微博架构演进的使用场景都离不开缓存,今天上午腾讯分享的 CKV 也同样提到了缓存服务在腾讯社交产品的重要性.缓存的设计为什么重要,我们先介绍其使用场景.

1、微博的缓存业务场景

微博几乎所有的接口都是实时组装的,用户请求最终转化到资源后端可能会存在 1 – 2 个数量级的读放大,即一个用户请求可能需要获取几十上百个以上的资源数据进行动态组装.

比如大家刷微博的时候,会触发一个 friends_timeline 的接口请求,然后服务端会聚合并组装最新若干条(比如 15 条)微博给用户,那这个过程后端服务需要到资源层拿哪些数据来组装?

  • 首先是后端服务会从资源层去获取用户的关注列表;

  • 然后根据关注列表获取每一个被关注者的最新微博 ID 列表 以及 用户自己收到的微博 ID 列表(即 inbox);

  • 通过对这些 ID 列表进行聚合、排序和分页等处理后,拿到需要展现的微博 ID 列表;

  • 再根据这些 ID 获取对应的微博内容;

  • 如果是转发微博还要获取源微博的内容;

  • 然后需要获取用户设置的过滤词并进行过滤.

  • 此后还需要获取微博作者、包括源微博作者的 user 信息进行组装;

  • 还需要获取这个用户对这些微博是不是有收藏、是否赞,

  • 最后还需要获取这些微博的转发、评论、赞的计数等进行组装.

从以上过程可以看到,用户的一个首页请求,最终后端 server 可能需要从资源层获取几百甚至几千个数据进行组装才能得到返回的数据.

微博线上业务的很多核心接口响应需要在毫秒级,可用性要求达到 4 个 9.因此,为了保证资源数据的获取性能和可用性,微博内部大量使用缓存,而且对缓存是重度依赖的,不少核心业务的单端口缓存访问 QPS 已经达到了百万级以上.

微博使用的缓存主要是 Memcache 和 Redis,因为 Memcache 的使用场景、容量更大,而且目前推的缓存服务化也是优先基于 Memcache,然后再扩展到 Redis、 ssdcache 等其他缓存,所以今天的缓存服务讨论也是以 Memcache 为存储标的来展开的.我们最早使用的缓存架构就是直接利用开源版本的 Memcache 运行在物理机上,我们称之为裸资源.

2、缓存的裸资源架构演进

首先看一下微博 Memcache 缓存的裸资源架构的演进过程.微博上线之初,我们就对核心业务数据进行分池、分端口的,把 size 接近的数据放在相同的池子里面.业务方通过 Hash 算法访问缓存池里的节点.同时,每个 IDC 部署使用独立的缓存资源,为了加速,业务前端也会在本地启用 local-Cache.

上线几个月之后,随着业务量和用户量的急聚增加,缓存节点数很快增加到数百个.这段时间,时常会因为网络异常、机器故障等,导致一些缓存节点不可用,从而导致缓存 miss.这些 miss 的请求最终会穿透到 DB 中.

如果某个时间点,核心业务的多个缓存节点不可用,大量请求穿透会给 DB 带来巨大的压力,极端情况会导致雪崩场景.于是我们引入 Main-HA 双层架构.

对后端的缓存访问时,会先访问 Main 层,如果 miss 继续访问 HA 层,从而在获得更高的命中率的同时,即便部分 Main 节点不可用,也可以保证缓存的命中率,并减少 DB 压力.

这一阶段我们对业务资源进一步的分拆,每一种核心数据都分拆到独立的端口.同时,根据不同的访问频率、容量进行缓存搭配部署,对 Memcache 资源的端口进行统一规划,确保缓存层的性能和可用性.同时我们发现,在各种海量业务数据的冲刷下,前端使用 local-Cache,命中率不高,性能提升不明显,所以我们把 local Cache 层去掉了.

随着业务访问量进一步增加,特别是一些突发事件爆发式的出现并传播,Main-HA 结构也出现了一些问题,主要是很多缓存节点的带宽被打满,Memcache 的 CPU 比较高,Memcache 响应变慢.

通过分析,我们发现主要是大量热数据的集中访问导致的服务过载,单个端口不能承载热数据的访问(比如明星发的微博所在的端口),于是我们引入了 L1 结构.

通过部署 3 – 4 组以上的小容量 L1 缓存,每个 L1 组等价存储热数据,来满足业务要求.

总结一下微博的缓存架构演进过程:

  1. 在直接使用裸缓存资源的过程中,我们通过 Main-HA 双层结构,消除了单点问题;

  2. 通过热数据的多 L1 副本,可以用较低的成本即可应对高峰、突发流量;

  3. L1s-M-H 三层缓存结构消除了缓存层出现的带宽和 CPU 过载的情况,使整个系统的读取性都、可用性得了很大的提高.

在以上 3 阶段的演进过程中,我们较好的解决了访问性能与访问峰值的压力,不过在服务的可管理性方面依然存在可管理空间.不同业务之间只有经验可以复用,在缓存的实现方面经常需要各种重复的劳动.我们需要把缓存的使用服务化才能把可管理性带到一个新的阶段.

3、缓存服务的设计与实践

直接使用裸缓存资源也存在一系列问题:

  1. 首先,随着业务的发展,微博缓存的访问量、容量都非常大.线上有数千个缓存节点,都需要在业务前端要去配置,导致缓存配置文件很大也很复杂.

  2. 同时,如果发生缓存节点扩容或切换,需要运维通知业务方,由业务方对配置做修改,然后进行业务重启,这个过程比较长,而且会影响服务的稳定性.

  3. 另外,微博平台主要采用 Java 语言开发,我们定制了 Java Memcache 缓存层来访问三层缓存结构,内置了不少访问策略.这时候,如果公司其他部门也想使用,但由于用的是其他开发语言如 PHP,就没法简单推广了.

  4. 最后,资源的可运维性也不足,基于 IP、端口运维复杂性比较高.比如一个线上机器宕机,在这个机器上部署了哪些端口、对应了哪些业务调用,没有简单直观的查询、管理入口.

于是我们开始考虑缓存的服务化,主要的过程及策略如下:

  1. 首先是对 Memcache 缓存引入了一个 proxy 层,基于 Twitter 的 twemproxy 进行改造.

  2. 引入 cluster,并内嵌了 Memcache Cluster 访问策略,包括三层的一些更新、读取,以及 miss 后的穿透、回写等.

  3. 我们通过单进程单端口来对多个业务进行访问,不同业务通过 namespace Prefix 进行区分.

  4. 在 Cache-proxy 也引入了 LRU,在某些业务场景减少热点数据的穿透.

通过 cacheProxy,简化了业务前端的配置,简化了开发,业务方只需要知道 cacheProxy 的 IP 和端口,即可实现对后端各种业务的多层缓存进行访问.

我们对缓存服务的服务治理也做了不少工作.

接入配置中心

首先,把 Cache 层接入了配置中心 configServer(内部叫 vintage).实现了 Memcache 缓存、 cacheProxy 的动态注册和订阅,运维把 Memcache 资源的 IP 端口、 Memcache 访问的 hash 方式、分布式策略等也以配置的形式注册在配置中心,cacheProxy 启动后通过到配置中心订阅这些资源 IP 及访问方式,从而正确连接并访问后端 Memcache 缓存资源.而且 cacheProxy 在启动后,也动态的注册到配置中心,client 端即可到配置中心订阅这些 cacheProxy 列表,然后选择最佳的 cacheProxy 节点访问 Memcache 资源.同时,运维也可以在线管理 Memcache 资源,在网络中断、 Memcache 宕机,或业务需要进行扩容时,运维启动新的 Memcache 节点,同时通知配置中心修改资源配置,就可以使新资源快速生效,实现缓存资源管理的 API 化、脚本化.

监控体系

其次,把 cacheProxy、后端 Memcache 资源也纳入到了 Graphite 体系,通过 logtailer 工具将缓存的访问日志、内部状态推送到 Graphite 系统,用 dashboard 直接展现或者按需聚合后展现.

Web 化管理

同时,我们也开发了缓存层管理组件 clusterManager(内部也叫 captain),把之前的 API 化、脚本化管理进一步的升级为界面化管理.运维可以通过 clusterManager,界面化管理缓存的整个生命周期,包括业务缓存的申请、审核,缓存资源的变更、扩缩容、上下线等.

监控与告警

ClusterManager 同时对缓存资源、 cacheProxy 等进行状态探测及聚合分析,监控缓存资源的 SLA,必要时进行监控报警.

我们也准备将 clusterManager 整合公司内部的 jpool(编排发布系统)、 DSP(混合云管理平台) 等系统,实现了对 cacheProxy、 Memcache 节点的一键部署和升级.

开发工具

对于 client 端,我们基于 Motan(微博已开源的 RPC 框架)扩展了 Memcache 协议,使 client 的配置、获取服务列表、访问策略更加简洁.方便开发者实现面向服务编程,比如开发者在和运维确定好缓存的 SLA 之后,通过 spring 配置 <weibo:cs namespace=“ unread-feed” registry=”vintage” />,即可访问 unread-feed 业务对应的 Memcache 资源,后续的扩容、节点切换等都不需要开发者介入,也不需要重启.

部署方式

对于 cacheProxy 的部署,目前有两种方式,一种是本地化部署,就是跟业务前端部署在一起的,在对 cacheProxy 构建 Docker 镜像后,然后利用 jpool 管理系统进行动态部署.另外一种是集中化部署,即 cacheProxy 在独立的机器上部署,由相同的业务数据获取方进行共享访问.

Cache 服务化后的业务处理流程如图.

首先运维通过 captain 把 Memcache 资源的相关配置注册到 configServer,cacheProxy 启动后通过 configServer 获取 Memcache 资源配置并预建连接; cacheProxy 在启动准备完毕后将自己也注册到 configServer,业务方 client 通过到 configServer 获取 cacheProxy 列表,并选择最佳的 cacheProxy 发送请求指令,cacheProxy 收到请求后,根据 namespace 选择缓存的 cluster,并按照配置中的 hash 及分布策略进行请求的路由、穿透、回写. Captain 同时主动探测 cacheProxy、 Memcache 缓存资源,同时到 Graphite 获取历史数据进行展现和分析,发现异常后进行报警.

(编辑:辽源站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读