摘要: 背景 6月14日晚,2018年俄罗斯世界杯在莫斯科开幕。国内数以千万的观众经过优酷、央视影音或者是咪咕视频观看了这次开幕赛。阿里云公布的一份数据显示,第一波流量洪峰出如今揭幕战开场后的第44分钟,峰值达到了1.5个2018年春晚的规模。html
背景
6月14日晚,2018年俄罗斯世界杯在莫斯科开幕。国内数以千万的观众经过优酷、央视影音或者是咪咕视频观看了这次开幕赛。redis
阿里云公布的一份数据显示,第一波流量洪峰出如今揭幕战开场后的第44分钟,峰值达到了1.5个2018年春晚的规模。自此,本届世界杯也成为了史上最大规模的一次在线直播。比赛期间,预计全网70%的世界杯直播流量都跑在了阿里云上。(注:上述内容引用自:https://www.leiphone.com/news...,所属权归原做者全部。)数据库
细心的网友们确定已经注意到了,今年的世界杯与以往的世界杯相比,不只比赛结果出人意料,并且观看比赛的APP客户端中也增长了丰富的互动和红包惊喜,众平台为了引流和激活“僵尸”用户也是使出了浑身解数。下面一块儿来盘点一下精彩世界杯背后你看得见的Redis身影吧!主要从业务架构、应用场景、高可用建设以及弹性扩缩容等几个方面进行展开。json
业务架构浏览器
(图来源自网络)
上图是某企业直播解决方案,主要使用了弹性计算、CDN、智能动态编码技术、视频AI、窄带高清2.0、Redis等等产品技术,充分保证了超清画质体验的同时,节省了带宽的消耗,并最大限度优化资源和成本,给观众带来流畅和丰富多彩的互动体验,极大的知足了用户的参与感。固然,本文重点不是谈论视频如何从录制到播出的,而是要探讨一下“数据库服务器”中Redis在丰富观看直播体验中发挥的重要做用和使用场景及实现。缓存
应用场景
Redis之因此可以被普遍的应用于企业的架构中,并且是不可或缺的重要组成部分,也能够说是标配,其中很重要的一点就是得益于它具备丰富的数据结构,这也是它逐渐替代Memcached,备受青睐的重要缘由。它的数据结构有:String、List、Hash、set、Sorted set、bitmap、bit field、hyperLogLog、Geospatial Index等。服务器
正是由于有了这些数据结构和Redis技术的不断完善和发展,才被普遍应用于各行各业中,应用场景也是百花齐放。好比:会话缓存(Session cache)、全页缓存(FPC)、手机验证码、访问频率限制/黑白名单、消息队列、发布与订阅、消息通知、排名/排行榜/最新列表、计数器(好比微博的转评赞计数、阅读数(浏览数,视频播放计数)、博文数(发帖数)、粉丝数、关注数(喜欢商品数)、未读数(动态数))、共同好友/喜爱/标签、推送、下拉刷新、私信、商品库存管理(限时的优惠活动信息)、证券指标实时计算,发号器/UUID、以及随着LBS(基于位置服务)的发展,加入的GEO(地理信息定位)的功能和基于Lua自定义命令或功能等等。你们在使用过程当中,须要结合本身的业务场景,选择正确的数据类型。那么下面以“优酷APP”为例,来看看有哪些看得见的场景用到了Redis技术。网络
聊天列表(评论列表)数据结构
这种评论列表能够用Hash来实现,好比:{userID:contents}架构
用户ID 评论内容
11101000 破产了
关于评论,你有没有想过一个问题,“垃圾评论” 怎么在评论列表里看不到?没有用户一直在刷评论的?是的,这个确定是spam系统在默默工做的,这个Redis也是能够作到的,更多策略/机制须要结合drools配合完成。固然一般都是有专门的spam的系统来实现。举个例子,好比要限制某个用户一分钟内的评论次数:
Method1: 用sorted set实现。将最近一天用户评论操做记录起来, score用timestamp替代得分,而后经过Zset的命令RANGEBYSCORE、ZADD、ZRANGEBYSCORE结合实现
RANGEBYSCORE userID:10000:operation:comment 61307510405600 +inf //得到1分钟内的操做记录
redis> ZADD userID:10000:operation:comment 61307510402300 "这是一条评论" //score 为timestamp (integer) 1
redis> ZRANGEBYSCORE userID:10000:operation:comment 61307510405600 +inf //得到1分钟内的操做记录
Method2: 用Redis+Lua实现访问频率控制
local key1 ,key2 = 'access:limit' ,'access:expire'
if redis.call('EXISTS' ,key2) > 0 then
return redis.call('DECR' ,key1) ;
else
redis.call('SET' ,key2 ,1)
redis.call('EXPIRE' ,key2 ,60)
redis.call('SET' ,key1 ,KEYS[1])
return KEYS[1]
end
赛况(赛事列表)
最新活动列表,能够用Redis的List数据结构或者sorted set数据结构实现,加上过时时间轻松搞定。一样的方法,也能轻松的实现最新商品列表、各类排行榜等。
消息(未读消息数)
实现思路是:使用hash存储用户上次看过的时间,使用sorted set存储每一个模块(评论区、群聊)的每一个信息产生的时间,并记录未读消息的数量,实现能够参考:https://yq.aliyun.com/ziliao/...
点赞(点赞数)
点赞数,实现相对比较简单了,用string数据结构或者Hash数据结构都能实现,这种点赞没有取消的操做,直接Incr便可。假设key为场次编号:active16
string:
INCR active16
GET active16
Hash:
HSET active:active16 zan 0
HINCRBY active:active16 zan 1
HGETALL active:active16
红包雨(传送门、红包雨)、商品库存/红包金额管理
下面介绍一种基于Redis的抢红包方案。
把原始的红包称为大红包,拆分后的红包称为小红包。
一、小红包预先生成,插到数据库里,红包对应的用户ID是null。
二、每一个大红包对应两个Redis队列,一个是未消费红包队列,另外一个是已消费红包队列。开始时,把未抢的小红包全放到未消费红包队列里。
未消费红包队列里是json字符串,activeID是活动场次,money是红包金额,product是商品个数。如{activeId:'16', money:'300'} 或 {activeID:'16',product:'50'}
三、在Redis中用一个map来过滤已抢到红包的用户。
四、抢红包时,先判断用户是否抢过红包,若是没有,则从未消费红包队列中取出一个小红包,再push到另外一个已消费队列中,最后把用户ID放入去重的map中。
五、用一个单线程批量把已消费队列里的红包取出来,再批量update红包的用户ID到数据库里。
上面的流程是很清楚的,可是在第4步时,若是是用户快速点了两次,或者开了两个浏览器来抢红包,会不会有可能用户抢到了两个红包?
为了解决这个问题,采用了lua脚本方式,让第4步整个过程是原子性地执行。
下面是在Redis上执行的Lua脚本:
-- 函数:尝试得到红包,若是成功,则返回json字符串,若是不成功,则返回空
-- 参数:红包队列名, 已消费的队列名,去重的Map名,用户ID
-- 返回值:nil 或者 json字符串,包含用户ID:userId,红包ID:id,红包金额:money
-- 若是用户已抢过红包,则返回nil
if redis.call('hexists', KEYS[3], KEYS[4]) ~= 0 then
return nil
else
-- 先取出一个小红包
local hongBao = redis.call('rpop', KEYS[1]);
if hongBao then
local x = cjson.decode(hongBao);
-- 加入用户ID信息
x['userId'] = KEYS[4];
local re = cjson.encode(x);
-- 把用户ID放到去重的set里
redis.call('hset', KEYS[3], KEYS[4], KEYS[4]);
-- 把红包放到已消费队列里
redis.call('lpush', KEYS[2], re);
return re;
end
end
return nil
参考:https://blog.csdn.net/hengyun...
消息推送
上图中的这种弹出消息,未必是Redis实现或者说确定不是,哈哈。可是这里想提示的是消息提醒,Redis是能够实现的。
这种用pub/sub机制来实现的消息通知,没有持久化机制,属于即发即弃模式。生产者不须要关心有多少的订阅者,也不用关心订阅者的具体信息,在线的客户端(消费者)正常状况下是都看到的,正如咱们关注的某个节目同样,在线的时候总能关注的节目更新通知同样。
高可用建设和弹性扩展
面对世界杯这种全球性的全民赛事,尤为是在你们都比较关注的明星或球队对抗的时候(朋友圈都被刷屏的那种),那压力可想而知,虽然拿不到具体的数据,可是从我在微博时保障的热点事件来看,也能猜着个大概。它跟微博热点有不少的类似点,具备不可预见性和突发性,而且伴随着极短期内流量的数倍增加,甚至更多,有时持续时间较长。如何快速应对突发流量的冲击,确保线上服务的稳定性,是一个很是巨大的挑战和有意义的事情。为了达到这一目标,首先须要有一个完善的,稳定可靠的,健壮的数据库运维体系来提供支撑和管理。
正如前面一开始提到的,优酷、央视影音、咪咕视频等视频平台,为了保障业务稳定、减小成本(不可能为了短短一个月的赛事准备4年才用到一次的基础设施),选择和公有云结合是最佳选择,这也是阿里云之因此有流量洪峰出现的重要缘由。那么对于Redis来讲如何去建设高可用服务以及解决弹性扩展问题?主要有两点:
高可用:异地灾备和多活能力
“不要把鸡蛋放到同一个篮子里”,相信不少架构师也确定会这么去想,也确定是这么作的。能够本身搭建一套高可用架构,也能够直接采用阿里云Redis服务提供的异地灾备和多活能力和, 实例部署在跨region,自动双向同步。(参考资料:https://help.aliyun.com/docum...)
经过异地灾备和多活的能力,一旦发生故障,还能够经过异地快速接管业务,确保使用体验。另外,不少分布较广的业务,用户须要跨地域远距离访问服务。若是此时访问延迟大,将直接影响用户体验。云数据库Redis提供的云上多活,还能够帮助用户消除跨地域远距离访问时的延迟大问题。
弹性:资源伸缩、读写分离
一个区域出现访问异常后,仍然能经过一些手段,好比降级、切流量、限流等一系列措施来保障服务的稳定性。在云模式下,当业务量上来了,扛不住的时候,能够经过阿里云Redis服务自动具有弹性扩缩容一劳永逸,还能够精打细算使用读写分离功能小成本卸载读压力或者经过混合存储卸载存储成本等等。(参考资料:https://help.aliyun.com/docum...)
总之,Redis是一个很是重要的组件,它可以被普遍的应用于企业的架构中,并且是不可或缺的重要组成部分。
若是以前没有了解过,那么,“Redis,请了解一下”!不足之处,欢迎批评指正。
做者简介:
张冬洪:阿里云MVP,极数云舟对外合做部总监、技术专家,Redis中国用户组主席,中国MySQL用户组主席团成员
点击如下连接报名
https://yq.aliyun.com/event/2...
原文连接本文为云栖社区原创内容,未经容许不得转载