先谈下我们需求,一个比较大的nginx访问日志,根据访问日期切割日志,保存在/tmp目录下。

测试机器为腾讯云机子,单核1G内存。测试日志大小80M。

不使用多线程版:

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. import re
  5. import datetime
  6.  
  7. if __name__ == '__main__':
  8. date_pattern = re.compile(r'\[(\d+)\/(\w+)\/(\d+):')
  9. with open('./access_all.log-20161227') as f:
  10. for line in f:
  11. day, mon, year = re.search(date_pattern, line).groups()
  12. mon = datetime.datetime.strptime(mon, '%b').month
  13. log_file = '/tmp/%s-%s-%s' % (year, mon, day)
  14. with open(log_file, 'a+') as f:
  15. f.write(line)

耗时:

  1. [root@VM_255_164_centos data_parse]# time python3 log_cut.py
  2. real 0m41.152s
  3. user 0m32.578s
  4. sys 0m6.046s

多线程版:

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. import re
  5. import datetime
  6. import threading
  7.  
  8. date_pattern = re.compile(r'\[(\d+)\/(\w+)\/(\d+):')
  9.  
  10. def log_cut(line):
  11. day, mon, year = re.search(date_pattern, line).groups()
  12. mon = datetime.datetime.strptime(mon, '%b').month
  13. log_file = '/tmp/%s-%s-%s' % (year, mon, day)
  14. with open(log_file, 'a+') as f:
  15. f.write(line)
  16.  
  17. if __name__ == '__main__':
  18. with open('./access_all.log-20161227') as f:
  19. for line in f:
  20. t = threading.Thread(target=log_cut, args=(line,))
  21. t.setDaemon(True)
  22. t.start()

耗时:

  1. # time python3 log_cut.py
  2.  
  3. real 1m35.905s
  4. user 1m10.292s
  5. sys 0m19.666s

使用多线程版竟然比不使用多进程版要慢的多。。cpu密集型任务使用上下文切换果然很耗时。

线程池版:

线程池类

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. import queue
  5. import threading
  6. import contextlib
  7. import time
  8.  
  9. StopEvent = object()
  10.  
  11. class ThreadPool(object):
  12.  
  13. def __init__(self, max_num, max_task_num = None):
  14. if max_task_num:
  15. self.q = queue.Queue(max_task_num)
  16. else:
  17. self.q = queue.Queue()
  18. self.max_num = max_num
  19. self.cancel = False
  20. self.terminal = False
  21. self.generate_list = []
  22. self.free_list = []
  23.  
  24. def run(self, func, args, callback=None):
  25. if self.cancel:
  26. return
  27. if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
  28. self.generate_thread()
  29. w = (func, args, callback,)
  30. self.q.put(w)
  31.  
  32. def generate_thread(self):
  33. t = threading.Thread(target=self.call)
  34. t.start()
  35.  
  36. def call(self):
  37. current_thread = threading.currentThread()
  38. self.generate_list.append(current_thread)
  39.  
  40. event = self.q.get()
  41. while event != StopEvent:
  42.  
  43. func, arguments, callback = event
  44. try:
  45. result = func(*arguments)
  46. success = True
  47. except Exception as e:
  48. success = False
  49. result = None
  50.  
  51. if callback is not None:
  52. try:
  53. callback(success, result)
  54. except Exception as e:
  55. pass
  56.  
  57. with self.worker_state(self.free_list, current_thread):
  58. if self.terminal:
  59. event = StopEvent
  60. else:
  61. event = self.q.get()
  62. else:
  63. self.generate_list.remove(current_thread)
  64.  
  65. def close(self):
  66. self.cancel = True
  67. full_size = len(self.generate_list)
  68. while full_size:
  69. self.q.put(StopEvent) #
  70. full_size -= 1
  71.  
  72. def terminate(self):
  73. self.terminal = True
  74.  
  75. while self.generate_list:
  76. self.q.put(StopEvent)
  77.  
  78. self.q.queue.clear()
  79.  
  80. @contextlib.contextmanager
  81. def worker_state(self, state_list, worker_thread):
  82. state_list.append(worker_thread)
  83. try:
  84. yield
  85. finally:
  86. state_list.remove(worker_thread)

