自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

萬億級日訪問量下,Redis在微博的9年優(yōu)化歷程

數(shù)據(jù)庫 MySQL Redis
Redis在微博內(nèi)部分布在各個應用場景,比如像現(xiàn)在春晚必爭的“紅包飛”活動,還有像粉絲數(shù)、用戶數(shù)、閱讀數(shù)、轉評贊、評論蓋樓、廣告推薦、負反饋、音樂榜單等等都有用到Redis。

一、Redis在微博的應用場景

Redis在微博內(nèi)部分布在各個應用場景,比如像現(xiàn)在春晚必爭的“紅包飛”活動,還有像粉絲數(shù)、用戶數(shù)、閱讀數(shù)、轉評贊、評論蓋樓、廣告推薦、負反饋、音樂榜單等等都有用到Redis。

1、業(yè)務&規(guī)模&挑戰(zhàn)  

 

線上的業(yè)務有前面提到的信息流、廣告、用戶關系等等,還有現(xiàn)在大家可能比較感興趣的熱搜,用戶一般會去看發(fā)生了什么事情,還有引爆閱讀量的話題,以及現(xiàn)在兵家必爭之地的視頻,微博大大小小的業(yè)務都有用到Redis。

線上規(guī)模方面,微博有100T+存儲,1000+臺物理機,10000+Redis實例。

關于面臨的挑戰(zhàn),我們每天有萬億級的讀寫,線上的響應時間要求也比較高。

舉一個簡單的例子,我們部署資源是跨機房部署,但是有一些業(yè)務部門連跨機房部署存在的多余兩毫秒的延遲都要投訴反饋(真的是臣妾做不到啊,如果單機房故障了呢?有些業(yè)務方真是異想天開)。響應時間基本上四個9是20毫秒。

成本的話因為我們線上有大量需求是上T的,所以成本壓力其實也特別大。

2、技術選型

 

上圖是微博數(shù)據(jù)庫的技術選型,其實可以看到這里面不僅僅包含Redis等NoSQL,還有隊列、存儲,如果以后有機會的話可以給大家分享一下從0到1搭建微博的數(shù)據(jù)庫,在內(nèi)部分享的時候大概花了2-3個小時,時間有限,這次就只講Redis這一部分。

3、優(yōu)化

從2010年開始,我們就基于官方的2.0版本引進Redis,到現(xiàn)在已經(jīng)有九個年頭了,我們主要做了以下這些方面的改進:

  • Redis編碼格式,在特殊場景下可以節(jié)省30%的空間;
  • 主從庫方面有獨立的復制線程;
  • 我們定制化一些數(shù)據(jù)結構,比如:LongSet 數(shù)據(jù)結構,它是一個“固定長度開放尋址的 Hash 數(shù)組”,減少Redis dict 很多額外的指針開銷;
  • 在主從復制方面,獨立復制線程 + 完全增量復制,這樣的話,如果網(wǎng)絡主從臨時斷了,只要從當前的pos點同步數(shù)據(jù)就行;
  • 在持久化方面,我們是全量的RDB加增量的AOF復制;
  • AOF寫入/ 刷盤,主線程—>BIO,避免了因為寫入導致的阻塞;
  • 落地時間,不可控—>cronsave可控;
  • 增加aofnumber,設置AOF數(shù)量,避免因為寫入過快,磁盤寫滿;
  • 高可用, Redis的HA我們并沒有用官方的或者社區(qū)開源的,用的是我們自己開發(fā)的一套Redis HA,保障在故障的情況下,能快速進行切換。

微博有大量的技術場景,比如轉評贊、閱讀數(shù)等,對于一些用戶來說,他們是很關心這些指標的。

如果我們用原生的Redis,會浪費大量的存儲空間,因為它的產(chǎn)品特別特殊,它的key是一個用戶的id,value是數(shù)字,我們自己內(nèi)部最早改了一版叫RedisCounter,它相當于只維持了一個哈希表,節(jié)省了大量的Redis內(nèi)存空間。

當然它有一個缺點就是當初是短平快地上線了,所以它只支持單個列和單個表,如果你要存轉發(fā),評論,贊3個計數(shù)的話需要部署三套資源,這樣一來大家訪問微博取這3個數(shù)的速度會變慢。

