Redis【应用篇】Redis我使用过的那些场景

session 共享

在 web 开发中,http 是无状态的协议,而为了保持会话状态,就需要维护一个列表,列表的数据格式为 key:value。

http 通过携带 key 进行访问,后台通过 key 获取 value 值,来确定此次 http 请求会话。

早期 该列表的维护保存在应用内存 session 中。在多机冗余部署的时候,会出现 session 共享的问题。业界有很多种解决方案,如 tomcat 配置 session 共享等。

使用 Redis 进行 session 集中管理是比目前较常用的一种方式。使用方式也很简单,使用 redis 中的 string 数据结构,就能够完成。

总结:通过集中存储 用户session 数据到Redis 中,所有需要进行认证的接口,都从该Redis 中获取 session 数据,进行认证判定。

简单日活统计

背景

待过的一家创业公司,给出的需求:简单的统计平台用户活跃数据(单位/天)。

需求分析
  • 1、首先用户每日登陆过至少一次,代表今日活跃。
  • 2、关键数据结构:时间、用户日活数据

设想一:使用Mysql 。

思路:每个用户,每日一条数据

存在问题:

  • 1、随着用户剧增,数据量也会疯狂增加。
  • 2、mysql 直接买的阿里云的,增加容量需要加钱
  • 3、数据量增加,统计sql 也会开始变慢,响应延迟开始变高。

设想一结论:从长远来看,不可取。

设想二:使用Mysql。

思路:所有用户每日只存一条数据。

分析:

  • 1、数据结构中需要指定一个字段用来存储所有用户的日活数据。
  • 2、通过二进制的格式存储,0代表今日未上线过,1代表今日已上线。
  • 3、通过计算用户主键对应的唯一数字作为偏移量,数据库中用户主键为数字自增,能够直接作为偏移量。

假设表结构如下

dateTime datetime '时间' content  varchar(m) '日活'

content 格式如下 0000010101 -> 表示:当前 dateTime 日期中,有3个人活跃。

不过很明显有个致命的问题,一个用户需要一个站位,1个varchar 站位1个字节,多少个用户多少个字节,且 varchar 最多 65532 个字节,明显不行。

假设表结构如下 dateTime datetime '时间' content  bigint(m) '日活'

如果通过数值,然后转换2二进制。如:id = 1 00 00 的用户进入活跃为1,则二进制位在1万位,对应的数字为 2^10000 ,,,超出想象

设想二结论:思路可以,通过Mysql 实现不靠谱。

设想三:使用文件存储。

思路:与设想二同,使用二进制格式存储。

分析:

  • 1、在Linux 系统中,1000 个用户的偏移大约  1k   -rw-r--r--. 1 root root 1020 5月  12 22:31 20190515

  1 0000 个用户大约 10k ,可以得出 100 万用户大约 1M左右。

  从数据的存储上来说能够实现。但是存在一个问题,就是统计计算复杂,加上io操作的损耗,同样不可取。

设想三结论:对比设想二,数据存储得到了解决,但是统计变得复杂,不可取。

设想四:使用 Redis 作为存储介质。

思路:与设想二同,采取二进制存储结构。

分析:

  • 首先,Redis 中的数据结构 bitmap 就是直接使用的二进制存储结构进行存储。
  • 其次,Redis 中提供了 bitCount ,bitop 命令 能够进行统计。
  • Redis 针对二进制的操作,提供了设值 和计算的方法。简化了很多步骤,但是Redis 是否就适合,此时的应用场景?

我们通过 Redis 中 bitmap 操作的相关说明进行分析。

设值:SETBIT key offset value

官方介绍

When setting the last possible bit (offset equal to 232 -1) and the string value stored at key does not yet hold a string value, or holds a small string value, Redis needs to allocate all intermediate memory which can block the server for some time。

setbit 进行设值的时候,空间是动态分配的。也就是说,日活存量随着用户增加,占用的内存随着增加,无需一次性进行空间分配。这个棒棒哒。

我们来简单的验证一下,官方的说法是否就是正确的。

  • 记录当前 redis 数据内存空间占用。   used_memory_human:856.30K
  • 模拟 最大 id 10 万的用户,并查看当前 Redis 数据内存空间占用   SETBIT 20190515 100000 1   used_memory_human:870.38K
  • 模拟 最大 id 1000 万的用户,并查看当前 Redis 数据内存空间占用   SETBIT 20190515 100 0000 1   used_memory_human:3.34M

验证结论: 1、SETBIT的空间分配是,动态分配的。 2、BitMap 空间占用小。 单单从 value 值来说,占用的内存空间 1000 0000 / 8 / 1024 / 1024 = 1.19M。加上key 占用的空间等。当用户达到 1000 0000,一条日活数据,也就占用大约 2.5M 的空间。 且setbit 偏移量最大为 2^32 -1 大约为 42 9496 7296(约42亿) ,value 占用内存空间最大为 512M。

统计:BITCOUNT key

官方介绍

Count the number of set bits (population counting) in a string.

统计指定bitmap 格式的key 中,二进制偏移被设置为1的数量。

也就是,(key -> value)20190515 ->  0010101010101,中1出现的次数。

我们可以通过该方法,统计某个时间点 日活数量。

BITCOUNT 能够直接进行计算,操作简便,那么其性能怎么样呢?

