通用點贊設計思路

點贊做爲一個高頻率的操做,若是每次操做都讀寫數據庫會增長數據庫的壓力,因此採用緩存+定時任務來實現。點贊數據是在redis中緩存半小時,同時定時任務是每隔5分鐘執行一次,作持久化存儲,這裏的緩存時間和任務執行時間可根據項目狀況而定。mysql

優勢

1.下降對數據庫的影響 2.提升點讚的效率redis

缺點

1.若是任務掛了,會丟失點贊數據 2.持久化存儲不是實時的sql

時序圖

在這裏插入圖片描述

數據庫設計

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上。bash

//點贊狀態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.代碼實現

如下值截取了部分代碼,提供思路。數據結構

1.點贊狀態枚舉 數據庫設計

在這裏插入圖片描述
2.點贊類型枚舉
在這裏插入圖片描述
3.用戶點贊類
在這裏插入圖片描述
4.點贊接口實現 這裏使用策略設計模式來實現,方便之後的擴展,對這個設計模式不瞭解的請點擊

juejin.im/post/5bdc1e…post

這裏進行策略的選擇
在這裏插入圖片描述
在這裏插入圖片描述
5.邏輯 取消點贊和這個接口相同,只須要替換下點贊狀態和redis增量
在這裏插入圖片描述
6.定時任務 定時任務採用Azkaban任務調度系統,每一個5分種運行一次任務,把點贊數據從redis緩存中取出作持久化到mysql。

4.改進點

如今的讀取都是用的一個key,接下來能夠優化爲把key作讀寫分離。寫入和讀取分別用不一樣的key,這樣作能夠減小資源的浪費,要不每次跑定時任務都會把已經持久化而且緩存未失效的數據拿出來作一遍查詢。

以上就是點讚的一個實現思路,你們有什麼更好的方法或者改進的點,歡迎提出來。

相關文章
相關標籤/搜索