问题:
最近处理公司某系统的日志,但是日志文件太多,而且量很大(使用 du -sh查看了一下有几百G),直接一次性将全部日志数据处理完会导致服务器负载很高,内存几乎被吃光了,进程经常被管理员kill
处理方法:
采用分天处理文件,然后将当前的和前一天的文件合并的方法,大大提供了程序效率,而且降低了内存占用。涉及到的关键代码就是文件合并,使用归并算法来将文件合并
实现思路:
1、首先从日志里面分天提取需要要的数据,并排序输出到文件,因为归并算法处理的是两个已排好序的数据结
2、然后将当前天的日志和前一天的日志合并。file_old代表前一天合并后的日志数据文件 ,file_today代表提取出来的前一天日志数据文件 、file_merge代表合并后的当前日志数据文件 ,也就是要将当天的日志文件和前一天合并后的日志文件进行合并,并输出到file_merge作为下一个迭代的输入。
3、归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。
主要步骤:a、两个指针x , y,分别指向两个已排序的序列的开头
b、比较两个指针所指向的元素x ,y ,选择相对小的元素放入到合并空间,并移动指针到下一位置
c、重复步骤3直到某一指针超出序列尾
d、将另一序列剩下的所有元素直接复制到合并序列尾
下面的代码假设提取出来的数据是以空格分隔的,每一行的第一个数据是关键字key,用作排序的,如果关键字相同,则根据业务逻辑合并这一行。第20行的 mergeLine(old,today) 是key相同的时候根据业务逻辑处理数据的方法,可以根据自己的需求写。
文件归并算法代码:
def mergeFile(file_old,file_today,file_merge):
fp_old = open(file_old,"r")
fp_today = open(file_today,"r")
fp_merge = open(file_merge,"w")
old_line = fp_old.readline()
today_line = fp_today.readline()
while old_line and today_line:
old = old_line.strip().split()
today = today_line.strip().split()
if old[0] < today[0]:
fp_merge.write(old_line)
old_line = fp_old.readline()
elif old[0] > today[0]:
fp_merge.write(today_line)
today_line = fp_today.readline()
else:
megre_line = mergeLine(old,today)
fp_merge.write(megre_line)
old_line = fp_old.readline()
today_line = fp_today.readline()
continue
if old_line:
fp_merge.write(old_line)
for line in fp_old:
fp_merge.write(line)
if today_line:
fp_merge.write(today_line)
for line in fp_today:
fp_merge.write(line)
fp_merge.close()
fp_old.close()
fp_today.close()
这里采用 readline 逐行读取文件,一行一行处理,这样占用内存很低。
由于每天的日志数据文件小的也有1G,大的有4、5G,直接使用readlines()读取全部文件会吃很多内存。
也可以使用linecache.getlines 将文件读入缓存,然后使用 linecache.getline(i) 来读取指定行。