最近要做一个圣诞抽奖活动,需要记录每天用户签到的记录,以前一般都是用普通的字符串数据类型,每个用户的签到用一个 key

// 用户10在活动第一天的签到key为record:1:10
$key = "record:$day:$id";
if ($redis->get($key)) {
echo '已签到';
} else {
$redis->set($key, 1)
}

那么一个用户一天的签到记录就要占一个字节,用户一多就产生非常多的 key,浪费宝贵的内存。

位图

为了解决这个问题,redis 另一种数据类型位图就非常适合。位图并不是特殊的数据类型,内容其实就是字符串,每一位只存储0或1,非常适合存储这种布尔类型的数据

位图使用 setbit/getbit 来存取数据

> SETBIT key offset value
> GETBIT key offset

比如一个用户圣诞连续五天的签到记录可以只使用一个 key, 10010 代表用户只有第二天和第五天签过到

$key = "record:$id";
if ($redis->getbit($key, $day)) {
echo '已签到';
} else {
$redis->setbit($key, $day, 1)
}

现在一个用户五天的签到记录只会产生一个 key,占用内存仅为 5bit 不到一个字节

进一步,如果你的用户系统中用户 id 是连续的 int 类型,还能更节省。因为只记录每个用户5天的签到记录,在一串位图中,每个用户占5个坑,这样所有的用户的签到数据只会使用一个 key

// 用户1占前5个坑
$offset = ($id - 1) * 5 + $day -1;
if ($redis->getbit('record', $offset)) {
echo '已签到';
} else {
$redis->setbit('record', $offset, 1)
}

现在只需要一个 key 就可以存下所有用户的签到记录了。

需要注意的是位图一个 key 最多存储 512mb 的内容,如果你的用户数大于 8*1024*1024*1024*512 / 5 ≈ 87 亿 并不适用这个方法。

其他用法

bitcount 用来统计指定位置范围内 1 的个数,bitpos 用来查找指定范围内出现的第一个 0 或 1。

> setbit s 0 1
> setbit s 3 1 #s=1001
> bitcount s [start, end]
(integer) 2
> bitpos s 0 [start, end]
(integer) 1

redis位图巧用,节约内存的更多相关文章

  1. Redis实战(18)Redis位图巧用,节约内存

    序言 资料 https://www.cnblogs.com/luke44/p/12031078.html

  2. 节约内存:Instagram的Redis实践(转)

    一.问题:     数据库表数据量极大(千万条),要求让服务器更加快速地响应用户的需求. 二.解决方案:      1.通过高速服务器Cache缓存数据库数据      2.内存数据库 三.主流解Ca ...

  3. 巧用redis位图存储亿级数据与访问 - 简书

    原文:巧用redis位图存储亿级数据与访问 - 简书 业务背景 现有一个业务需求,需要从一批很大的用户活跃数据(2亿+)中判断用户是否是活跃用户.由于此数据是基于用户的各种行为日志清洗才能得到,数据部 ...

  4. 节约内存:Instagram的Redis实践(转)

    Instagram可以说是网拍App的始祖级应用,也是当前最火热的拍照App之一,Instagram的照片数量已经达到3亿,而在Instagram里,我们需要知道每一张照片的作者是谁,下面就是Inst ...

  5. 节约内存:Instagram的Redis实践

    Instagram可以说是网拍App的始祖级应用,也是当前最火热的拍照App之一,Instagram的照片数量已经达到3亿,而在Instagram里,我们需要知道每一张照片的作者是谁,下面就是Inst ...

  6. Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  7. 基于Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  8. Redis位图法记录在线用户的状态

    Redis位图法记录在线用户的状态 位图 Redis官方文档对于位图的介绍如下: 位图不是一个真实的数据类型,而是定义在字符串类型上的面向位的操作的集合.由于字符串类型是二进制安全的二进制大对象,并且 ...

  9. Redis(八)理解内存

    Redis所有的数据都存在内存中,当前内存虽然越来越便宜,但跟廉价的硬盘相比成本还是比较昂贵,因此如何高效利用Redis内存变得非常重要. 高效利用Redis内存首先需要理解Redis内存消耗在哪里, ...

随机推荐

  1. git 合并代码

    分支 dev 及衍生分支 dev-ctj 一.rebase 1.git checkout dev-ctj 2.git rebase -i head~num[num 是本分支的提交数,多个提交数先合并为 ...

  2. 在控制器中如何对frxml的控件初始化

    如果在控制器中实现Initializable这个接口,并重iInitializable这个方法 对于一个fxml文件来说它首先执行控制器的构造函数,这个时候它是无法对@FXML修饰的方法进行访问的,然 ...

  3. servlet三大组件

    servlet大致可以分为三个:简单servlet.过滤servlet.监听servlet servlet: servlet的创建 创建一个类并实现Servlet接口. 重写service方法. 在服 ...

  4. HashMap深入分析及使用要点

    本文内容来自深入理解HashMap.从数据结构谈HashMap.HashMap深度分析 先说使用要点. 1.不要在并发场景中使用HashMap HashMap是线程不安全的,如果被多个线程共享的操作, ...

  5. go中的数据结构接口-interface

    1. 接口的基本使用 golang中的interface本身也是一种类型,它代表的是一个方法的集合.任何类型只要实现了接口中声明的所有方法,那么该类就实现了该接口.与其他语言不同,golang并不需要 ...

  6. iOS定位--CoreLocation

    一:导入框架 #import <CoreLocation/CoreLocation.h> 二:设置代理及属性 <CLLocationManagerDelegate> @prop ...

  7. ES6,import时如何正确使用花括号'{ }'

    在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种.前者用于服务器,后者用于浏览器.ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取 ...

  8. 你不知道的JS系列【1】- 什么是作用域

      几乎所有的编程语言都能够储存变量,并且能在之后对这个变量值进行访问或修改,正是储存和访问变量的能力将状态带给了程序,那么,这些变量储存在哪里呢?程序需要时又是如何找到他们?这些问题说明需要一套设计 ...

  9. [error] hadoop:ls: `.': No such file or directory

    问题: 解决: https://stackoverflow.com/questions/28241251/hadoop-fs-ls-results-in-no-such-file-or-directo ...

  10. 领扣(LeetCode)独特的电子邮箱地址 个人题解

    每封电子邮件都由一个本地名称和一个域名组成,以 @ 符号分隔. 例如,在 alice@leetcode.com中, alice 是本地名称,而 leetcode.com 是域名. 除了小写字母,这些电 ...