你们项目中签到为什么要使用bitmap
bitmap是Redis中的String类型里的一种类型,存储数据是以二进制(bit位)为单位进行存储的。在处理大量数据统计和判断时,只占用非常小的一部分内存,且计算速度非常高效。
在项目中签到功能,是需要计算连续签到天数,如果使用其他类型去计算的话效率较慢,以及对内存的存储而言是不好的,而使用bitmap类型通过0,1就可以表示是否签到,效率好,内存空间的使用更少。
你们项目中积分功能是如何实现的
在项目中积分的规则基于学院的签到次数、每天学习次数以及有效交互(写评价、写回答、写笔记)规则来计算积分。
实现的话是基于MQ来实现,对服务之间进行解耦操作,以用户发起一条有效评论来举例:
- 学员发起了一条有效评论,保存到MongDB之前。
- 将用户id和分数投递到MQ中。
- 保存积分的服务监听MQ队列中的消息,一旦有消息就进行积分的增加。
- 在增加积分时,先判断该用户在今天对于当前类型的积分是否到达上限。
- 如果到上限,直接返回。
- 如果积分不足每日上限,但加上本次会超过上限,则保存积分最大上限-已获取的积分数。
- 如果不满足以上条件,则直接保存即可。
当然对于不同的积分类型都会有一个专门的队列。
Redis三大新面试点: 跳表、pipeline、bitmap
-
跳表:主要是单链表 + 索引的方式实现,以空间换时间的形式,提高查找速度。redis中的zset就用到跳表结构。
比如此时有一个1到6的链表,我要找5这个数字,普通的链表是依次向后找出5,而跳表是在这个基础上又加了一层索引。比如1–>3,3–>5。通过这种方式来减少遍历的数量。主要思想是二分查找。
-
pipeline:可以一次性发送多条命令并在执行完后一次性将结果返回。实现的原理通过队列先进先出原理来实现,以保证数据的顺序性。不具有原子性。
//查询哪些是我点赞的业务id pipeLine List<Object> resultList = redisTemplate.executePipelined(new RedisCallback<Object>() { @Override public Object doInRedis(RedisConnection connection)throws DataAccessException { StringRedisConnection conn = (StringRedisConnection) connection; for (Long bizId : bizIds) { conn.sIsMember("likes:biz:" + bizId, UserContext.getUser().toString()); } //必须返回null return null; } }); //lambda写法收集 return IntStream.range(0, resultList.size()) .filter(index -> (boolean) resultList.get(index)) .mapToObj(index -> bizIds.get(index)) .collect(Collectors.toSet()); }
-
bitmap:bitmap实际上就是String类型中的一种特殊的数据结构,通过二进制表示某个元素对应的值或者状态。 分为0或1。被称为位图,可以用来表示大量的布尔值。
命令 作用 setbit key offset value 根据偏移量(索引)设置值,值只能是0和1 ,返回对应偏移量上的旧值 getbit key offset 获取指定偏移量上的值 bitconut key 统计指定范围值为1的个数 Bitfield key Bitfield 命令可以将一个 Redis 字符串看作是一个由二进制位组成的数组, 并对数组中任意偏移量位置进行访问 Bitfield key: Bitfield 命令可以将一个 Redis 字符串看作是一个由二进制位组成的数组, 并对数组中任意偏移量位置进行访问
命令 作用 [GET type offset] 可以使用该命令对指定偏移量位置取值。 [SET type offset value] 也可以对指定偏移量的位置设置指定值。 [INCRBY type offset increment] 本命令可以对指定的整数进行自增和自减操作 [OVERFLOW WRAP|SAT|FAIL] 可配置的上溢和下溢处理操作