threadingPool.py

代码

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. import re
  5. import datetime
  6. from threadingPool import ThreadPool
  7.  
  8. date_pattern = re.compile(r'\[(\d+)\/(\w+)\/(\d+)\:')
  9.  
  10. def log_cut(line):
  11. day, mon, year = date_pattern.search(line).groups()
  12. mon = datetime.datetime.strptime(mon, '%b').month
  13. log_file = '/tmp/%s-%s-%s' % (year, mon, day)
  14. with open(log_file, 'a+') as f:
  15. f.write(line)
  16.  
  17. def callback(status, result):
  18. pass
  19.  
  20. pool = ThreadPool(1)
  21.  
  22. with open('./access_all.log-20161227') as f:
  23. for line in f:
  24. pool.run(log_cut, (line,), callback)
  25.  
  26. pool.close()

耗时:

  1. # time python3 log_cut2.py
  2.  
  3. real 0m53.371s
  4. user 0m44.761s
  5. sys 0m5.600s

线程池版比多线程版要快,看来写的线程池类还是有用的。减少了上下文切换时间。

进程池版:

  1. #!/usr/bin/env python
  2. # coding=utf-8
  3.  
  4. import re
  5. import datetime
  6. from multiprocessing import Pool
  7.  
  8. date_pattern = re.compile(r'\[(\d+)\/(\w+)\/(\d+):')
  9.  
  10. def log_cut(line):
  11. day, mon, year = re.search(date_pattern, line).groups()
  12. mon = datetime.datetime.strptime(mon, '%b').month
  13. log_file = '/tmp/%s-%s-%s' % (year, mon, day)
  14. with open(log_file, 'a+') as f:
  15. f.write(line)
  16.  
  17. if __name__ == '__main__':
  18. pool = Pool(1)
  19. with open('./access_all.log-20161227') as f:
  20. for line in f:
  21. pool.apply_async(func=log_cut, args=(line,))
  22. pool.close()

单个进程耗时:

  1. # time python3 log_cut.py
  2.  
  3. real 0m28.392s
  4. user 0m23.451s
  5. sys 0m1.888s

2个进程耗时:

  1. # time python3 log_cut.py
  2.  
  3. real 0m40.920s
  4. user 0m33.690s
  5. sys 0m3.206s

看来使用多进程时,如果是单核cpu只开一个进程,多核cpu的话开多个速度更快,单核cpu开多个进程速度很慢。

