通用点赞设计思路

点赞做为一个高频率的操做,若是每次操做都读写数据库会增长数据库的压力,因此采用缓存+定时任务来实现。点赞数据是在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,这样作能够减小资源的浪费,要不每次跑定时任务都会把已经持久化而且缓存未失效的数据拿出来作一遍查询。

以上就是点赞的一个实现思路,你们有什么更好的方法或者改进的点,欢迎提出来。

相关文章
相关标签/搜索