天天看點

每秒30W次的點贊業務,怎麼優化?

每秒30W次的點贊業務,怎麼優化?

繼續答星球水友提問,30WQPS的點贊計數業務,如何設計? 可以看到,這個業務的特點是:(1)吞吐量超高;(2)能夠接受一定資料不一緻;畫外音:計數有微小不準确,不是大問題。 先用最樸素的思想,隻考慮點贊計數,可以怎麼做?有幾點是最容易想到的:(1)肯定不能用資料庫抗實時讀寫流量;(2)redis天然支援固化,可以用高可用redis叢集來做固化存儲;(3)也可以用MySQL來做固化存儲,redis做緩存,讀寫操作都落緩存,異步線程定期刷DB;(4)架一層計數服務,将計數與業務邏輯解耦; 此時MySQL核心資料結構是:

t_count(msg_id, praise_count)

 此時redis的KV設計也不難:

key:msg_id

value:praise_count

每秒30W次的點贊業務,怎麼優化?

似乎很容易就搞定了:(1)服務可以水準擴充;(2)資料量增加時,資料庫可以水準擴充;(3)讀寫量增加時,緩存也可以水準擴充; 計數系統的難點,還在于業務擴充性問題,以及效率問題。 以微網誌為例:

每秒30W次的點贊業務,怎麼優化?

(1)使用者微網誌首頁,有多條消息list<msg_id>,這是一種擴充;(2)同一條消息msg_id,不止有點贊計數,還有閱讀計數,轉發計數,評論計數,這也是一種擴充; 假如用最樸素的方式實作,多條消息多個計數的擷取僞代碼如下:

// (1)擷取首頁所有消息msg_id

list<msg_id> = getHomePageMsg(uid);

// (2)對于首頁的所有消息要拉取多個計數

for( msg_id in list<msg_id>){

         //(3.1)擷取閱讀計數

         getReadCount(msg_id); 

         //(3.2)擷取轉發計數

         getForwordCount(msg_id);

         //(3.3)擷取評論計數

         getCommentCount(msg_id);

         //(3.4)擷取贊計數

         getPraiseCount(msg_id);

}

 由于同一個msg_id多了幾種業務計數,redis的key需要帶上業務flag,更新為:

msg_id:read

msg_id:forword

msg_id:comment

msg_id:praise

用來區分共一個msg_id的四種不同業務計數,redis不能支援key的模糊操作,必須通路四次reids。 假設首頁有100條消息,這個方案總結為:(1)for循環每一條消息,100條消息100次;(2)每條消息4次RPC擷取計數接口調用;(3)每次調用服務要通路reids,拼裝key擷取count;畫外音:這種方案的擴充性和效率是非常低的。 那如何進行優化呢? 首先看下資料庫層面中繼資料擴充,常見的擴充方式是,增加列,記錄更多的業務計數。

每秒30W次的點贊業務,怎麼優化?

如上圖所示,由一列點贊計數,擴充為四列閱讀、轉發、評論、點贊計數。

 增加列這種業務計數擴充方式的缺點是:每次要擴充業務計數時,總是需要修改表結構,增加列,很煩。 有沒有不需要變更表結構的擴充方式呢?行擴充是一種擴充性更好的方式。

每秒30W次的點贊業務,怎麼優化?

表結構固化為:

t_count(msg_id, count_key, count_value)

當要擴充業務計數時,增加一行就行,不需要修改表結構。畫外音:很多配置業務,會使用這種方案,友善增加配置。 增加行這種業務計數擴充方式的缺點是:表資料行數會增加,但這不是主要沖突,資料庫水準擴充能很輕松解決資料量大的問題。 接下來看下redis批量擷取計數的優化方案。

每秒30W次的點贊業務,怎麼優化?

原始方案,通過拼裝key來區分同一個msg_id的不同業務計數。

 可以更新為,同一個value來存儲多個計數。

每秒30W次的點贊業務,怎麼優化?

如上圖所示,

同一個msg_id的四個計數,存儲在一個value裡,進而避免多次redis通路。

畫外音:通過value來擴充,是不是很巧妙? 總結計數業務,在資料量大,并發量大的時候,要考慮的一些技術點:(1)用緩存抗讀寫;(2)服務化,計數系統與業務系統解耦;(3)水準切分擴充吞吐量、資料量、讀寫量;(4)要考慮擴充性,資料庫層面常見的優化有:列擴充,行擴充兩種方式;(5)要考慮批量操作,緩存層面常見的優化有:一個value存儲多個業務計數; 計數系統優化先聊到這裡,希望大家有收獲。

歡迎大家繼續提問,有問必答。

本文轉自“架構師之路”公衆号,58沈劍提供。