配景
md5是不行解密的. 凡是网站http://www.cmd5.com/宣称的解密都是有一个MD5到值的映射数据库(彩虹表).
做法是提前将数据用MD5加密,然后生存成MD5到原数据的映射干系,解密时只要查询MD5对应的值就可以了.
业务数据快要1000亿,估算下来或许占用6T. 由于MD5的数据是32位,并且每一位都属于0-f.
假如直接查询生成的6T数据,速度预计很慢. 于是想到分区, 好比以32位MD5的前几位沟通的作为一个分区,
查询时首先将MD5路由到指定的分区, 再查询这个分区的所有数据,这样每个分区的数据量就会少许多.
原始文件data.txt(最后两个字段暗示MD5的前四位):
111111111111111,001e5a2b1c68d7b7dddddddddddddddc,00,1e 222222222222222,01271cc012464ae8ccccccccccccccce,01,27
Hive分区(×)
姑且表和分区表:
CREATE EXTERNAL TABLE `mob_mdf_tmp`( `mob` string, `mdf` string, `mdf_1` string, `mdf_2` string ) ROW FORMAT delimited fields terminated by ',' LOCATION 'hdfs://tdhdfs/user/tongdun/mob_mdf_tmp'; CREATE EXTERNAL TABLE `mob_mdf`( `mob` string, `mdf` string ) PARTITIONED BY ( mdf_1 string, mdf_2 string) stored as parquet LOCATION 'hdfs://tdhdfs/user/tongdun/mob_mdf';
将原始文件导入到姑且表(可能用hive的load呼吁),然后读取姑且表,加载数据到分区表
#!/bin/sh file=$1 /usr/install/hadoop/bin/hadoop fs -put $file /user/tongdun/mod_mdf_tmp #LOAD DATA LOCAL INPATH 'id.txt' INTO TABLE id_mdf PARTITION(mdf_1='ab',mdf_2='cd'); #LOAD DATA LOCAL INPATH 'id.txt' INTO TABLE id_mdf_tmp; /usr/install/apache-hive/bin/hive -e " set hive.exec.dynamic.partition=true; set hive.exec.dynamic.partition.mode=nonstrict; SET hive.exec.max.dynamic.partitions=100000; SET hive.exec.max.dynamic.partitions.pernode=100000; set mapreduce.map.memory.mb=5120; set mapreduce.reduce.memory.mb=5120; INSERT into TABLE mod_mdf PARTITION (mdf_1,mdf_2) SELECT mod,mdf,mdf_1,mdf_2 FROM mod_mdf_tmp; msck repair table mod_mdf; "
问题:将原始文件导入到HDFS是很快的,基天职分钟搞定.可是转换身分区的Hive表,速度起慢无比. %><%
AWK剧本处理惩罚分区
A.原始文件首先拆分成一级文件,再拆分成二级文件(×)
一级拆分: awk -F, ‘{print >> $3}’ data.txt
上面的awk呼吁会凭据第三列即MD5的前两个字符分组生成差异的文件. 好比生成00,01文件.
然后举办二级拆分: 遍历所有的一级文件, 生成二级文件. 好比001e.txt, 0127.txt.
nums=('0' '1' '2' '3' '4' '5' '6' '7' '8' '9' 'a' 'b' 'c' 'd' 'e' 'f') for n1 in ${nums[@]}; do for n2 in ${nums[@]}; do var=$n1$n2 awk -F, '{OFS=",";print $1,$2 >> $3_$4".txt"}' $var done done echo "end."
缺点: 每个数据文件都必需在本身的范畴内生成一级文件, 然后在本身的一级文件基本上生成二级文件.
最后所有的二级文件要归并为一个文件. 较量贫苦, %><%
B.原始文件直接生成两级拆分文件
直接拆分成两级的: awk -F, ‘{OFS=”,”;print $1,$2 >> $3_$4″.txt”}’ data.txt
利益: 由于有多个原始数据文件, 执行同样的awk呼吁, 生成最终功效不需要任那里理惩罚.
问题: 大文件分组,速度较量慢,并且不像上面的分成两次,0000.txt文件并不会立即有数据生成.
同样尚有一个问题: 假如多个文件一起追加>>数据, 会发生斗嘴,即写到同一行.
C.切分原始大文件(×)
对原始大文件(20G~100G)先split: split -C 2014m $file,再举办上面的二级拆分进程.
功效: 27G切分成2G一个文件, 耗时538s. 估算6T数据需要500h~20D. %><%
paldb@linkedin(×)
linkedin开源的paldb声称对付写一次的kv存储读取机能很好. 可是一个严重的问题是不支持在已有的db文件中新增数据.
Can you open a store for writing subsequent times?
No, the final binary file is created when StoreWriter.close() is called.
所以要读取所有的原始文件后,不能一个一个文件地处理惩罚. 这期间StoreWriter要一直打开,下面是索引文件的代码:
//直接读取所有原始文件, 生成paldb public static void indexRawFile(String[] files) throws Exception{ List<String> prefix = generateFile(); //提前筹备好Writer Map<String,StoreWriter> maps = new HashMap(); for(String pref : prefix){ StoreWriter writer = PalDB.createWriter(new File(folder + pref + ".paldb")); maps.put(pref, writer); } for(String filepath : files){ File file = new File(folder + filepath); BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(fis,"utf-8"),5*1024*1024);// 用5M的缓冲读取文本文件 String line = ""; while((line = reader.readLine()) != null){ String[] data = line.split(","); //按照前两位, 确定要利用哪个Writer. 沟通2位前缀的记录写到同一个db文件里 String prefData = data[2]; maps.get(prefData).put(data[1], data[0]); } fis.close(); reader.close(); } for (Map.Entry<String, StoreWriter> entry : maps.entrySet()) { entry.getValue().close(); } }