外行看熱鬧,內行看門道,盤點精彩世界盃背後你看得見的Redis身影

摘要: 背景 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實現訪問頻率控制

KEYS[1]表示限制次數,由調用程序傳入

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...

原文連接本文爲雲棲社區原創內容,未經容許不得轉載

相關文章
相關標籤/搜索