計數場景的優化

2021-06-20 07:04:24 字數 2515 閱讀 3485

前言

社交網路資訊爆發,如何衡量你在社交**上的影響力?計數!

今天著重介紹下redis在計數器場景上的應用。

正文

對於計數器大家肯定還有或多或少的疑問。

q1:計數從**來?

通常我們發布的社交內容會儲存在資料庫中,最常見的如mysql:

更新索引:insert into user_message(uid,messageid) values(『xx』,』xx』)

更新內容:insert into message_2013_05(messageid,message) values(『xx』,'xx』);

為什麼要進行索引和內容區分我這裡就不多熬述了,這時要計算我有傳送了多少個message,再mysql庫中select count(messageid) where uid=*** 就可以獲得我們想要得計數,也就說大多數情況它源於我們的索引資料

q2:計數和其他資料相比有什麼特點?

1.單key讀寫頻繁,總體讀取量我們認為可能比內容模組還要頻繁,索引的增刪改查都會導致計數器的頻繁增減。尤其當某篇twitter,feed,weibo非常火爆時,單key的更新將更加火爆。

2.需要持久化,所有使用者都可能需啊知道自己的計數,這個資料和內容本身一樣重要。

從上面這兩個需求來看選用redis就是水到渠成了,而應對hotkey從mysql update count+1 & memcache 替換成redis incr更是優雅很多。減少了很多資料一致性的風險。

優化的思路:

我們知道隨著單個uid->message的個數越來越多,而count(message_id)的邏輯複雜度是o(n),獲取這個計數的成本是越來越大。如何讓其獲取變為o(1)?其實很簡單,我們只要單獨維護一下這個計數就可以了。舉乙個簡單的例子來說明:

假設我們有個字段,我們需要頻繁的獲取和更新這個欄位的長度,引用redisbook(中的一段對於redis 用於儲存key value的sds的描述好像能簡單的敘述這件事情。

「比如說, hello world 在 c 語言中就可以表示為 "hello world\0" 。

struct sdshdr ;

通過 len 屬性, sdshdr 可以實現複雜度為 θ(1) 的長度計算操作。

」前端維護:當發生message_id的增減時,client端進行一次transaction提交,索引更新及計數更新。優點是邏輯比較簡單,就是原來單次寫入變成了多次寫入,缺點是易引起資料不一致。

後端維護:當資料庫接收到message索引增減後,會產生相應的操作log,對於mysql來說就是binlog,我們根據mysql insert及delete 對索引計數進行增減操作。

不推薦mysql及mysql 觸發器更新的原因有如下幾個:

1.mysql本身可能成為更新瓶頸。mysql update其實是一種重更新,在buffer pool未命中的情況下,需要把where id=***的page從磁碟載入到記憶體中,在大併發的hot key更新時,這點很有可能成為瓶頸。

2.mysql replication的效率問題。mysql replication在如上寫入更新頻繁的情況下,也會成為瓶頸,當你的發了一篇feed,卻發現過了一分鐘計數才更新,這個肯定是不能容忍的。

3.mysql trigger相關bug比較多:

如下是我們線上環境遇到的乙個trigger引發的同步中斷問題:

後端維護的思路

詳細可見 @jackbillow  中使用redis方法

其實選擇前端維護還是後端維護實際應該取決於你們公司前端及後端技術成熟程度,如果後端技術足夠成熟,那麼放在後端維護節省的就是大量的開發時間和降低資料一致性的風險,反之,可以放在前端進行維護。

redis kv資料結構如下:

對於簡單的k-v場景來說,最好的優化思路就是將圖中redis本身為了通用性建立的dict(16位元組)及redis object(16位元組)去除,sds的額外位元組去除,這樣假設你的key占用10位元組,value 採用int占用4位元組:

那麼去除之前可能占用的記憶體是:

string型別的記憶體大小 = 鍵值個數 * (dictentry大小16位元組 + redisobject大小16位元組 + 包含key的sds大小 + 包含value的sds大小) + bucket個數 * 4

去除之後:

string型別的記憶體大小 =鍵值個數 *(key的大小10位元組 + value的4位元組)+bucket個數 * 4

當你有數億個key的時候,節省的內容容量將會是相當可觀的,當然實際優化的場景肯定會比現在列幾個公式複雜,有得必有失。

redis資料不能將老資料平滑過度到磁碟,無法應用到現ssd等高效能裝置是硬傷。

這篇文章給了不錯的思考方向。

DOM幾個場景的優化場景?

問題 在input的onchange事件中進行實時請求,當輸入框輸入發生改變時就會傳送一次請求。比如輸入react 解決方式 新增防抖功能,設定乙個合理的時間間隔,避免時間在時間間隔內頻繁觸發,同時又能保證輸入後可以看到結果 1 每次value改變,就會發出一次請求 const handlechan...

計數排序的優化

一 計數排序 計數排序是將序列中的數值轉化為陣列的下標,當數字a出現一次時,就把陣列中對應a下標的值加1。這些資料需要存放在額外開闢的陣列空間中 我們把該陣列成為統計陣列 計數排序的時間複雜度為線性的,它適用於在一定範圍內的整數排序,在取值範圍不是很大的情況下,它的效能可以超過那些時間複雜度為o n...

特定場景下SQL的優化

1.大表的資料修改最好分批處理。1000萬行的記錄表中刪除更新100萬行記錄,一次只刪除或更新5000行資料。每批處理完成後,暫停幾秒中,進行同步處理。2.如何修改大表的表結構。對錶的列的字段型別進行修改,改變字段寬度時還是會鎖表,無法解決主從資料庫延遲的問題。解決辦法 1.建立乙個新錶。2.在老表...