而且需要維護3套資源,為了應對這種場景,我們支持了多列和多表的方式,如果一個表寫滿了,可以繼續(xù)寫下一個表,寫到最后一個表時,我們可以把前面的表滾到盤里面,但是這個時候是不可讀的。

為了解決不可讀的問題,我們想了一個辦法,把表都放在磁盤里面,維護ddb的數(shù)據(jù)結構,在這樣的落地方式下,就可以把最近的熱數(shù)據(jù)放在內(nèi)存里面,把冷數(shù)據(jù)或者歷史數(shù)據(jù)放在磁盤里面。

之前統(tǒng)計了一下,在線上90%多的情況下,用戶只訪問幾個月的數(shù)據(jù),所以一些長尾數(shù)據(jù)可以靠從磁盤中讀取數(shù)據(jù)來解決,也不影響用戶體驗。

微博還有一些存在性判斷的行為,比如是否贊過、是否閱讀過,這些全量的數(shù)據(jù)特別大,如果用Redis的話對內(nèi)存成本花費特別大。

所以我們改造了一版服務,它是一個兼容Redis協(xié)議,基于BloomFilter,開發(fā)了一版phantom,高性能,單線程網(wǎng)絡處理機制,與Redis性能相當,低存儲空間,每條記錄占用1.2*N字節(jié)(1%的誤判率,每增加0.6*N字節(jié)誤判率下降為原來的1/10,N為單個槽位占用的bit數(shù))。

當然還有其他像我們最近用的隊列、MySQL等等其他類型的數(shù)據(jù)庫,這邊就不展開了。簡單做一下Redis第一階段優(yōu)化的小結:

  • 無阻塞落地
  • 增量復制 -> RDB+AOF
  • 在線熱升級
  • 關系graph定制
  • -內(nèi)存降為1/10
  • -性能相當
  • 計數(shù)定制化
  • -內(nèi)存降為1/4
  • -性能提升3-5倍
  • BloomFilter

但是我們做了這么多優(yōu)化還是跟不上業(yè)務的需求。

二、Redis在微博的優(yōu)化

首先需要明白為什么要優(yōu)化,我們一般從三個方面進行考慮:

首先是業(yè)務方。目前線上的業(yè)務方需要關心資源的分布、容量規(guī)劃等多方面,比如內(nèi)存是否滿了、磁盤是否滿了、如果用MySQL的話是否要提前分庫分表、QPS是否能扛住。

我們希望把這些問題對業(yè)務方屏蔽,他們只管用,而不用關心太多涉及到資源細節(jié)的方面。

第二是DBA。雖然現(xiàn)在微博已經(jīng)不是處于高速增長的狀態(tài)了,但實際上它也還是以一定的速度在增長,所以對DBA來說,需求還是特別多的。

加上我們部門是承接微博所有的數(shù)據(jù)庫的服務,有微博最多的服務器,因此對于我們來說,需求多,變更多,挑戰(zhàn)大。

從設計的角度,我們要考慮如何設計Redis更合理。

總結了一下有三個方面:

一是高性能,讀寫快、訪問快、響應時間快。

二是能夠支持大容量的需求。

三是可擴展,因為接觸的業(yè)務方比較多,就會發(fā)現(xiàn)一個問題,基本上沒有幾個業(yè)務方能把自己的需求描述得特別清楚,經(jīng)常上線之后才發(fā)現(xiàn)內(nèi)存不夠了,或者寫入扛不住了,所以這個時候我們需要在可擴展性方面提供一個強有力的支持。

我們可以把這三個方面解釋為三座大山。

1、Cache Service服務化

為了解決三座大山,首先要把Cache服務化,它是一個多級緩存的服務,能夠解決高訪問、高并發(fā)的問題以及實現(xiàn)高可用。

基于這套系統(tǒng),也設計了一套后臺程序,根據(jù)微博的流量進行自動監(jiān)測、能夠支持自動擴縮容,這樣能快速扛過峰值,峰值過去之后又回收機器,實現(xiàn)了對資源的充分利用。

當然這套系統(tǒng)還在持續(xù)完善中,希望未來能做到更智能。

ConfigService就是我們把配置放在配置中心里面,Client再從配置中心里面拉取配置。

一共有兩種訪問方式,第一種是SDK,第二種是支持多語言的,通過Proxy把請求路由到后端的Cache里面。DBA只要通過管理平臺就可以對資源進行快速擴縮容。

 

