使用ELK分析Nginx日志实践

安装好ELK后,可以分析Nginx的日志查看访问量,甚至可以根据ip地址解析出GPS信息,最后生成用户访问热力图,本文是基于ELK 5.6.3版本。

1.配置Nginx日志的Logstash文件

在logstash的config目录下

vim logstash.conf

添加:

input {
        file {
                path => ["/data/log/nginx/www_access.log"]
        }
}
filter {
        grok {
                match => { "message" => "%{IPORHOST:clientip} - - \[%{HTTPDATE:time}\] \"%{WORD:verb} %{URIPATHPARAM:request} HTTP/%{NUMBER:httpversion}\" %{NUMBER:http_status_code} %{NUMBER:bytes} \"%{GREEDYDATA:referrer}\" \"%{GREEDYDATA:agent}\" \"%{GREEDYDATA:xforwardedfor}\""}
        }
        geoip {
                source => "clientip"
                        target => "geoip"
                        # fields => ["city_name", "continent_code", "country_code2", "country_code3", "country_name", "ip", "latitude", "longitude", "postal_code", "region_name", "timezone"]
                        database => "/data/src/logstash/GeoLite2-City_20171107/GeoLite2-City.mmdb"
                        add_field => [ "[geoip][coordinates]", "%{[geoip][longitude]}" ]
                        add_field => [ "[geoip][coordinates]", "%{[geoip][latitude]}"  ]
        }
        mutate {
                convert => [ "[geoip][coordinates]", "float"]
        }
}
output {
        stdout { codec => rubydebug }
        elasticsearch {
                hosts  => "127.0.0.1:9200"
                        index  => "logstash-nginx-%{+YYYY.MM.dd}"
        }
}

重点说明:

以上的配置中input下的file是Nginx的access文件。

下面filter的grok的match里的规则对应的是Nginx默认配置的日志格式,一般来说Nginx的配置文件里access日志后面加上main,下面的geoip是用来将IP地址解析成GPS信息,database是在 https://dev.maxmind.com/geoip/geoip2/geolite2/ 下载的,选择的是GeoLite2 City MaxMind DB binary gzipped,解压后将数据库mmdb格式的地址写入。

最后的output里将elasticsearch的地址写入,值得注意的是index一定要logstash打头,否则后面使用Kibana做用户访问热力图的时候会报错“No Compatible Fields: The “[nginx-access-]YYYY-MM-dd” index pattern does not contain any of the following field types: geo_point”,原因是索引格式为[nginx-access-]YYYY-MM-dd的日志文件由logstash输出到Elasticsearch;在Elasticsearch中,所有的数据都有一个类型,什么样的类型,就可以在其上做一些对应类型的特殊操作。geo信息中的location字段是经纬度,我们需要使用经纬度来定位地理位置;在Elasticsearch中,对于经纬度来说,要想使用Elasticsearch提供的地理位置查询相关的功能,就需要构造一个结构,并且将其类型属性设置为geo_point,此错误明显是由于我们的geo的location字段类型不是geo_point。

2.Kibana配置Index Patterns

到Kibana选择Management->选择Index Patterns->点击Create Index Pattern按钮->在Index pattern的输入框输入logstash-nginx-*

3.Kibana配置地图

Visualize->New->选择Maps下的Coordinate Map->选择刚刚配置的logstash-nginx-*->点击Geo Coordinates->Field选择geoip.location->点击“播放键”apply changes

最后结果:

ELK安装和实践

今年博主转战创业公司,随着系统的稳定和访问量的提升,急需一个在线的日志分析系统提供帮助,业界最知名的当属ELK了。架设这套体系的目的有三个:

1. 收集多台服务器上的日志信息,不需要上不同的服务器查看日志,方便分析处理问题。

2. 可视化界面方便搜索关键词和日志类型,处理潜在的bug。

3. 分析Nginx的访问量,是数据说话,让整个系统的运行情况了然于胸。
不多说了,直接切入正题

