最近开发需要在linux服务器上做大数据处理,由于对Linux开发并不是很熟悉,因此踩了很多坑,先作如下记录:
1.bash shell实现多进程
背景如下:需要从hadoop的hdfs上向服务器下拉数据,共7200多个数据文件,每个文件约1G左右,共7T左右的数据。
单纯的我一开始写了个shell脚本文件然后开始拉数据,结果发现拉了一下午,也才下载了100多个文件。。。照此速度基本得拉倒天荒地老了。。。多核的机器得用起来啊,于是开始研究如何在bash shell中实现多进程同时拉数据。参考了一些教程,主要有以下三点技能需要get:
1.for 循环
2.后台运行符&
3.wait等待所有子进程结束
get到了这3点技能后,说干就干的我开始写出了如下的脚本代码:
#!/bin/bash
for((i=0;i<7252;i++));do
{
}&
done
wait
保存,运行~动作完美和谐,一气呵成。然而。。呵呵。。机器挂了。。。。世界陷入了一片死寂。。。
不明真相的我开始找运维。。运维说是机器背部电源板老化导致宕机。修复后重新登上机器,我又准备运行我的脚本,然而不出所料,机器再一次挂掉了。。。我觉得运维应该有杀了我全家的冲动。。。
此时的我终于意识到应该是我的脚本文件导致机器挂掉。于是开始仔细反思,在脚本中,我设定了循环中的变量从0到7151,后台运行符表明此段应该要后台并发执行,所以意味着我要同时开7252个进程去执行这段代码。。。再强大的机器也没这么多核。。。理解了多进程原理后,找到症结的我重新修改了代码:
#!/bin/bash
for((i=0;i<7252;i+=10));do
{
for((j=0;j<10;j++));do
{
index=$(expr $i + $j)
}&
done
wait
}
done
上面的代码中,每次同时开10个进程拉取10个文件,等这10个进程都拉取完毕后,再开10个进程拉取下一批10个文件,直到把所有的7252个文件拉取完毕。
总结这个坑,是因为对Linux多进程实现机制不了解所致,以后再写多进程脚本时,应该会吃一堑长一智了。
2.TAB的ascii码
写下这个小标题的时候我的内心是崩溃的,这种初学计算机的菜鸟都应该懂的知识,我一个在BAT互联网工作了两年的工程师居然都是后知后觉才Get到。
背景是这样的:
上面提到的这些数据都是SQL查询得到的表,我现在需要分析表中每行的记录,提取有用的信息。用fstream 的getline得到了一行string,接着理所当然地想去用string.find函数来查找空格,以此来分隔数据。然而发现find(” “)返回的结果为-1,即没有空格。然而我可没瞎,用Notepad打开文档后可是很整齐的数据表格式。此时的我内心如柯南遇到棘手的杀人案件一样,深深滴发出了疑问。。调试发现,该string中原本是空格的位置显示的是’9’,即ascii码是9,查ASCII表后发现,十进制数字9对应的是符号HT。。。HT是神马。。。敖!!!HT是TAB啊。。。我真是蠢死了~改代码为find(“\t”)后,成功对数据表进行了处理。。。
对于这个坑,我对我的无知已经无话可说~只能说,活到老学到老,思维要放宽阔。
3.多线程与多进程
每次上多线程与多进程学习的课程,讲师总会俗不可耐地提出如下疑问:多线程与多进程的区别是什么?答对了有小礼品赠送哦~星星眼~原来的我对这个问题答案的理解也只是停留在了概念阶段,比如,最核心的区别,应该就是多线程可以共享同一块内存,而多进程是程序运行实例的多个副本,是独立的,并不共享数据。这种概念性的东西讲起来头头是道,可是真正在实际工作中用起来,却并不那么顺手。
背景如下:我需要从这些数据表文件中,分析每行数据,提取每行数据的uin(类似于用户id之类的字段,约10亿量级),然后统计每个uin出现的次数。原理很简单,就是建一个hash map,然后依次读入每行数据,在每个uin对应的数值累加就可以了。然而不要忘记了这是大数据处理。如果一根筋的用一个线程(进程)依次统计这7252个文件(每个文件约百万行数据),那么估计等我被炒鱿鱼了都还没处理完。。。由于可用的服务器就一台,还是得考虑单机多核。
有了for循环多进程的知识,单纯的我又开始写起了shell脚本,同时开16个进程,每个进程统计约454(7252/16)个文件,然后把得到的结果写到对应的文件中,最后得到的这16个文件结果再合并起来,因为中间肯定有重复的uin。行云流水的写完代码后,脚本欢快地运行了起来,然而没过多久,一些进程就被kill了。。。原来是机器内存使用超过了99%,运维GG再一次出马了。。。
简直欲哭无泪,本来觉得很简单的一项工作实施起来备受阻碍。思考了一下,发现了问题所在:我在程序中开辟了map来做统计,如果开16个进程,相当于在这16个运行实例中都要开map,共有16个map,并且考虑最坏情况,如果我每个进程统计的这454个文件中涵盖了所有的uin,那么我的每个进程都有一份这10亿uin的hash表,16个进程就是16个10亿份。。。系统内存不崩我都要崩了。。再次被自己的智商蠢哭。。。
所以说,为了只维护一份hash表,我应该实现的是多线程,而非多进程。。。这样,我每个线程中统计不同的文件,但所有线程共同维护一份map,统计的结果也只有一份。想通这一点后,开始改程序。linux下实现多线程的最便捷的方法就是pthread,只需如下几步
#include<pthread.h>
#include<unistd.h>
void *thread(void *arg)
{
return 0 ;
}
int main()
{
pthread_t id ;
int ret = pthread_create(&id, NULL, thread, NULL);
if(ret) {
cout << "Create pthread error!" << endl;
return 1;
}
pthread_join(id, NULL);
return 0;
}
其中,pthread_join很重要,他会在父进程中一直等到直到子进程结束后才退出,否则,不等子进程执行完,父进程就return了。
这个坑让我意识到,掌握多线程和多进程开发很有必要,而且很多概念应该要学会活学活用,更重要的是,在做事情之前要三思!三思!三思!
最后,贴一些最近用到的很有用的linux系统命令
wc -l a.txt 查看a.txt文档中的行数
查找所有空目录
find ./ -depth -empty -type d -type d为只找目录,不加则找出所有空目录和空文件
find ./ -depth -empty -type d -exec rmdir -v {} \;
统计文件夹下的文件数量
ls -l|grep “^-“|wc -l
统计文件夹下(包括子文件夹)的文件数量
ls -lR|grep “^-“|wc -l
统计文件夹下的文件夹数量
ls -l|grep “^d”|wc -l
df -h 查看挂载的硬盘信息
cat /proc/meminfo 或者 free 查看内存使用情况 或 剩余可用内存
CPU占用最多的前10个进程:
ps auxw|head -1;ps auxw|sort -rn -k3|head -10
内存消耗最多的前10个进程
ps auxw|head -1;ps auxw|sort -rn -k4|head -10
虚拟内存使用最多的前10个进程
ps auxw|head -1;ps auxw|sort -rn -k5|head -10
seq -f %06g 1 10 产生000001 000002 … 000010的数据序列
seq -f %06g 1 2 10 以2为步长,产生000001 000003 000005…000009的数据序列
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)