用redis實現計數器的例子

來源:互聯網
上載者:User

社交產品業務裡有很多統計計數的功能,比如:

使用者: 總點贊數,關注數,粉絲數
文章: 點贊數,評論數,熱度
訊息: 已讀,未讀,紅點訊息數
話題: 閱讀數,貼文數,收藏數

統計計數的特點
即時性要求高
寫的頻率很高
寫的效能對MySQL是一個挑戰
可以採用redis來最佳化高頻率寫入的效能要求。

redis最佳化方案一

對於每一個實體的計數,設計一個hash結構的counter:
//使用者
counter:user:{userID}
                        ->  praiseCnt: 100      //點贊數
                        ->  hostCnt: 200        //熱度
                        ->  followCnt: 332      //關注數
                        ->  fansCnt: 123        //粉絲數


//文章
counter:topic:{topicID}
                        -> praiseCnt: 100       //點贊數
                        -> commentCnt: 322      //評論數


//話題
counter:subject:{subjectID}
                            -> favoCnt: 312     //收藏數
                            -> viewCnt: 321     //閱讀數
                            -> searchCnt: 212   //搜尋進入次數
                            -> topicCnt: 312    //話題中貼文數

類似這種計數器,隨著產品功能的增加,也會越來越多,比如回複數,踩數,轉寄數什麼的。

redis相關的命令

//擷取指定userID的所有計數器
HGETALL counter:user:{userID}  

//擷取指定userID的指定計數器
HMGET counter:user:{userID}  praiseCnt hostCnt

//指定userID點贊數+1
HINCRBY counter:user:{userID}   praiseCnt

缺點:

這樣設計,如果要批量查詢多個使用者的資料,就比較麻煩,例如一次要查指定20個userID的計數器?只能迴圈執行 HGETALL counter:user:{userID}。
優點:

以實體彙總資料,方便資料管理

redis最佳化方案二

方案二是用來解決方案一的缺點的,依然是採用hash,結構設計是這樣的:

counter:user:praiseCnt
                        ->  userID_1001: 100
                        ->  userID_1002: 200
                        ->  userID_1003: 332
                        ->  userID_1004: 123
                                .......
                        ->  userID_9999: 213

 

counter:user:hostCnt
                        ->  userID_1001: 10
                        ->  userID_1002: 290
                        ->  userID_1003: 322
                        ->  userID_1004: 143
                                .......
                        ->  userID_9999: 213


counter:user:followCnt
                        ->  userID_1001: 21
                        ->  userID_1002: 10
                        ->  userID_1003: 32
                        ->  userID_1004: 203
                                .......
                        ->  userID_9999: 130

擷取多個指定userID的點贊數的命令變成這樣了:

HMGET counter:user:praiseCnt userID_1001 userID_1002

上面命令可以批量擷取多個使用者的點贊數,時間複雜度為O(n),n為指定userID的數量。

優點:

解決了大量操作的問題

缺點:

當要擷取多個計數器,比如同時需要praiseCnt,hostCnt時,要讀多次,不過要比第一種方案讀的次數要少。
一個hash裡的欄位將會非常寵大,HMGET也許會有效能瓶頸。
用redis管道(Pipelining)來最佳化方案一

對於第一種方案的缺點,可以通過redis管道來最佳化,一次性發送多個命令給redis執行:

$userIDArray = array(1001, 1002, 1003, 1009);

$pipe = $redis->multi(Redis::PIPELINE);
foreach ($userIDArray as $userID) {
    $pipe->hGetAll('counter:user:' . $userID);
}

$replies = $pipe->exec();
print_r($replies); 

還有一種方式是在redis上執行lua指令碼,前提是你必須要學會寫lua。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.