浅谈业务
文章目录
引言
在过去一段时间里,我接触了在内存不足的情况下对于部分大数据业务的处理,以下是我的处理心得体会。
一、利用bitmap统计持续访问的用户ID与持续访问量
- bitmap
- 场景
- 用户量要大,id为自增。
二、使用bitmap对学生考勤记录进行统计
- 业务
对学校学生考勤情况进行统计,统计出全天出勤、全周出勤、以及出勤数量。
- 技术路线
- 使用hashMap<k,v> : student_no : counter.
- 统计逻辑实现效率不高
- 使用 bitmap
- 高效率记录、高效率统计,只需要进行多次位与操作
- 节省内存空间
- 使用hashMap<k,v> : student_no : counter.
三、基于BloomFliter的网关设计
- 数据量
基于项目未来的发展考虑,该网关需要过滤的IP达到上百万的级别。
- 业务
在微服务架构中,我负责了网关服务的开发中的IP黑名单业务。需要在未来估计达到上百万甚至千万的IP中判断这个IP是否存在黑名单中。黑名单中的IP默认是三天。
- 个人任务
对IP进行判断,返回一个布尔值给安全拦截过滤器进行调用,且IP黑名单的时效为3天。
- 技术路线
- redis<key:value expire>
- 效率快,未来可能击穿中间件
- application hashSet
- 直接撑爆内存
- redis : bloom f
- 按照日期构造bf,过去三天的时间作为bf_name
- 内存节省,效率快
- redis<key:value expire>
四、出租车大数据之某车牌是否在某块区域出现过
- 数据量
出租车数据40亿,存放于Hbase数据库中,Hbase数据库基于fusionInsight大数据集群由七台每台220.34G内存的高性能服务器组成。
- 业务
已有60天的A区域出租车运营数据,包括车牌号,GPS信息等。某司机B驾驶着一辆车牌号为X的车辆,登录平台,想要体验平台的热点预测功能(平台会根据以往的出租车运营信息,如果该车是新车,那么向司机提供更好的福利来吸引更多的司机使用该出租车智能预测平台)
- 个人任务
我需要能够快速判断出该出租车是否是新车,从而返回一个levels.给予其它业务调用。
-
技术路线
- hashSet (直观感受就是使用hashSet)
- outOfMemoryException
- google guava(Bloom f的想法)
- application 负载大;但是采用服务调用的方式,需要开发一个新的分布式系统,专门为这个业务服务,不划算。
- redis 4.0的bf
- 中间件形式使用,应用到redis cluster上
- 切割region,作为bf_name
- 切割time,作为bf_name
- hashSet (直观感受就是使用hashSet)
-
解决方案
- redis bf。
五、redis4.0拓展之bloomfilter
-
开源链接
https://github.com/RedisBloom
-
阅读源码
- contrib:是布隆过滤器的核心结构体、算法的实现
//error为设定的错误率 bloom->bpe=-ln(error)/(ln2)^2 //所需要的位数bits计算如下,dentries为该过滤器存放的entry数量的double类型,因为要涉及到double运算 bits = bloom->bits = (uint64_t)(dentries * bloom->bpe);
//hash algorithm murmurhash2
//数据的存放位置;#define BLOOM_CALLOC calloc //bytes=bits/8 //这里要注意,即buf的空间是由calloc函数实现,而不是redis中的redis_calloc bloom->bf = (unsigned char *)BLOOM_CALLOC(bloom->bytes, sizeof(unsigned char));
- src : redis module api
static int SBChain_AddLink(SBChain *chain, size_t size, double error_rate) { if (!chain->filters) { //过滤器指针由redis申请 chain->filters = RedisModule_Calloc(1, sizeof(*chain->filters)); } else { chain->filters = RedisModule_Realloc(chain->filters, sizeof(*chain->filters) * (chain->nfilters + 1)); } SBLink *newlink = chain->filters + chain->nfilters; newlink->size = 0; chain->nfilters++; return bloom_init(&newlink->inner, size, error_rate, chain->options); } //sb是布隆过滤器链表,由多个布隆过滤器组成 void SBChain_Free(SBChain *sb) { for (size_t ii = 0; ii < sb->nfilters; ++ii) { //1、free每个过滤器内部的元素 bloom_free(&sb->filters[ii].inner); } //2、由redis释放该布隆过滤器的指针 RedisModule_Free(sb->filters); //3、释放链 RedisModule_Free(sb); }
-
源码阅读总结:
- redis分配给bloomfilter的只是过滤器链节点的空间,实际存储bits的空间由bloomf自己申请。
- bloomf只是使用了redis的API实现了网络通信、链节点内存管理,redis无法查看bf的数据存储情况,但是它通过每个bf的名字来构造一个< key:data >,它只能通过key来释放这个链节点,但是无法进行其它操作。因此,如果我们强行get bf_name,就会报类型错误。但是del bf_name是可行的,它会释放链节点,并且释放链节点的内联数据。
- bloomf哈希算法采用了murmurhash2,并且,至少为1000节点以上,否则会默认申请1000.错误率推荐在0.001这个粒度。
注:google guava中也有bloom filter的实现,是应用层的,而redis bloom是中间件的形式。