点赞做为一个高频率的操做,若是每次操做都读写数据库会增长数据库的压力,因此采用缓存+定时任务来实现。点赞数据是在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='点赞统计表';
复制代码
整个点赞模块主要采用缓存来完成,因此要选择合适数据结构,我选择hash数据结构来实现,应为它能够添加、获取、移除单个键值对,而且能够获取全部键值对。主要缓存两种数据,一种是用户的点赞状态,一种是被点赞id的点赞数量。这两种数据分别用两个key存储,这两个key中都是存储的多个键值对。键值对格式以下:数据库
用户的点赞状态key-value------>{"被点赞的id::用户id" :"点赞状态::点赞时间::点赞类型"}设计模式
被点赞id的点赞数量key-value------>{"被点赞id" : "点赞数量"}缓存
点赞的数据量比较大的状况下,上面的设计会形成单个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)
复制代码
如下值截取了部分代码,提供思路。数据结构
1.点赞状态枚举 数据库设计
如今的读取都是用的一个key,接下来能够优化为把key作读写分离。写入和读取分别用不一样的key,这样作能够减小资源的浪费,要不每次跑定时任务都会把已经持久化而且缓存未失效的数据拿出来作一遍查询。
以上就是点赞的一个实现思路,你们有什么更好的方法或者改进的点,欢迎提出来。