原文地址:http://52sox.com/use-mongodb-...在项目开发的过程中,总是离不开日志分析,虽然有时候比较麻烦,但是当你静下心来,你会发现,有时候也是一件很有趣的事情。这里我们需要从日志文件中找出访问IP最多的10条记录,然后判断是否合法,从而采取相应的措施。日志解析流程一般情况下,Nginx日志解析的流程如下:一般情况下,我们会提前对需要解析的日志进行划分,常见的方式是按照日期保存一周的日志。那么下一步就是分析日志了。在这个过程中,会用到一些工具或者编程语言,比如awk、grep、perl、python。最终的入库和可视化处理一般视业务而定,没有强制要求。日志查询的解决方案Nginx日志解析常见的解决方案主要有以下四种方式:通过awk和grep进行解析;通过Postgresql外部表映射日志;通过ELK结合Python和MongoDB查询日志,一个开源套件查询Postgresql外部表的方式,在之前的公司一直使用。当然是处理公司里多条3GB的日志。第一种和第四种方案实践经验不多,这里主要看第二种方案。日志格式关于日志的解析和处理,我们常用的方法是使用正则表达式进行匹配,常用的库是nginxparser,我们可以直接通过pip安装。当然还有其他的方式来分析,这个要看业务。在日志解析中,日志的格式更为重要。默认情况下,Nginx的日志格式如下:log_formatmain'$remote_addr-$remote_user[$time_local]"$request"''$status$body_bytes_sent"$http_referer"''"$http_user_agent""$http_x_forwarded_for"''$upstream_addr$upstream_response_time$request_time;下面来看一个实际业务中的应用。之前公司有微信抢红包活动,当然也有用户反映好几天都抢不到红包了。因此,我们的团队成员认为这个过程中可能存在作弊行为,于是我们决定对Nginx日志进行分析。详情请点击优化微信红包抢购系统。这是一条真实的日志记录:101.226.89.14--[10/Jul/2016:07:28:32+0800]"GET/pocketmoney-2016-XiKXCpCK.htmlHTTP/1.1"302231"-""Mozilla/5.0(Linux;Android5.1;OPPOR9tmBuild/LMY47I)AppleWebKit/537.36(KHTML,likeGecko)Version/4.0Chrome/37.0.0.0MobileMQQBrowser/6.2TBS/036548Safari/537.36MicroMessenger/6.3.22.821NetType/WILanguage/zh_CN》日志分析通过awk解析接下来我们看看如何使用awk解析出IP访问次数最多的记录。awk语法可以参考学习:dog@dog-pc:~$awk'{a[$1]++}END{for(iina)printi,a[i]}'nginx.log|sort-t''-k2-rn|head-n10111.167.50.20826794183.28.6.14316244118.76.216.77956014.148.114.2133609183.50.96.1273377220.115.235.213246222.84.160.2492905121.42.0.16221214.208.240.200200014.17.37.1431993Bydefault,awk默认以远程格式作为分隔符到Ngin$。这里,我们定义一个字段,使用IP作为键名,如果对应的键名存在,则数字加1。最后我们遍历字典,按数量排序,最后按head得到10条记录。当然这种操作方式有很大的误差,因为我们没有指定状态码等其他条件,我们看一下根据状态码和请求方式这两个条件筛选出来的数据:dog@dog-pc:~$awk'{if($9>0&&$9==200&&substr($6,2)=="GET")a[$1]++}END{for(iina)printi,a[i]}'nginx.log|sort-t''-k2-rn|head-n10222.84.160.2492856183.28.6.1432534116.1.127.110162514.208.240.200152114.17.37.1431335219.133.40.131014219.133.40.1599414.17.37.14498814.17.37.161960183.61.51.195944这样我们就可以分析这10个IP,考虑下一步,比如通过iptables的组合,禁止该IP的访问或者限制访问次数。通过Postgresql进入数据库后使用SQL通过Postgresql查询的方法可以通过下面两张图查看:上图中主要是查看日志中请求状态码的总数。下图是筛选前10个状态码为200的IP:可以看出和上面的awk分析方法基本一致。通过MongoDB查询我们知道MongoDB是一个文档数据库。通过这个数据库,我们可以辅助解决一些关系型数据库不太擅长的工作。在Python中,主要的MongoDB客户端驱动是PyMongo,我们可以通过以下方式建立连接:In[1]:frompymongoimportMongoClientIn[2]:client=MongoClient()由于我们使用的是默认端口和地址,所以MongoClient类中没有传递任何参数。这里先说一下我们插入MongoDB的日志格式:{"status":302,//HTTP状态码"addr":"101.226.89.14",//远程IP地址"url":"-","req":"/pocketmoney-2016-XiCXCpCK.html",//请求地址"agent":"Mozilla/5.0(Linux;Android5.1;OPPOR9tmBuild/LMY47I)AppleWebKit/537.36(KHTML,likeGecko)Version/4.0Chrome/37.0.0.0MobileMQQBrowser/6.2TBS/036548Safari/537.36MicroMessenger/6.3.22.821NetType/WIFILanguage/zh_CN,//requesteduser-agent"referer":"NetType/WIFI","t":"2016/07/1006:28:32",//请求时间"size":231,//响应大小"method":"GET",//请求方式"user":"-"//用户名}这里我们通过Python解析后,组装成上面的格式,插入到MongoDB中。这里主要使用MongoDB文档对象的insert_one方法插入一条记录。db=client['log']col=db['nginx']data={}...col.insert_one(data)然后我们开始查询上面的记录,主要是通过MongoDB提供的map-reduce实现聚合操作,其对应的Python代码为:In[3]:db=client['log']In[4]:col=db['nginx']In[5]:pipeline=[...:{"$match":{"status":200}},...:{"$group":{"_id":"$addr","count":{"$sum":1}}},...:{"$sort":{"count":-1}},...:{"$limit":10}...:]In[6]:list(col.aggregate(pipeline))Out[6]:[{u'_id':u'222.84.160.249',u'count':2856},{u'_id':u'183.28.6.143',u'count':2534},{u'_id':u'116.1.127.110',u'count':1625},{u'_id':u'14.208.240.200',u'count':1521},{u'_id':u'14.17.37.143',u'count':1335},{u'_id':u'219.133.40.13',u'count':1014},{u'_id':u'219.133.40.15',u'count':994},{u'_id':u'14.17.37.144',u'count':988},{u'_id':u'14.17.37.161',u'count':960},{u'_id':u'183.61.51.195',u'count':944}]可以看出这个过程和前面两种方法得到的结果是一致的。关于可视化处理关于可视化处理,我们可以选择一些Javascript库,例如:百度的Echartsd3.js及其派生库。对于Python来说,可视化处理可以使用以下库:matplotlibpandas当然还有一些其他的库,这里一一介绍。下面是百度Echart画的界面:还是挺好看的。参考文章:http://api.mongodb.com/python...
