写点什么

新浪微博中的周期性爆发流量

2015 年 2 月 06 日

【编者按】《博文共赏》是 InfoQ 中文站新推出的一个专栏,精选来自国内外技术社区和个人博客上的技术文章,让更多的读者朋友受益,本栏目转载的内容都经过原作者授权。文章推荐可以发送邮件到 editors@cn.infoq.com

业务背景

最近,微博平台的群发业务增长迅速,一个月内业务量暴涨 70%,出现两次负载过高报警,通过紧急扩容解决。仔细思索,这一类业务场景在移动互联网中非常普遍,值得深入探讨。

在微博通讯系统中,有两种常见的模式,一种是单点对单点的私信通讯方式,另一种是单点对多点的群发通讯方式,后面一种主要使用在粉丝服务平台。最近几年,通讯内容趋向于富媒体,包含图片、网络文章、音视频文件等,微博统一将各类资源抽象为卡片(Card),平台负责 Card 数据的存储与处理,前端和客户端根据不同的模板渲染 Card。

微博服务号基本都是每天早上向所有粉丝推送一条消息,这就是群发场景,同一时段高并发的请求访问给后端系统带来巨大压力。

问题挑战

对于群发业务,增加缓存能挡住大多数的流量,但这里还有诸多挑战:

  • 缓存大小规划,如果所有内容都缓存,成本直线上升,虽然可以抗住峰值时段流量,但是非峰值时端,资源严重浪费。
  • 缓存资源有状态,很多 Card 并非完全是静态资源,根据请求参数不同返回数据不同。
  • 同一资源集中访问间隔时间非常短,经常维持在几分钟内,还有一个特点,5% 的资源占据了 80% 以上的访问请求。

弹性计算 or CDN?

问题一:能否使用云服务中的弹性计算解决****?

如果业务爆发周期为一年中的某一季节或者某些节日,弹性计算可以较好地解决这个问题,如果业务爆发周期为一天中的某一时段,从运维管理层面来讲,弹性计算可实施性非常低。

问题二:能否使用CDN技术缓存Card资源?

Card 资源为后台动态生成,有些 Card 是无状态的,有些是有状态的,CDN 网络可以处理无状态的 Card 资源,对于有状态的,目前还没有成熟的 CDN 解决方案,同时 Card 资源的使用方式也与传统的 CDN 资源使用方式不太相同。

技术方案

针对这种每天粒度周期性爆发的业务模型,团队总结出三种技术方案。

方案一:针对业务的定制化方案

这种方案分析业务特点,提出解决方案,不具有通用性,目前平台的 Card 服务使用方包含各个端的 Feed 组以及通信系统,而周期性爆发流量,目前仅有通讯系统中的群发和群聊会产生,针对这种情况,Card Service 改进点:

  • 区分有状态和无状态的 Card 请求,有状态的不缓存。
  • 无状态的 Card 请求,结合业务特点,判断是否是群发以及群聊业务。
  • 对于群发和群聊业务,将 Card 资源缓存在分布式缓存中。

分布式缓存有一个问题,虽然可以按照服务号水平分区在不同的节点,克服缓存容量问题,但是不能处理瞬时的千万级流量高峰,这种情况需要在每台前端机上做本地缓存,大小受前端机内存大小限制,我们根据业务特点进一步做优化, 对于群发和群聊业务,使用 L1 本地缓存和 L2 分布式缓存。

  • L1 本地缓存处理服务号粉丝规模超过 20 万的,通过众多的前端处理机 L1 缓存抗峰值。
  • L2 分布式缓存处理粉丝规模较小的服务号,处理从 L1 缓存穿透过来的访问。

方案二:简单的数据挖掘策略

通用方案基于实时的流量统计分析,运用数据挖掘算法,统计出资源请求中最频繁的 K 个,同时本地缓存大小不能太大,计算性能要求也较高,方案二将高频资源请求检测模块放在前端机本地缓存,使用类蓄水池采样算法,适合微博的群发场景。

这里介绍一下蓄水池问题:在不知道文件总行数的情况下,如何从文件中随机的抽取一行?

首先想到的是我们做过类似的题目吗? 当然,在知道文件行数的情况下,我们可以很容易的用 C 运行库的 rand 函数随机的获得一个行数,从而随机的取出一行,但是,当前的情况是不知道行数,这样如何求呢?我们需要一个概念来帮助我们做出猜想,来使得对每一行取出的概率相等,也即随机。