shell版

  1. #!/bin/bash
  2.  
  3. Usage(){
  4. echo "Usage: $0 Logfile"
  5. }
  6.  
  7. if [ $# -eq ] ;then
  8. Usage
  9. exit
  10. else
  11. Log=$
  12. fi
  13.  
  14. date_log=$(mktemp)
  15.  
  16. cat $Log |awk -F'[ :]' '{print $5}'|awk -F'[' '{print $2}'|uniq > date_log
  17.  
  18. for i in `cat date_log`
  19. do
  20. grep $i $Log > /tmp/log/${i::}-${i::}-${i::}.access
  21.  
  22. done

耗时:

  1. # time sh log_cut.sh access_all.log-
  2.  
  3. real 0m2.435s
  4. user 0m2.042s
  5. sys 0m0.304s

shell的效果非常棒啊,只用2s多久完成了。

按日期切割nginx访问日志--及性能优化的更多相关文章

  1. 性能调优之访问日志IO性能优化

    性能调优之访问日志IO性能优化   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821 ...

  2. 访问日志IO性能优化

    在高并发量的场景下磁盘IO往往是性能的瓶颈所在,访问日志涉及到频繁的写操作,所以这部分要尽可能地优化,不然将拖累系统的整体性能.针对文件记录及数据库记录两种方式可以有以下措施提高写性能, l 避免频繁 ...

  3. 采集并分析Nginx访问日志

    日志服务支持通过数据接入向导配置采集Nginx日志,并自动创建索引和Nginx日志仪表盘,帮助您快速采集并分析Nginx日志. 许多个人站长选取了Nginx作为服务器搭建网站,在对网站访问情况进行分析 ...

  4. Nginx访问日志.Nginx日志切割

    11月27日任务 12.10 Nginx访问日志12.11 Nginx日志切割12.12 静态文件不记录日志和过期时间 1.Nginx访问日志 示例一: 日志格式 vim /usr/local/ngi ...

  5. Nginx 访问日志轮询切割

    Nginx 访问日志轮询切割脚本 #!/bin/sh Dateformat=`date +%Y%m%d` Basedir="/application/nginx" Nginxlog ...

  6. Nginx访问日志、 Nginx日志切割、静态文件不记录日志和过期时间

    1.Nginx访问日志 配制访问日志:默认定义格式: log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_loc ...

  7. Nginx访问日志、日志切割、静态文件不记录日志和过期时间

    6月8日任务 12.10 Nginx访问日志12.11 Nginx日志切割12.12 静态文件不记录日志和过期时间 12.10 Nginx访问日志 除了在主配置文件nginx.conf里定义日志格式外 ...

  8. Linux centosVMware Nginx访问日志、Nginx日志切割、静态文件不记录日志和过期时间

    一.Nginx访问日志 vim /usr/local/nginx/conf/nginx.conf //搜索log_format  日至格式 改为davery格式 $remote_addr  客户端IP ...

  9. nginx访问日志(access_log)

    一.nginx访问日志介绍 nginx软件会把每个用户访问网站的日志信息记录到指定的日志文件里,供网站提供者分析用户的浏览行为等,此功能由ngx_http_log_module模块负责,对应的官方地址 ...

随机推荐

  1. ADT - Eclipse 常用快捷键

    ADT - Eclipse 常用快捷键 Alt + / : 自动补全 F3 : 打开类的源码 Ctrl + D : 删除选中行 Ctrl + 1 : 自动弹出修改建议 Ctrl + Shift + J ...

  2. Android Weekly Notes Issue #226

    Android Weekly Issue #226 October 9th, 2016 Android Weekly Issue #226 本期内容包括: 用Firebase做A/B Test; 用R ...

  3. python基础(1) 变量类型

    变量赋值: python中的变量不需要类型声明 每个变量在使用前必须赋值,变量赋值以后才会被创建 变量在内存中创建时,包括变量的标识.名称和数据这些信息. EX: #!/usr/bin/python ...

  4. GCC 预处理、编译、汇编、链接..

    1简介 GCC 的意思也只是 GNU C Compiler 而已.经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言:它现在还支持 Ada 语言.C++ 语言.Java 语言.Objective ...

  5. Java中堆内存和栈内存详解2

    Java中堆内存和栈内存详解   Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,ja ...

  6. ambari2.4.2_centos7 学习全纪录

    目录: 为什么要用Ambari 概念概述 原理简介 安装 创建集群 创建集群 手动修改配置 NameNode HA 安装SmartSense 二次开发 为什么要用Ambari Ambari 是 Apa ...

  7. 前端HTML之页面结构

    前端工作一年了,期间由于工作需要,也做了一些产品的设计,因为自己的目标就是做编程,所以婉拒了与产品相关的一些任务,打算主要把精力放到编程这方面. PS:2015年1月进军编程行业. 废话不多讲,这一年 ...

  8. 解决ubuntu eclipse中 Android SDK Manager 图标不见的方法

    在eclipse中选择的步骤如下:   Window ---> Custom Perspective  --> command Group Availability ----> an ...

  9. java 线程池——异步任务

    一.简单粗暴的线程 最原始的方式,当我们要并行的或者异步的执行一个任务的时候,我们会直接使用启动一个线程的方式,如下面所示: new Thread(new Runnable() { @Override ...

  10. 【译】什么是 web 框架?

    Web 应用框架,或者简单的说是“Web 框架”,其实是建立 web 应用的一种方式.从简单的博客系统到复杂的富 AJAX 应用,web 上每个页面都是通过写代码来生成的.我发现很多人都热衷于学习 w ...