官方给出了,BITCOUNT 时间复杂度 :O(N)。可以理解随着偏移量增多,也就是用户量增多,计算时间会延长。那究竟时间是多长?官方举了个简单的例子进行描述。

456 字节的查询的时间花费和 GET,INCR 命令的 O(1)操作一样。 也就是 用户量 3648 几乎没什么影响。那在增加10 - 20 倍呢,经过简单测试,几乎也没什么影响。足以应对,小公司中的用户增长。

复杂统计:BITOP operation destkey key [key …]

官方介绍

The BITOP command supports four bitwise operations: AND, OR, XOR and NOT, thus the valid forms to call the command are: BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN BITOP NOT destkey srckey

BITOP 能够对多个 bitmap 进行位运算。通过位运算我们能够计算更复杂的计算。

比如:统计 20190515,20190516,20190517 这3天的日活总数。

20190515 -> 01010100000      3
20190516 -> 10000000000      1
20190517 -> 00000000111      3
----------------------------------
            11010100111      7

使用 BITOP OR DELAY_DAY_3 20190515 20190516 20190517 就能够得到 3日日活数据。

总结:使用 Redis 提供的 bitmap 数据结构,加上 BITCOUNT、BITOP 命令进行日活统计。

  • 数据存储   日期(单位/日) : 用户ID作为偏移量    其中:0代表不活跃,1代表活跃    如:20190515 000001010101010101
  • 数据统计:BITCOUNT   使用BITCOUNT 计算 20190515 000001010101010101 中 1 的个数,能够得到 20190515 当天日活
  • 数据统计:BITOP   使用 BITOP 能够计算,复杂的统计。

用户签到

背景

用户签到活动,每日一签,并计算用户周签到数,月签到数,达到标准进行奖励发放。

需要如下的数据展示, Redis我使用过的那些场景_签到日历

以及,后台的用户签到统计。

需求分析

设想一:Mysql,每个用户每天一条签到记录。

表结构: sign_id   bigint(10) 主键id  u_id          bigint(10) 用户id sign_time  datetime 签到时间

从数据存储来说:1个用户,如果每天签到,一年假设 365 天,占用空间,大约:(8+8+8)* 365 = 8760 b = 0.0083 MB

从数据展示来说:针对没有签到的时间,没有记录,如果需要返回某月的,签到详细记录。没有签到的日期,需要补全,并返回日期数据到前台。

设想二:Redis 每个用户,所有的签到记录,只有1条数据。

使用 bitmap 数据格式保存数据。存入的数据格式为:用户唯一标识 : 签到记录

其中签到记录,起始时间为功能上线那天。之后根据时间天差,作为 offset 偏移量进行设值。

从数据存储来说:1个用户,如果每天签到,一年假设 365天,占用空间,大约:365 bit = 0.0000435 MB。

从数据展示来说:需要遍历某个偏移量之间的所有值获取每个偏移量的值。

结果

选择设想二,无论从空间占用,还是数据展示统计来说,redis 都是更优的选择。

关注点

在实现的过程中,这里计算的月签到数,需要使用到 BITCOUNT 命令。

BITCOUNT 用法:BITCOUNT key 【start】 【end 】

其中 start 和 end 代表的是字节 而不是 bit 。 例如:BITCOUNT SIGN_USER_1 0 1 查询的是 SIGN_USER_! 用户,从签到功能上线起 ,前8天内的签到统计。

所以在设计,数据存储的时候我们需要如下的存储方式:

Redis我使用过的那些场景_签到数据存储结构

首先 BITCOUNT 计算 8 个bit 起,一个月最多 31 天,使用 4 个字节 32 个 byte 存储1个月的签到数据,而此时 1个用户每年的数据占用空间变为 32 * 12 = 384 bit,和之前理想化的 365 bit 相比 相差无几。

使用 Redis 提高性能,提高系统相应速度

在后台管理系统中,我们使用的是 Shiro 权限控制框架。而针对权限控制,所需要的就是当前登录用户,所拥有的权限。通常 查询一个用户拥有的权限都是相对耗时的。在用户通过后台的鉴权时,保存用户相关权限到 redis 中,当用户进行后台操作时的验权步骤中,能够较少因为验权查询数据库导致的响应时间过长。

在我们系统中,app 首页 就进行了一系列的汇总统计,如 累计订单汇总,累计交易总数汇总,累计交易金额汇总等之类的复杂汇总查询。 查询sql耗时较长,导致首页数据响应延迟高。使用 Redis 对数据进行缓存,根据可容忍的时效性进行过期控制。提高接口除第一次加载数据到缓存外的响应速度。

Redis 实现分布式锁

Redis实现分布式锁

其他

Redis 的用法除了以上这些自身用过之外,还有很多用途。比如说:

  • 数据预热。   这个数据预热也不能说完全没用过,像上面提到的复杂sql 计算,我在项目启动的时候,已经提前进行获取当前最新的数据统计结果存入到了 Redis 中,比如说,微信公众号 accessToken 和 js票据的获取,在应用启动的时候,同样回去加载到 Redis 中。
  • 解决高并发问题   这个就真的没用过了。想要用,也得要有场景给我啊。不过,虽然没有过,想到是有想过。网上也有很多类似的场景,比如说什么商品秒杀,高并发下的防止超卖的问题啊。

代码地址 redis 分支

更多精彩,关注公众号:【WTF名字好难取】!

转载于:https://my.oschina.net/u/3787570/blog/3051298

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值