公司的实时报表系统采用 druid 作为查询引擎,阿里的一个开源项目。druid 也是目前比较快的引擎了。所以有时候一边走路一边就会想,这东西也是中国人做的啊,我能不能做一个比 druid 更快的引擎那,我也是中国人啊,也上过学的啊,所以慢慢的就有了下面的一些思考。不过又觉得自己的一些想法还是比较浅显的,所以一直没写下来,只是写到了记事本上,最近一些原因决定写下来,后续再慢慢的改,满满的补充。
首先,我自认为大数据分两块,一块是存储,一块是计算(实时计算是一边计算一边存储)。对存储来说,只要能分布式存储,这个问题基本就解决了。而数据格式是为了计算服务的。所以更高的追求应该在计算的速度上。那怎么样能更快点那?
首先想到的是,查询最多的是比较是否相等,而大部分的结果其实是不相等的,亦即排除的数据占大部分,于是想到可否先比较部分特征那?比如先比较字符串的哈希值,如果哈希值不相等,那待查字符串一定不是目标字符串,如果是哈希值一致,那么再去比较对象。显然比较哈希值这样的整数要比直接比较字符串快很多。
自己简单的做了测试(容量为100w个),比较相同个数的int值比比较相同个数的只含有几个字符的字符串快2到3倍。因为一旦哈希值相等,还要再比较字符串相等,所以这样效率会不会反而更低那?假设极端坏的情况,一组数据中有一半待查字符串和目标字符串是不相等的,效率按照一倍算,比较字符串的时间设为m,那么先比较哈希值再比较字符串的方法的时间为(1/2*1/2*m+1/2*1/2*m+1/2*m)=m,最坏的情况的是相等的,那一般的情况自然是好很多,已经碾压了,就不再讨论了。
再去看 druid 的存储结构。首先 druid 会把维度做成一个数据字典,比如 platform 的值可能为 android,ios,desktop 三个,那么字典就是用 1 代表 android,2代表ios,3代表 desktop,这样每一条记录只要存1,2,3就可以了。为了优化,又使用了bitmap,即android 有一个 bitmap 存储,某一行是android 就存1,不是就存0,所以android这个维度的bitmap是[1,0,0,1] ,ios对应的就可能是 [0,1,1,0] 说明第一、第四行识android,第二三行是ios。发现druid还是比较厉害的,因为用bitmap后就全部都是位操作,位操作的速度一定大于数字的比较速度,大于字符串的比较速度。
然后我又进行了对比,结果发现用bitmap的速度没有比对比数字快很多,也就快百分之几的样子(因为cpu时间片分配的问题,测试结果不稳定的,我都是实验很多次,大概观察结果,哈哈),然后就略失望。
试着分析其中的原因,觉得可能是因为实际操作的时候要用 int 这种数据结构去模拟位的集合,如果一位一位的顺序判断的话会涉及好多移位的操作,比如判断某一位是否为1要首先把1左移n位,然后跟这个int做与操作,所以自然想到不移位是不是就快了,那怎么办那?
比如一个int数组32位,低位第一位存储 android 的结果,第二位存储ios的结果,第三位存储desktop的结果,这样,判断哪些行是android只需要判断数组元素的第一位就可以了,就不需要再移位什么的了(完美)。这个方法的问题是会增加内存的消耗,因为每一个int只有一位是有效信息(当然用byte数组的话会好一些),不过事情都是平衡的,速度更快了,当然可以更快的释放内存了,内存的效率也不一定低太多。
现在反过头来看第一个想法,即比较字符串是否相等先比较哈希值是否相等,一定比bitmap的实现差么?有以下几点思考:1、放在更大的范围内去看这个问题,比如hive sql 其实就会生成很多的mr任务,join 啊,gruop by 啊 order by 啊什么的,比如join啊什么的其实更适合用hashcode去比较是否相等,而bitmap更适合gruop by啊什么的,所以各自适合的场景是不一样的。2、bitmap是有序的,而hashcode只是一个元素的部分特征,一旦要生成子集,比如sql的字查询,bitmap就不能再继续使用了,或者要重新生成一个bitmap,而hashcode则没有这个问题,可以直接跟着生成一个子集。3、一些计算本身就是需要用到哈希值的,比如求基数的 HLL估算法。
再放宽了看,其实不同的计算适合的数据结构是不同的,那怎么更好的利用这个特性那?我想到了数据备份,hdfs一般是三个备份,最重要的是三份数据都是在线上的环境的,也就是无差的,可以随时分配内存进行计算。那完全可以三份数据用不同的格式存储啊(完美),这样可以针对不同的计算选择使用其中的一个数据格式,增加并行度,而且不影响备份的特性,只要任何一份数据都可以完整的表达出原始数据就可以了。
所以总结一下,有三点:
- 比较字符串是否相等先比较哈希值是否相等
- 对bitMap改进,只在特定的第n位存储某一个元素的信息,比如用int数组实现,只在第1位存是否是android
- 分布式系统在存储的时候,每一份数据可以存储成不同格式的数据,计算的时候可以选择合适的那份数据,提高并发度。
以上,是我的一点点思考,浅薄至极,也欢迎指正讨论,谢谢~
也欢迎查看另一篇我想到的关于哈希一致性改进的文章 https://blog.csdn.net/songsts/article/details/83034072