Java+Redis位图实现点赞签到相关功能
你知道的越多,不知道的就越多,业余的像一棵小草!
成功路上并不拥挤,因为坚持的人不多。
编辑:业余草
juejin.cn/post/6975051843437068318
推荐:https://www.xttblog.com/?p=5221
前言
对于我们平时的一些社区应用,如微博,知乎,掘金等应用点赞,评论这类功能是不可或缺的,例如点赞功能我们其实是可以通过 mysql 去做实现的,但是每次点赞都去实时改库可以想象一下当遇到一个热点文章例如,前段时间大火特火的爆料某艺人日薪多少
帖子,这个上千万乃至亿级的点赞量,这个时候我们再去实时改库的话就不那么恰当,今天我们介绍的主角是Redis的位图操作,接下来我们引出正题,来看一下位图
是这么做到的;
介绍
在 Redis 里位图并不是一个真正的数据类型,其实就是一种普通的字符串,也可以说是byte数组。它是定义在字符串类型中,一个字符串类型的值最多能存储512M
字节的内容也就是2^32b
;
❝2^(9(512)+10(1024)+10(1024)+3(8b=1B))=2^32b
❞
应用场景:
用户签到 用户在线状态 统计活跃用户 各种状态值 自定义布隆过滤器 点赞功能
可以想象一下假如我们要统计一个用户一年的签到记录,签了是 1,没签是 0,
要记录 365 天。如果使用普通的 key/value
,每个用户要记录 365个
,当用户上亿的时候,需要的存储空间是惊人的。因为只统计0,1
我们可以使用位图
来进行存储,这样每天的签到记录只占据一个位,365 天就是 365
个位,46
个字节 (一个字节有8位) 就可以完全容纳下,这样就很节省资源了,同时也提高了效率;
基本命令:
SETBIT key offset value
//对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。
//offset 参数必须大于或等于 0 ,小于 2^32 (bit 映射被限制在 512 MB 之内)。
GETBIT key offset
//对 key 所储存的字符串值,获取指定偏移量上的位(bit)。
BITCOUNT key
//计算给定字符串中,被设置为 1 的比特位的数量。
BITPOS key bit [start] [end]
//返回位图中第一个值为 bit 的二进制位的位置。
BITOP operation destkey key [key …]
//对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
BITFIELD
//bitfield 有三个子指令,分别是 get/set/incrby,它们都可以对指定位片段进行读写,
//但是最多只能处理 64 个连续的位,如果超过 64 位,就得使用多个子指令,bitfield 可以
//一次执行多个子指令。
简单使用:
//添加
127.0.0.1:6379> setbit a 2 1
(integer) 0
127.0.0.1:6379> setbit a 3 1
(integer) 0
//查找
127.0.0.1:6379> getbit a 2
(integer) 1
//统计
127.0.0.1:6379> bitcount a
(integer) 2
点赞功能
我们先拿点赞功能来做一个简单的编码介绍:
帖子1(post1):
postId:1
postName:《震惊!业余草日薪高达208w,超过马云》
帖子2(post2):
postId:2
postName:《业余草持刀狂追某用户8条街,原因是该用户看文不点赞》
用户1(user)
id:1001
name:业余草
。。。。
点赞功能
我这里的处理方式是异步改库,点完赞之后异步修改数据库,不要求实时处理结果其实可以用定时任务去批量改库(需要存一定时间内的 postId 和 userId 索引关系);
@Override
public boolean giveLike(String userId, Long postId) {
try (Jedis jedis = redisUtil.getJedis()) {
//设置用户点赞
jedis.setbit(userId, postId, true);
//设置帖子点赞
jedis.setbit(String.valueOf(postId), Long.valueOf(userId), true);
threadPool.submit(new Runnable() {
@Override
public void run() {
//同时可以异步将点赞信息写到数据库中
updateGiveLikeInfo(userId, postId);
}
});
return true;
} catch (Exception e) {
return false;
}
}
取消点赞的操作和这个相反将jedis.setbit(userId, postId, false);
就OK了!
统计点赞数:
@Override
public Long getGiveLikeByUserId() {
try (Jedis jedis = redisUtil.getJedis()) {
String userId = "1001";
String PostId = "1";
System.out.println(jedis.bitcount(userId));
System.out.println(jedis.bitcount(PostId));
return 1L;
} catch (Exception e) {
return 0L;
}
}
在页面展示的时候我们我们只需要查询当前的这个 bitmap 的总数就 ok 了!
范围统计
当然我觉得范围查找最实用的场景就是签到统计 第一种玩法:userId 为 key,时间戳为 offset,签到 1 未签到 0 可以使用以下命令:
BITPOS key bit start :从start+1个字节开始查找,直到尾部 BITPOS key bit start end:从start+1字节开始到end+1字节之间查找
第二种玩法:时间为 key,userId 为 offset,签到 1 未签到 0 可以使用以下命令:
BITOP operation destkey key [key ...]
对一个或多个保存二进制位的字符串 key 进行位操作,并将结果保存到 destkey 上。operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种
❝ok!一个简单的位图实现点赞等功能就实现了,大家一个举一反三哈,玩法还是很多的,大家也可以根据自己的需求去做优化,希望可以对大家有帮助,有不对的地方希望大家可以提出来的,共同成长。
❞