点赞系统设计
点赞在社交类平台中,作为一个最常见的操作,每天会有成千上万的操作。如果每次都将操作写入数据库,那么对于数据库会形成很大的操作负担,因此,本文讲述如何通过Redis构件一个定时写入数据库的点赞功能。
点赞操作存储在一个set中,key以review:ID作为标识,value记录了点赞人ID:操作(1点赞/0取消点赞),这样针对同一个set即代表了指定时间内所有对于这个评论的点赞或取消。
另外有一个单独的set,记录了此单位时间内,所有被点赞的书评列表索引,此索引可以快速的找到上面提到的点赞set。当计划任务处理所有的评论时,除了一次写入点赞信息之外,同时可以合并数量为用户做消息推送动作。
Redis中的存储结构如下图所示:
以下是点赞记录功能,采用PHP实现:
(简要逻辑:首先讲评论索引加入到reviewindex中,然后判断数据库中是否有点赞,如果有,则在redis中加入取消此点赞操作。如果数据库没有点赞,那么在redis中记录点赞操作。相应的,如果redis中有点赞,那么可以直接在redis中取消,这样以后就不需要与数据库发生任何交互了。)
public function likeByRedis($reviewId, $fromUserId){
$redis=…//获取Redis连接
$redisKey='review:'.$reviewId;
$redis->sadd('reviewindex',$redisKey); //将此评论加入索引
$likeSetMember=$fromUserId.':1'; //:1代表点赞操作
$unlikeSetMember=$fromUserId.':0'; //:0代表取消点赞操作
if($this->is_like_exists($reviewId,$fromUserId)){ //数据库中存在
if($redis->sismember($redisKey,$unlikeSetMember)){
$redis->srem($redisKey,$unlikeSetMember);
}else{
$redis->sadd($redisKey,$unlikeSetMember);
}
}elseif($redis->sismember($redisKey,$likeSetMember)){ //redis中存在,那么取消之
$redis->srem($redisKey,$likeSetMember);
}else{ //点赞操作
$redis->srem($redisKey,$unlikeSetMember);
$redis->sadd($redisKey,$likeSetMember);
}
}
接下来,附上计划任务中的批量处理点赞功能,因业务原因才用python实现:
(简要逻辑:从Redis中,拿到reviewindex,然后迭代取出每一个书评信息,解析书评中的点赞和取消点赞操作,之后统一写入到数据库中)
def process(self):
redisClient = #连接Redis
likesInfo=redisClient.smembers('reviewindex')
likeOperation=[]
unlikeOperation=[]
for item in likesInfo:
reviewID=0
try:
reviewIndexInfo=item.split(':')
reviewID=reviewIndexInfo[1]
except e:
pass
if reviewID!=0:
reviewDetail=redisClient.smembers(item)
for likeDetail in reviewDetail:
try:
operationInfo=likeDetail.split(':')
#使用元祖模式而不使用对象模式 方便批量无区分的快速插入数据库
if operationInfo[1]=='1': #点赞
likeOperation.append((reviewID,reviewInfo['user_id'],operationInfo[0]))
else: #取消赞
unlikeOperation.append((reviewID,reviewInfo['user_id'],operationInfo[0]))
except Exception,e:
pass
redisClient.delete(item)
redisClient.delete('reviewindex')
# 数据库同步
likeDAO=LikesDAO()
likeDAO.persistLikeInfo(likeOperation,LikesDAO.LIKE_OPERATION)
likeDAO.persistLikeInfo(unlikeOperation,LikesDAO.UNLINE_OPERATION)
# 推送通知给用户
# 因为上述结构可以方便的统计到单个书评收到了哪些用户的点赞,所以可以推送类似“您的书评收到周杰伦,李宗盛等10位好友的点赞”
只是初步简单实现了点赞功能,如果有写错的地方,欢迎做过此类功能的大牛指正。