1. 安装Elasticsearch

下载最新的Elasticsearch tar包

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.6.3.tar.gz

解压

tar zxvf elasticsearch-5.6.3.tar.gz

进入解压后目录

cd elasticsearch-5.6.3

如果想要设置其他服务器访问,需要修改配置,将network.host修改为本机的外网或内网ip地址,如果只要用127.0.0.1就略过

vim config/elasticsearch.yml

启动Elasticsearch

bin/elasticsearch -d

2. 安装Logstash

下载最新的logstash tar包

wget https://artifacts.elastic.co/downloads/logstash/logstash-5.6.3.tar.gz

解压

tar zxvf logstash-5.6.3.tar.gz

进入解压后目录

cd logstash-5.6.3

增加配置

vim config/logstash.conf

添加:

input {
        tcp {
                mode => "server"
                host => "localhost"
                port => 4567 
                codec => multiline {
                        pattern => "^\t"                                
                        what => "previous"
                }       
        }
}
filter {
        grok {
                match => { "message" => "%{TIMESTAMP_ISO8601:time} \[%{GREEDYDATA:thread}\] \[%{GREEDYDATA:id}\] \[%{GREEDYDATA:id2}\] %{LOGLEVEL:loglevel} %{JAVACLASS:class}(\s-\s%{GREEDYDATA:info})?"}
        }
}
output {
        stdout { codec => rubydebug }
        elasticsearch {
                hosts  => "127.0.0.1:9200"
                index => "logstash-platform-%{+YYYY.MM.dd}"
        }
}

说明:以上的配置中input下的tcp是根据log4j里配置写的,在我们的JAVA工程里log4j的配置文件部分内容如下:

<Appenders>
    <!-- 日志输出到logstash -->
    <Socket name="LogStash" host="localhost" port="4567">
        <PatternLayout pattern="%d [%t] [%X{X-UUID}] [X-UID-%X{X-UID}] %-5level %logger - %msg%n" />
    </Socket>
</Appenders>
<Loggers>
    <Root level="DEBUG">
        <AppenderRef ref="Console"/>
        <AppenderRef ref="LogStash"/>
    </Root>
</Loggers>

以上XML中的host和port就对应了logstash配置中的host和port。

codec的multiline的作用是为了将exception报错输出的内容合并到一行去,即如果是以制表符\t开头的一行输入内容都连接到上一行(previous)。

filter中的grok用与匹配输入的message并做文本的截取,这里面是正则表达式,大家可以到 http://grokdebug.herokuapp.com/ 调试自己的match规则。

output里面hosts就是elasticsearch的http地址,index是logstash在elasticsearch里面创建的索引的名字,它的默认值是”logstash-%{+YYYY.MM.dd}”,我把它配置成了”logstash-platform-%{+YYYY.MM.dd}”目的是跟nginx拉过来的日志做个区分。
如果有什么问题建议大家查阅logstash官方文档,很容易理解。

最后启动logstash

nohup bin/logstash -f config/logstash.conf & > /dev/null

3. 安装Kibana

下载最新的Kibana tar包

wget https://artifacts.elastic.co/downloads/kibana/kibana-5.6.3-linux-x86_64.tar.gz

解压

tar zxvf kibana-5.6.3-linux-x86_64.tar.gz

进入解压后目录

cd kibana-5.6.3-linux-x86_64

修改配置,将elasticsearch.url改为上面安装的elasticsearch的地址

vim config/kibana.yml

启动kibana

nohup bin/kibana & > /dev/null

4. 给kibana增加登录认证

centos需要运行htpassword,先安装httpd-tools

sudo yum install -y httpd-tools

给admin这个用户设置密码

sudo htpasswd -c /data/nginx/.htpasswd admin

最后配置nginx反向代理,这里就不说了。
随着JAVA的工程启动,会忘logstash写入日志信息,这时候可以通过

curl -XGET 127.0.0.1:9200/_cat/indices

