适用于分布式系统下的简单签到积分系统

设计背景

      在当今互联网应用中,签到被广泛用于提高应用日活,吸引用户访问网站。用户通过连续登录网站签到,换取积分,可以用来兑换一些奖品。对于提高用户的积极性,系统的活跃度来说,是一个简单且有效的方式。本文就针对签到系统给出了一个简单的实现思路。

技术选型

     对于签到系统来说,一般都会统计该用户本月内的签到次数,连续签到天数,并根据不同连续签到的天数给出不同的积分。那么要统计这些数据,我们首先想到的是设计一个数据表,包括用户id,签到的年月日,用户当日签到就向数据库新增一条记录,在统计连续签到天数,也需要逐个记录去查询。对于一个用户来说,一个月就是三十条记录,当我们的系统人数越来越多后,这张表就会产生非常庞大的数据量,不仅占用磁盘空间,也会极大的影响查询效率。

     为了解决数据库存储签到记录的局限性,人们想到了使用bit位来表示是否签到,众所周知,一个比特位只有0或1,那么自然就可以使用0表示未签到,使用1表示已签到,想要查询当月签到次数,只需要统计值为1的位的个数就可以了,这种使用位来表示任务的状态的数据结构就叫做bitmap,位图。

     redis恰好为我们提供了bitmap的数据结构和相关操作命令,使我们操作bitmap变得十分便捷。redis中的bitmap底层是基于String类型实现的,可以理解为一个二进制位组成的字符串,非常适合处理大量布尔值或小整数的高效存储和快速操作,尤其适用于需要频繁读写的场景。通过合理的应用,可以在保证性能的同时大幅减少内存占用。用来实现签到功能自然再合适不过了。

查询签到

    查询用户本月的签到情况。就是使用bitfield (key) get u(days) 0 命令,该命令表示从0号索引取指定个数的位,返回一个十进制数,将十进制数转为二进制,如果二进制数的位数少于天数的话,就需要在起点补0,表示当日未签到。

新增签到

     就是使用set命令将对应的天数的bit位置1,要注意起始索引是0,所以使用命令时要将当前天数减一。

获取连续签到天数

      获取当天之前的连续签到天数,就是获取到签到情况的十进制数后转化为二进制字符串,再根据位数决定是否补零,之后将字符串反转,获取到第一个不是1的索引位置,该索引就代表连续签到天数。

新增积分

    本系统是一个在线学习系统,学员可以通过多种方式获取积分,兑换奖品,积分的获取规则如下:

  1. 签到规则 签到1天给1分 连续7天额外奖励10分 连续14天额外奖励20分 连续28天额外奖励40分 每月签到进度当月第一天重置

  2. 学习规则 每学习一小节积分+10,每天获得上限50分

  3. 交互规则(有效交互数据参与积分规则,无效数据会被删除) 写评价,积分+10 每日获得上限为50分 写问答,积分+5 每日获得上限为20分 写笔记,积分+3,每次被采集+2 每日获得上限为20分

     每位学员的积分只在当月有效,下月清零重新统计。

     其中,签到,学习,交互都属于不同的微服务,而用户在进行上述这些行为时,都需要向积分表插入一条记录。如果我们在每个服务中都加上统计积分的逻辑,就会使代码的耦合度过高,所以,我采用了rabbitmq进行跨服务间的积分信息收发,实现了异步的方式统计积分,将积分作为一个独立的微服务进行部署,实现了解耦,提高效率。具体实现如下:

      在不同的服务中获取积分后,向rabbitmq中投递积分的详情,在积分服务中,监听这些来自不同服务的积分详情,执行保存逻辑,逻辑如下

查询不同类型的积分

用户可以查看当天不同类型的已获得积分和积分上限,效果如下

就是根据积分类型分组,统计每组的分值总和返回给用户。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值