有了这个概念,我们便有了这样一个解决方案:定义取出的行号为 choice,第一次直接以第一行作为取出行 choice ,而后第二次以二分之一概率决定是否用第二行替换 choice ,第三次以三分之一的概率决定是否以第三行替换 choice ……,以此类推。这种方法的巧妙之处在于成功构造出一种方式,使得最后可以证明对每一行的取出概率都相等。

微博业务场景中的问题为长度为 K 的蓄水池,当 Card 资源没有命中缓存时,资源以 K/N 的概率存储到缓存,其中 K 为蓄水池的长度,N 为时间片内的平均访问量。

方案三: 基于 Spark 集群的 Top K 资源请求

这是方案二的升级版,将高频资源请求检测模块从本地缓存迁移到 Spark 集群,通过其强大的数据处理能力,更精确更实时地统计 Top K 高频资源访问。

目前,工程领域已经涌现众多性能优越的 Top K 算法,有基于计数的 Sticky Sampling 算法,也有空间使用率很低的 Space Saving 算法(思路和蓄水池有一点像,都是概率替换),还有使用 Bloom Filter 数据结构的算法,这些算法作用于 Spark 集群,理论上效果比方案二更好,但是消耗的资源更多。

总之,文中的三种方案没有好坏之分,应该结合公司业务特点,选择最适合的。

本文首发于“微博平台架构”微信公众号,发布时有少量的文字润色和调整。

关于作者

卫向军 @卫向军 _ 微博),毕业于北京邮电大学,现任微博平台架构师,先后在微软、金山云、新浪微博从事技术研发工作,专注于系统架构设计、音视频通讯系统、分布式文件系统和数据挖掘等领域。


感谢臧秀涛对本文的审校。

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

2015 年 2 月 06 日 08:303939

评论

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

Apache Beam 大数据处理一站式分析

李孟

Java 大数据 数据中台 数据交换 Beam

当dubbo多注册中心碰上标签路由

小楼

dubbo

一次漫长的dubbo网关内存泄露排查经历

小楼

dubbo 内存泄露

C++数组可以为变量吗

程序喵大人

c++ 互联网 编程语言

格局不行,有机会也抓不住

池建强

创业 格局 MacTalk

Docker运行常用软件:MySQL,Redis,Nginx,RabbitMQ,Neuxs,Gitlab

读钓

MySQL nginx Docker gitlab

什么是物联网中台

老任物联网杂谈

物联网中台 IOT Platform 物联网平台

记一次spring注解@Value不生效的深度排查

小楼

spring Spring Boot dubbo

用jdk8的stream实现斐波那契数列

编号94530

jdk stream 斐波那契 fibonacci

广告与数据算法系列1.1.1: 什么是广告

黄崇远@数据虫巢

互联网 算法 广告

SpringBoot中如何优雅的使用多线程

读钓

Java spring Spring Boot

Sentinel在docker中获取CPU利用率的一个BUG

小楼

Java sentinel cpu

skywalking内存泄露排查

小楼

dubbo 内存泄露

身为程序员,怎么接私活赚外快?

爱看书的小代码

MySQL死锁与Spring事务

Dean

MySQL

centos7.6操作系统安装

桥哥技术之路

Linux

思维导图学《Linux性能优化实战》

Yano

Linux 后端

以为是青铜,没想到是王者的dubbo标签路由

小楼

dubbo

Linux系统优化

桥哥技术之路

Linux

在Kubernetes上运行SpringBoot应用

铁花盆

Docker Kubernetes Spring Boot

Ledge:这可能是距今最好的『DevOps + 研发效能』知识平台

Phodal

DevOps 敏捷开发 软件开发 研发效能

Django 中如何优雅的记录日志

AlwaysBeta

Python django Web 后端

MacOS配置网络命令

编程随想曲

macos network

项目实施要避免哪些坑?

顾强

项目管理

要不要重新认识一下递归与迭代?

西了意

编程

零基础应该如何学习爬虫技术?

极客时间

Python 编程 爬虫

一个工程师向电信公司的维权

如何在非 sudo 用户下运行 docker 命令?

愚一

Docker DevOps

nacos的一致性协议distro介绍

小楼

nacos

LeetCode 前1000题二叉树题目系统总结

Yano

面试 算法 LeetCode 二叉树 刷题

IPFS 星际传输协议的入门(二)

AIbot

区块链 分布式数据库

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

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

新浪微博中的周期性爆发流量-InfoQ