查看是否存在logstash-platform开头的索引生成。如果不正常,可以去logstash目录下的logs去查看什么原因。正常就打开Kibana,配置index pattern为logstash-platform*。

搞定后大家就可以自己去把玩Kibana发掘下它的牛逼之处了!

解决python 3.6 from http.client import HTTPSConnection ImportError: cannot import name ‘HTTPSConnection’的方法

我今天在用python3.6的时候出现了报错

from http.client import HTTPSConnection ImportError: cannot import name 'HTTPSConnection'

后来查看了python 3.6的client.py的源码和查阅了一些资料后,发现是我服务器没有安装ssl的问题。

rpm -aq|grep openssl
yum install openssl-devel -y
rpm -aq|grep openssl

然后重新编译安装python 3.6

./configure --with-ssl --enable-optimizations
make
make install

然后就ok啦!

CentOS 6.7下安装vsftpd FTP服务器经验

最近Wordpress从虚拟主机迁移到了VPS上,原来虚拟主机服务商有提供FTP,现在VPS需要自己安装一个FTP服务器来支持Wordpress的插件和主题升级。vsftpd是Linux下比较著名的FTP服务器,我选择它搭建FTP服务器。

 

第一步:安装vsftpd

查看你的服务器是否已经安装vsftpd

rpm -qa | grep vsftpd

如果已经安装就略过下一步yum安装。如果没有安装过就执行以下命令:

yum -y install vsftpd

 

第二步:基于虚拟用户的配置

所谓虚拟用户就是没有使用真实的帐户,只是通过映射到真实帐户和设置权限的目的。虚拟用户不能登录CentOS系统。

1. 修改配置文件

打开/etc/vsftpd/vsftpd.conf,修改该文件原来的配置,如下(这里需要一个一个项目在编辑器里查找并修改,注意YES或NO等配置项后面不要在复制过程中多出不必要的空格):

#设定不允许匿名访问
anonymous_enable=NO

#设定本地用户可以访问。注:如使用虚拟宿主用户,在该项目设定为NO的情况下所有虚拟用户将无法访问
local_enable=YES

#使用户不能离开主目录
chroot_list_enable=YES

ascii_upload_enable=YES

#设定支持ASCII模式的上传和下载功能
ascii_download_enable=YES

#PAM认证文件名。PAM将根据/etc/pam.d/vsftpd进行认证
pam_service_name=vsftpd

以下这些是关于vsftpd虚拟用户支持的重要配置项,默认vsftpd.conf中不包含这些设定项目,需要自己手动添加到/etc/vsftpd/vsftpd.conf中:

#设定启用虚拟用户功能
guest_enable=YES

#指定虚拟用户的宿主用户,CentOS中已经有内置的ftp用户了
guest_username=ftp

#设定虚拟用户个人vsftp的CentOS FTP服务文件存放路径。存放虚拟用户个性的CentOS FTP服务文件(配置文件名=虚拟用户名
user_config_dir=/etc/vsftpd/vuser_conf

 

2. 进行认证

首先,安装Berkeley DB工具,很多人找不到db_load的问题就是没有安装这个包。

yum install db4 db4-utils

然后,创建用户密码文本/etc/vsftpd/vuser_passwd.txt ,注意奇行是用户名,偶行是密码:

wordpress
123456

接着,生成虚拟用户认证的db文件:

db_load -T -t hash -f /etc/vsftpd/vuser_passwd.txt /etc/vsftpd/vuser_passwd.db

随后,编辑认证文件/etc/pam.d/vsftpd,全部注释掉原来语句,再增加以下两句:

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd
account required pam_userdb.so db=/etc/vsftpd/vuser_passwd

最后,创建虚拟用户配置文件:

mkdir /etc/vsftpd/vuser_conf/
vi /etc/vsftpd/vuser_conf/wordpress  //文件名等于vuser_passwd.txt里面的账户名,否则下面设置无效

内容如下(这里需要注意YES或NO等配置项后面不要在复制过程中多出不必要的空格):

