使用redis的bitmap实现用户点赞功能

写在前面,redis bitmap set key offset value 中的offset值的大小决定了它在内存中分配了多少内存。offset特别大的时候特别占用内存。一定注意

在一台2010MacBook Pro上,offset为2^32-1(分配512MB)需要~300ms,offset为2^30-1(分配128MB)需要~80ms,offset为2^28-1(分配32MB)需要~30ms,offset为2^26-1(分配8MB)需要8ms。<来自官方文档>
大概的空间占用计算公式是:($offset/8/1024/1024)MB
在我这个点赞里面offset为用户的merchantId,当用merchantId为5000万的时候只需要6M内存。

就是因为这个merchantId,我们系统中不知哪个同事把merchantId自增起始id设置了21亿多,算了一下这样有一个用户点了赞这个章节内存就是差不多250M然后就是这样导致redis内存满了,引发一系列问题。一定要注意这一点。这是我们生产真实发生的事故。

最近有一个需求,和新浪微博的评论很类似,是一个话题可以被评论,然后每个评论下都可以被回复,每个回复都有自己的回复数量,评论有评论的点赞数和回复数量,具体的方案如下:

对于点赞这样的功能,操作非常的频繁,如果单纯的考虑数据库肯定是最low的方式。

还有需要考虑的,哪个用户点赞了,对哪个评论点赞了,这两点非常重要。需要维护的数据用户的id,评论的id,以及点赞的结果。

这里我采用了redis的bitmap数据结构。

这里简单介绍一下这个数据结构的常用命令,具体的原理暂时不做介绍。

几个常见的命令:

  setbit,getbit,bitcount

比如我实现id为100的用户对id为1000的评论点了赞,可以这么写

setbit 1000 100 1

获取id为100的用户对1000的评论是否点赞

getbit 1000 100  返回结果为 1

setbit key offsect value 

key是需要存储数据的key,本次设计key为评论内容的id

                                  offsect是偏移量,即我们关系的用户对评论的唯一性操作,即用户的id

                                     value 是最终是否存在这个value只能是0,1

有意思的是这个值可以一直赋值,比如第一次执行命令setbit 1000  100 1

再次执行setbit 1000  100 1 那么他的值就会变为0。这里正好应用这个特性实现判断用户是否点赞,如果点赞再次执行这个命令,用户就会取消点赞。

下面是StringredisTemplate客户端对上面几条命令的封装

//bitmap操作
    /**
     * setbit 设置一个值
     *
     * @param key
     * @param offset
     * @param value
     */
    public void setBit(String key, Long offset, Boolean value) {
        if (StringUtils.isBlank(key)) {
            throw new IllegalArgumentException("redis key is null");
        }
        redisTemplate.execute((RedisCallback<Boolean>) con -> con.setBit(key.getBytes(),offset , value));
    }

    /**
     * getBit
     * 获取指定offset的值
     *
     * @param key
     * @param offset
     * @return
     */

    public Boolean getBit(String key, Integer offset) {
        if (StringUtils.isBlank(key)) {
            throw new IllegalArgumentException("redis key is null");
        }
        return redisTemplate.execute((RedisCallback<Boolean>) con -> con.getBit(key.getBytes(), offset));

    }

    /**
     * bitcount
     * @param key
     * @return
     */
    public Integer bitCount(String key) {
        return redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(key.getBytes())).intValue();
    }

    public Long bitOp(RedisStringCommands.BitOperation op, String saveKey, String... desKey) {
        byte[][] bytes = new byte[desKey.length][];
        for (int i = 0; i < desKey.length; i++) {
            bytes[i] = desKey[i].getBytes();
        }
        return redisTemplate.execute((RedisCallback<Long>) con -> con.bitOp(op, saveKey.getBytes(), bytes));
    }

 

最后写写一个定时每天凌晨同步这些点赞数,评论数到咱们的mysql数据库就可以。这样就实现了一个点赞,取消点赞功能。

总结如下:

点赞,取消点赞

这里还有一个是对用户回复的统计,由于需要统计每条回复被多少人回复了,这里我采用看传统redis,key,v结构

使用redis的incr原子特性结合每个回复内容的id使用进行统计累加

当用户回复了某个回复就会+1,这incr不会存在并发的问题,这是redis的原子操作命令。

上面便是我使用redis对点赞以及评论功能的总结。over,下班,回家。

源码在我的资源里可以看到,需要的自行下载。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值