現(xiàn)在講一下多級的Cache,實際上這里面有四個角色:master、maste-l1、slave、slave-l1。

master跟slave沒有同步關系,只是按角色作用的方式命名的,master-l1有多組數(shù)據(jù)來扛熱點,master是基準數(shù)據(jù)保存全量數(shù)據(jù),slave一般是做多機房的容災,slave-l1做多機房的數(shù)據(jù)同步,這個同步只保證最終數(shù)據(jù)的一致性。

 

以讀取作為例子來說一下流程,讀取是先訪問master-l1,如果沒有命中會訪問master,如果又沒有命中會訪問到slave,通過這3層,大部分情況下能把99%的熱點給扛住,然后還有1%的流量才會落到MySQL里面。

假如是100萬的讀,穿透到MySQL只有一萬QPS,如果100萬的讀全部都打到MySQL的話,對于MySQL而言成本特別高,而且大家知道,MySQL在高并發(fā)讀寫情況下,很容易被打死,且在短時間內(nèi)是恢復不了。

Cacheservice 目前支持mc和Redis協(xié)議2種協(xié)議。

 

上圖是我們DBA操作的擴縮容的界面,這個業(yè)務總共有20組,每組有5個IP,5×20=100個實例,實際上就是一百個實例在里面提供服務,線上有好多個單個集群服務,可以支撐百萬甚至千萬QPS的高并發(fā)訪問,而且可以支持快速的擴縮容。

分享一下我們之前的成功案例,我們已經(jīng)實現(xiàn)好幾年的春晚1000+臺阿里云ECS彈性擴縮容,多次實現(xiàn)無降級平滑過渡,高峰期支持微博50%的春晚核心流量。

 

上圖是我們內(nèi)部為了支持系統(tǒng)而進行的系統(tǒng)整合,在這邊就不展開了。

2、mcq服務化

基于前面的Cache服務化,我們在2018上半年跟業(yè)務方一起合作,把隊列也給服務化了。

為什么要把隊列單獨提出來呢?是因為經(jīng)常有內(nèi)部或外部的人問,你們發(fā)微博是什么樣的流程?你們發(fā)評論是什么樣的流程?數(shù)據(jù)怎么解決?

這些問題很關鍵的一環(huán)就是在隊列里面,發(fā)微博的時候實際上是先寫到隊列,然后隊列再寫到后端的MySQL里面,如果這個時候MySQL宕機了,我們會有一個修復隊列,專門有一個Key來存這部分的數(shù)據(jù),等MySQL恢復以后再把這部分數(shù)據(jù)寫入到MySQL里面。

 

上面還有一個BCP,是因為當初我們在做這一套的時候,實際上是想在整個微博推廣。

去年比特幣特別火,我們也想通過購買比特幣的方式,在內(nèi)部通過機器的資源或者內(nèi)部開源的一些東西來做等價物質(zhì)的轉換,然后來應用這個服務,但是最終這個計劃沒有具體落地。

 

上圖是一鍵告警以及操作的監(jiān)控圖。

前面提到我們把Cache服務化了,但是實際上并沒有很好地解決容量過大的問題,雖然現(xiàn)在內(nèi)存的價格一直在下降,但相對硬盤來說價格還是太高。

如果我們經(jīng)常有像5T或者10T的業(yè)務,并且全放內(nèi)存里面的話,對于我們成本的壓力實際上是特別大的。

而且我們需要向專門的成本委員會申領資源,只有成本委員會同意了我們才能拿到這些機器,整個周期時間長。

3、如何解決Redis容量過大?

為了解決容量過大的問題,我們想把容量從內(nèi)存放到磁盤里面。

我們當時考慮了一些特性,比如支持冷熱數(shù)據(jù)的分離,比如把歷史的數(shù)據(jù)或者全量的數(shù)據(jù)全部存在磁盤,然后支持持久化、支持數(shù)據(jù)主從復制、支持在線熱升級,需要兼容Redis數(shù)據(jù)類型,還要兼容與Redis的復制。

基于前面的場景,像微博這種屬性特別適合用這種方法,就算冷熱數(shù)據(jù)不明顯,比如上T,每秒幾K訪問的情況,用這個方法也特別合適。

 

下面講一下處理模塊,里面有主線程和后臺線程。