local_root=/home/wwwroot
write_enable=YES
anon_umask=022
anon_world_readable_only=NO
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

 

3. 设置Selinux(可省略)

setsebool -P ftp_home_dir=1   //设置ftp可以使用home目录
setsebool -P allow_ftpd_full_access=1   //设置ftp用户可以有所有权限

 

4. 设置FTP根目录权限

mkdir /home/wwwroot   //创建目录,如果目录已存在请省略
chmod a-w /home
chmod -R 777 /home/wwwroot

最新的vsftpd要求对主目录不能有写的权限所以/home为a-w,主目录下面的子目录再设置777权限。

 

5. 设置防火墙

打开/etc/sysconfig/iptables,添加一句:

-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT

然后保存,并关闭该文件,在终端内运行下面的命令,刷新防火墙配置:

service iptables restart

启动FTP服务器:

service vsftpd start

 

6. 连接FTP服务器

现在你就可以使用FTP工具连接服务器了,建议使用FileZilla工具连接,连接的过程中如果出现报错,你只需要去搜索报错的内容调整服务器的配置就好了。

 

参考文章:http://www.cnblogs.com/xiongpq/p/3384759.html

一次JVM引起的服务器load过高问题排查经历

2016-11-08早上9:25分,公司运维的同事给我报警,称我们团队的一台服务器CPU的压力很大,zabbix的图显示:

1接到警报后,我在该服务器上使用w和top命令查看服务器的load和CPU情况,1分钟的load average在3-5之间,系统在高负荷运转,查看了我们的线上应用系统发现网页打开正常,但一个別列表的查询缓慢,chrome浏览器的network查看http接口的timing在十几秒。这部分列表走的是搜索引擎,我第一反应是会不会是搜索引擎出问题了?

于是我在服务器上查看tomcat日志,获取我们的应用调用搜索引擎的接口和参数,拼装后使用

curl -v '$url'

命令访问,发现访问的速度没有问题。那说明搜索引擎没有问题,那一定是我们的应用从搜索引擎返回值到展示给用户的部分处理有问题。

由于有大量用户反馈系统速度慢,于是我使用jps获取java进程的pid,随后使用:

jmap -dump:format=b,file=crm.bin [pid]

命令dump jvm的信息“保留犯罪现场”,然后重启线上应用。

启动应用后检测到服务器的load渐渐越来越高,最后保持在重启前的样子,于是使用

jstat -gc [pid] 3000

查看服务器每隔3秒的gc情况,发现3秒钟的full gc能够达到两次,jvm的状况十分异常。在启动服务器的这个时间里我利用eclipse MAT工具分析jmap dump文件信息,未诊断出异常。

后来我把原来jvm的Xms参数配置由1024m提高到3072m,发现双机的full gc次数分别稳定在0和2后再也没有full gc过了,但是young GC却十分频繁,3秒钟young GC次数可以达到15-20次。

到底是什么东西这么占内存???我使用jmap -histo pid查看,发现排在第一位的[C对象经常飙升到1个多G然后降到200MB,就是young GC频繁的原因,这通常是String类型的对象存在问题。

随后我使用

top -H -p [pid]

看到了如下结果:

2这一排的PID都占用了大量的CPU资源,于是随机取了一个PID为1077的进程,使用

printf "%x\n" 1077

转换成16进制的数字为435

随后使用jstack工具:

jstack [pid] | less

输出当前的堆栈信息,然后搜索435,发现如下内容:

3这块代码就是调用搜索引擎的代码,它处于RUNNABLE的状态,一直在执行中,说明这段代码一定是追魁祸首!打开代码看看!原来是这样的一段代码:

while ((line = in.readline()) != null) {
    result += line;
}

真相就是:循环里每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。

将String改成StringBuilder,发布上线后load过高的问题解决。这就解释了为什么一般的页面打开速度正常,而搜索客户列表接口速度缓慢以及为什么char类型的数组占用大量内存。