如图所示为用户留存分析功能前端
该柱状图展现的为用户留存百分比.redis
以按周展现为例算法
U:活跃用户数 x:第几周 y:活跃占比数据库
需求整理:数组
对于这种数据后台的功能,做为服务端开发,咱们会尽可能要求数据库将结果统计好,由咱们服务端直接取结果作展现.数据结构
可是因为有随机日期的对比,假设由数据组来进行统计,意味着须要对天天都作对比统计(统计结果数据量大,耗费性能),并不现实.性能
因此最终仍是决定由服务端来作实时统计.大数据
实时统计,主要考虑前端的响应速度.优化
采用bitmap按天纬度来存放用户登陆数据..net
实现过程:
采用bitmap按用户纬度存放登陆时间信息(哪几天登陆)
记当天为标准第0天
对每一个登陆用户,将对每一个登陆用户,将当前天数对应的位置为1
当计算y(x(i))时
用户 | 描述 | bitmap |
---|---|---|
a | 第-4,-3,-1,0天登陆 | [1,1,0,1,1] |
b | 第-3,-2,0天登陆 | [1,1,0,1] |
B(-3,0) | 第-3,0天登陆 | [1,0,0,1] |
B(0) | 第0天登陆 | [1] |
优势 | 缺点 | |
---|---|---|
方案一 | 查询快,只须要作一次and操做 | 空间占用太大,天天都要以最大用户量生成一条bitmap |
方案二 | 节省空间,空间占用随用户量增加,每一个用户的bitmap随登录状况变化 | 查询略慢,须要遍历全部用户作and操做 |
简单归纳: 方案一费空间,方案二查询慢
实际开发过程当中,因为咱们采用redis进行存储.
采用方案一的话内存过于浪费.而采用方案二,以个人macpro-i5配置只能负载20w/s的and操做,响应速度方面难以接受.
综合上述方式一二都不能知足要求,只能看是否还有优化空间.
通过同事提醒,针对方式一采用一种空间压缩算法,解决了方案一空间浪费的缺陷.
简单归纳:
假设数据量为不超过2^32.
将数据拆分为高16位,低16位
对高位进行聚合(以高位作key,value为有相同高位的全部低位数组)
根据低位的数据量(不一样高位聚合出的低位数组长度不相同),使用不一样的container(数据结构)存储
len<4K ArrayContainer 直接存值
len>=4K BitmapContainer 使用bitmap存储
4K的取值缘由:value的最大总数是为2^16=65536. 假设以bitmap方式存储须要65536bit=8kb,而直接存值的方式,一个值16,4K个总共须要2byte*4K=8kb.因此当value总量<4k时,使用直接存值的方式更节省空间
RunContainer 压缩存储
RunContainer中的Run指的是行程长度压缩算法(Run Length Encoding),对连续数据有比较好的压缩效果.对于数列11,12,13,14,15,21,22 它会压缩为11,4,21,1
空间压缩主要体如今:
对数据的位操做速度有影响(3种container相互and.乐观状况两个BitmapContainer作and切BitCount()>4096,则数据无影响)
综上: 使用RoaringBitmap的优缺点
方案3能够说是平衡了方案一二,是本次的最优选择