通用點贊設計與實現_專注的部落格
本文由 簡悅 SimpRead 轉碼, 原文地址 blog.csdn.net
點贊作為一個高頻率的操作,如果每次操作都讀寫資料庫會增加資料庫的壓力,所以採用快取 + 定時任務來實現。點贊資料是在 redis 中快取半小時,同時定時任務是每隔 5 分鐘執行一次,做持久化儲存,這裡的快取時間和任務執行時間可根據專案情況而定。
優點
- 降低對資料庫的影響
- 提高點讚的效率
缺點
- 如果任務掛了,會丟失點贊資料
- 持久化儲存不是實時的
時序圖
資料庫設計
create table user_like( id bigint(20) unsigned not null auto_increment comment 'id', user_id bigint(20) not null default 0 comment '使用者id', liked_id varchar(21) not null default '' comment '被點讚的id', liked_status int(11) not null default 0 comment '點贊狀態,0未點贊,1已點贊', liked_type int(11) not null default 0 comment '點讚的型別', liked_time timestamp not null default '0000-00-00 00:00:00.000000' comment '點贊時間', is_delete tinyint not null default '0' comment '是否邏輯刪除', create_time timestamp not null default CURRENT_TIMESTAMP comment '建立時間', update_time timestamp not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP comment '更新時間', primary key (id), unique uniq_user_id_liked_id_type(user_id,liked_id,liked_type), key idx_liked_id (liked_id), key idx_create_time (create_time), key idx_update_time (update_time) )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='使用者點贊表'; create table user_like_stat( id bigint(20) unsigned not null auto_increment comment 'id', liked_id varchar(21) not null default '' comment '被點贊id', liked_count int(11) not null default 0 comment '點贊總數量', is_delete tinyint not null default '0' comment '是否邏輯刪除', create_time timestamp not null default CURRENT_TIMESTAMP comment '建立時間', update_time timestamp not null default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP comment '更新時間', primary key (id), unique uniq_info_num(liked_id), key idx_create_time (create_time), key idx_update_time (update_time) )ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='點贊統計表';
實現步驟
1. 設計快取資料格式
整個點贊模組主要採用快取來完成,所以要選擇合適資料結構,我選擇 hash 資料結構來實現,應為它可以新增、獲取、移除單個鍵值對,並且可以獲取所有鍵值對。主要快取兩種資料,一種是使用者的點贊狀態,一種是被點贊 id 的點贊數量。這兩種資料分別用兩個 key 儲存,這兩個 key 中都是儲存的多個鍵值對。鍵值對格式如下:
使用者的點贊狀態 key-value------>{“被點讚的 id:: 使用者 id” : “點贊狀態:: 點贊時間:: 點贊型別”}
被點贊 id 的點贊數量 key-value------>{“被點贊 id” : “點贊數量”}
2. 大 key 拆分
點讚的資料量比較大的情況下,上面的設計會造成單個 key 儲存的 value 很大,由於 redis 是單執行緒執行,如果一次操作的 value 很大,會對整個 redis 的響應時間有影響,所以我們這裡在將上面的兩個 key 做拆分。固定 key 的數量,每次存取時都先在本地計算出落在了哪個 key 上,這個操作就類似於 redis 分割槽、分片。有利於降低單次操作的壓力,將壓力平分到多個 key 上。
//點贊狀態key拆分 newHashKey = hashKey +"_"+ (userId% 5); hset (newHashKey, field, value) ; hget(newHashKey, field) //點贊數量key拆分 newHashKey = hashKey +"_"+ Math.abs((hash*(被點贊id)) % 5); hset (newHashKey, field, value) ; hget(newHashKey, field)
3. 程式碼實現
以下值截取了部分程式碼, 提供思路。
- 點贊狀態列舉
- 點贊型別列舉
- 使用者點贊類
- 點贊介面實現
這裡使用策略設計模式來實現,方便以後的擴充套件,對這個設計模式不瞭解的請點選
https://blog.csdn.net/qq_34264849/article/details/83657745
5. 邏輯
取消點贊和這個介面相同,只需要替換下點贊狀態和 redis 增量
6. 定時任務
定時任務採用 Azkaban 任務排程系統,每個 5 分種執行一次任務,把點贊資料從 redis 快取中取出做持久化到 mysql。
4. 改進點
現在的讀取都是用的一個 key,接下來可以優化為把 key 做讀寫分離。寫入和讀取分別用不同的 key,這樣做可以減少資源的浪費,要不每次跑定時任務都會把已經持久化並且快取未失效的資料拿出來做一遍查詢。
以上就是點讚的一個實現思路,大家有什麼更好的方法或者改進的點,歡迎提出來。