我想解析apache访问日志wrt IP。我使用了以下代码,但花了将近 90 秒。
grep "^$CLIENT_IP" /var/log/http/access.log > /tmp/access-$CLIENT_IP.log
然后我尝试了如下替代方法。
sed -i -e "/^$CLIENT_IP/w /tmp/access-$CLIENT_IP.log" -e '//d' /var/log/http/access.log
甚至这也花了 60 多秒。
有 1200 个 IP 需要解析。我想知道有什么方法可以实现并行性以减少运行时间。
我假设您在所有 IP 地址的 shell 循环中执行此操作,可能 IP 地址来自文本文件。是的,这会很慢,一次调用
sed
或grep
每个 IP 地址。sed
相反,如果您仔细准备,您可能会一次使用.首先,我们必须创建一个
sed
脚本,我们从一个ip.list
包含 IP 地址的文件中执行此操作,每行一个地址:这个
sed
东西,对于每个IP地址,sed
)。.
为\.
(为了正确匹配点,您的代码没有这样做)。^
和附加[[:blank:]]/w /tmp/access-
到模式空间。.log
到行尾(并隐式输出结果)。对于包含
这将创建
sed
脚本请注意,您必须在 IP 地址后匹配一个空白字符(空格或制表符),否则日志条目
10.0.0.100
将进入/tmp/access-10.0.0.1.log
文件。您的代码省略了这一点。然后可以在您的日志文件上使用它(无循环):
我从未测试过从同一个
sed
脚本写入 1200 个文件。如果它不起作用,请尝试以下awk
变体。一个类似的解决方案
awk
涉及首先将 IP 地址读入一个数组,然后将它们与每一行进行匹配。这需要一次awk
调用:在这里,我们
awk
同时给出 IP 列表和日志文件。当NR == FNR
我们知道我们仍在读取第一个文件(列表)时,我们将 IP 编号list
作为键添加到关联数组中,然后继续下一行输入。如果
FNR == NR
条件不成立,我们将从第二个文件(日志文件)中读取,并测试输入行的第一个字段是否是一个键list
(这是一个纯字符串比较,而不是正则表达式匹配) . 如果是,我们将该行附加到适当命名的文件中。我们必须小心关闭输出文件,否则我们可能会用完打开的文件描述符。所以会有很多打开和关闭文件用于追加,但它仍然比
awk
每个 IP 地址调用(或任何实用程序)一次要快。我很想知道这些东西是否适合您以及大概的运行时间可能是多少。我只在极小的数据集上测试了这些解决方案。
grep
当然,我们可以接受您的想法,即通过在系统上并行抛出 eg 的多个实例来强制它:忽略我们没有正确匹配 IP 地址中的点的事实,我们可能会像这样
在这里,
xargs
一次最多将 100 个 IP 地址从ip.list
文件提供给一个简短的 shell 脚本。它将安排脚本的四个并行调用。简短的 shell 脚本:
这只会遍历
xargs
在其命令行上提供它的 100 个 IP 地址,并应用与您拥有的几乎相同的grep
命令,不同之处在于将有四个这样的循环并行运行。增加或
-P 4
与-P 16
您拥有的 CPU 数量相关。加速可能不是线性的,因为每个并行实例grep
都会从同一个磁盘读取和写入。除了
-P
标志 toxargs
,这个答案中的所有东西都应该能够在任何 POSIX 系统上运行。for的-P
标志xargs
是非标准的,但在 GNUxargs
和 BSD 系统中实现。对于各种方法: https ://stackoverflow.com/questions/9066609/fastest-possible-grep
除此之外,如果您经常这样做,那么 SSD 可能是您的最佳选择。触摸高清是此类事情的杀手锏。
您有大量不同的 grep 需要运行。制作一个脚本,将脚本命令(例如,每个核心一个)启动到后台,然后跟踪它们何时完成,因为它们已经完成了更多的启动。
当我这样做时,我可以让所有 12 个内核以 100% 的 CPU 使用率运行,但你可能会发现你的资源限制是别的东西。鉴于您的所有工作都需要相同的文件,如果您不在 SSD 上,您可能希望复制该文件,以免它们共享。
如果
/var/log/http/access.log
大于 RAM 并因此无法缓存,那么并行运行更多进程可能是access.log
多次读取的一个很好的替代方案 - 特别是如果您有多个内核。这将为grep
每个 IP 并行运行一个(+ 几个帮助包装过程)。