主線程主要處理連接的請求、協(xié)議的解析以及命令的請求,后臺線程主要是復制線程,還有像BIO線程,我們把像刷盤操作是寫AOF都是放在這個線程,這樣可以盡可能減少寫入所造成的對Redis的阻塞。

還有一個Bloom Filter,是基于布谷鳥算法來優(yōu)化,初始化的時候指定Filter的容量,新增雙向鏈表管理Hash沖突。

 

從這個名字大家可以猜到,是Redis+RocksDB的結合,為什么這個時候我們不像前面提到的類似設計CounterserviceSSD那樣自己設計,其實主要原因是當初我們在設計時RocksDB還沒有非常多大規(guī)模的應用。

現(xiàn)在RocksDB已經(jīng)特別成熟,而且有非常多成功的案例。我們還有一個不自己開發(fā)的原因,就是如果自己開發(fā)的話,可能適用性或者性能,以及代碼健壯性反而沒有那么好,所以為了節(jié)省時間我們采用了RocksDB來做存儲,避免重復造輪子。

LRU是為了加快訪問速度的,如果第一次訪問的時候沒有在內(nèi)存里面讀取到,就從磁盤里面讀取,它實際上會放在內(nèi)存,下次你再讀取的時候會從LRU里面讀取出來。

這邊還涉及到數(shù)據(jù)從內(nèi)存到磁盤換入換出,如果key或者value特別大的話,性能會有影響。這就是前面提到的為什么我們不推薦那種特別大的key或者value用RedRocks。

把前面的處理模塊和后端整合一下就形成了以下這樣的架構圖。

 

對其做一下小結:

簡單易用:完全兼容Redis,業(yè)務方不用做任何改動就可以遷移上;

成本優(yōu)勢:把熱點數(shù)據(jù)或者頻繁訪問數(shù)據(jù)放在內(nèi)存,全量的數(shù)據(jù)全部放磁盤,這是一個特別大的優(yōu)勢,可以突破內(nèi)存容量限制;

高性能:熱點數(shù)據(jù)在內(nèi)存,熱點數(shù)據(jù)訪問性能和Redis相當。

下圖是性能壓測報告,我們對比了set的隨機對寫。

 

4、仍滿足不了新需求?

我們前面已經(jīng)解決了大容量的問題,但還是有很多困難并沒有得到很好的解決。

因此,我們借鑒了開源經(jīng)驗,也調(diào)研了Twemproxy、Codis、Corvus、Redis-Cluser這些功能:

 

實際上我們在2015年就已經(jīng)存在基于Twemproxy的業(yè)務,在線上的話像微博音樂、微博健康、通行證這3個業(yè)務已經(jīng)上線。

但是我們沒有在內(nèi)部大范圍推廣開來,其中涉及到2個主要的原因,第一就是遷移還是比較費時間,第二是無法比較完美的動態(tài)增加節(jié)點,還有內(nèi)部一些其他原因等等的約束。

 

以上是我們的設計思路,一是能支持在線擴縮容,二是支持多語言的訪問,因為我們是要對整個公司進行推廣的,而不是說只對一個部門,所以為了推廣方便我們必須有這種功能,三是對服務化特性的需求。 

 

 

下面簡單講一下proxy里面各模塊的功能:

port自動增刪和監(jiān)聽:根據(jù)Vintage對本proxy節(jié)點的配置,自動增加監(jiān)聽的端口或者刪除移除的端口,監(jiān)聽客戶端的連接。

Redis協(xié)議解析:解析Redis協(xié)議,確定需要路由的請求,非法和不支持的請求直接返回錯誤。

路由:需要獲取和監(jiān)聽端口對應的backend以及它們的slot, 根據(jù)端口、key和Redis命令選擇一個backend, 將請求路由到對應的backend,并將結果返回給客戶端。

配置監(jiān)控:監(jiān)控Vintage中本proxy的配置,包括端口的變動、端口和backend的變動以及slot的變化等,通知端口監(jiān)聽模塊和路由模塊。

指標監(jiān)控:需要將Metrics發(fā)送到Graphite中進行監(jiān)控。

日志記錄:生成日志文件以便跟蹤。

 

Redis存儲方面:還是沿用我們內(nèi)部改造的Redis版本,相對之前線上的版本,這次我們新增了官方比如Mememory,內(nèi)存編碼的優(yōu)化,以及內(nèi)部新增的一些新的功能。

 

關于集群管理方面,無論是Redis也好,MySQL也好,對資源的任何管理都可以用這個來總結,包括五個部分:資源申請,資源分配,業(yè)務上線,資源查詢,資源變更。

對于業(yè)務申請這一方面需要有一個業(yè)務唯一的標識,QPS、數(shù)據(jù)類型是怎樣的,基于這些考察我們再對它進行分配、配置、部署。

基于前面我們做了那么多的優(yōu)化以及平臺服務化,用下圖作為總結比較合適,就相當于服務的高可用、高性能以及可擴展這些方面,我們基本上都用前面這一套方案解決了。

[[280437]] 

三、未來展望

無論是最開始的MySQL也好還是到后面的Oracle也好,這些都離不開SQL。如果我們能把數(shù)據(jù)一致性解決好的話,Redis的應用場景會更廣。

現(xiàn)在有很多公司對Raft做了二次開發(fā),后續(xù)我們也會投入到在這方面中。

 

借用兩句話結束今天的演講:“數(shù)據(jù)庫實際上是需要你用最快的速度把數(shù)據(jù)存儲下來,然后以最方便的方式把數(shù)據(jù)給回憶起來。”

謝謝大家!

Q & A

Q1:剛才您說您這邊有一個新的類型叫LongSet,能不能說一下它的應用場景?

A:應用場景是在關系判斷這個場景下,在微博關注Cache化改造中,需要把Redis當做Cache用存儲用戶的關注列表,原定方案是使用Hash結構。

但是由于Redis是做Cahce使用,key可能會被剔除,所以在判斷用戶是否關注某人的時候,可能不存在,這時就需要從數(shù)據(jù)庫拉用戶的關注列表直接HMSET到Hash結構中。

但是Redis在一次HSET多個field的時候,性能是比較低的,并且會堵塞其它的請求。

同時在仿真壓力測試過程中發(fā)現(xiàn),在Cache為空的情況下,必須要逐步放量填充Cache后,業(yè)務才能達到穩(wěn)定。

這種情況下,對運維的壓力比較大,容錯很低,違背了我們Cache化的初衷,所以才有了這一次的改造。

為了解決Redis Hash結構HMSET性能較低及內(nèi)存利用率較低的問題,對Redis進行了定制化改造,增加了一種新的數(shù)據(jù)結構LongSet,用來存儲元素為long類型的集合。

Q2:您剛剛解釋的是熱數(shù)據(jù)放在Redis,初始放在RocksDB,什么時候調(diào)用這個數(shù)據(jù)?什么時候調(diào)用那個數(shù)據(jù)?肯定是有一張表吧?

A:讀取流程是,先讀取內(nèi)存中的數(shù)據(jù),這個內(nèi)存大小是可以動態(tài)調(diào)整的,和官方的maxMemory參數(shù)是一致的,內(nèi)存中只保留一部分的數(shù)據(jù),如果內(nèi)存中的數(shù)據(jù)沒有讀取到,才會從磁盤里面讀取數(shù)據(jù)。

 

責任編輯:龐桂玉 來源: DBAplus社群
相關推薦

2018-05-21 09:15:06

Redis美團點評數(shù)據(jù)庫運維

2019-10-31 09:32:58

Redis微博緩存

2018-05-28 08:20:12

服務器Redis優(yōu)化

2020-06-15 21:08:42

機器Redis微博6

2018-06-05 09:31:01

微博緩存架構設計

2018-06-08 09:48:52

緩存架構設計

2017-04-01 09:04:54

docker自動化

2018-01-30 14:26:49

監(jiān)控應用性能管理運維管理

2022-07-17 06:54:51

Eureka架構

2009-01-12 10:39:55

Twitter訪問量SNS

2011-06-19 12:12:12

網(wǎng)站瀏覽量訪問量

2020-01-13 08:43:20

Elasticsear分布式搜索

2023-06-05 08:17:03

2019-12-06 15:20:58

Redis獨立用戶數(shù)據(jù)庫

2013-12-30 10:33:43

訪問量12306癱瘓

2018-05-06 16:33:52

微信朋友圈實踐

2012-05-08 14:26:05

交換機銳捷

2011-07-29 15:00:10

ServiceStacRedis

2009-08-26 11:33:28

Twitter

2009-07-30 15:50:49

ASP.NET中網(wǎng)站訪
點贊
收藏

51CTO技術棧公眾號