利用openresty+kafka+elk搭建日志系统
场景
Nginx的Access log有时候对我们来说很有价值,但是当成log文件一直放在服务器上的话价值并不大,而且还占磁盘空间。
其实通过log做各种分析,统计等方案挺多,我想在这里介绍一下利用OpenResty+Kafka+ELK搭建日志系统。
OpenResty
国人杰作,OpenResty
可以在Nginx之上利用Lua语言编写模块儿。
Nginx:诞生在俄罗斯,一个高性能的HTTP和反向代理服务器
Lua:诞生在巴西,脚本语言,易于嵌入到其他语言,因此很多人叫它胶水语言
有人说OpenResty是来自金砖国家
Kafka
Kafka是一个诞生在LinkedIn的高性能分布式消息系统,用Scala语言编写,目前已经贡献给Apache基金会。
ELK
ELK是Elasticsearch+Logstash+Kibana的缩写
Elasticsearch是基于Lucene的分布式全文搜索引擎
Logstash:收集log,处理log的工具,可以利用Logstash直接把log文件内容存到Elasticsearch中,但是为了进一步编辑log内容,本文没有采用Logstash
Kibana:Elasticsearch的可视化平台
思路
- 用OpenResty替代原来的Nginx
- 用Lua脚本改造Accesslog打印,把log发送到Kafka集群中
- Kafka的Consumer Group异步处理log队列
- 基于log内容编辑数据并存到Elasticsearch中
安装Kafka
https://kafka.apache.org/quickstart
编辑中…
安装OpenResty
下载最新的源码:https://openresty.org/cn/download.html
# 解压
tar -xzvf openresty-VERSION.tar.gz
cd openresty-{VERSION}
./configure # 可以通过--prefix=/your/directory 参数指定安装目录
# 默认安装到/usr/local/openresty目录
# 如果报Missing OpenSSL错误执行下面命令
yum install readline-devel pcre-devel openssl-devel gcc curl
# 编译
make
# 安装
make install
lua-resty-kafka
一个OpenResty的Kafka Client 下载地址:https://github.com/doujiang24/lua-resty-kafka
lib下的resty/kafka整个拷贝到/usr/local/openresty/lualib/下
nginx.conf
cd /usr/local/openresty/nginx/conf
vi nginx.conf
user root;
worker_processes 4;
error_log logs/error.log;
error_log logs/error.log notice;
error_log logs/error.log info;
pid logs/nginx.pid;
events {
use epoll;
worker_connections 65535;
}
http {
include mime.types;
default_type application/octet-stream;
access_log off;
underscores_in_headers on;
client_header_buffer_size 32k;
large_client_header_buffers 4 64k;
client_body_buffer_size 512k;
client_max_body_size 50m;
proxy_buffer_size 32k;
proxy_buffers 4 512k;
proxy_busy_buffers_size 1024k;
proxy_temp_file_write_size 1024k;
server_tokens off;
sendfile on;
tcp_nopush on;
keepalive_timeout 300;
tcp_nodelay on;
gzip on;
gzip_min_length 1k;
gzip_buffers 16 64k;
gzip_http_version 1.1;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml application/xml-dtd image/gif image/jpeg image/png image/x-icon image/bmp image/jpg image/x-ms-bmp text/javascript application/x-javascript application/javascript;
gzip_vary on;
upstream apps {
keepalive 80;
server 192.168.1.20:8080;
server 192.168.1.21:8080;
}
# 引用Kafka Client
lua_package_path "/usr/local/openresty/1.11.2.3/lualib/kafka/?.lua;;";
server {
listen 80;
server_name your-domain.com;
index index.html index.htm index.jsp;
root html;
location / {
proxy_next_upstream http_502 http_504 http_404 error invalid_header;
proxy_pass http://apps;
proxy_http_version 1.1;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
#proxy_set_header Connection "";
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 编辑消息体并发送到kafka集群
log_by_lua '
local cjson = require "cjson"
local producer = require "resty.kafka.producer"
local broker_list = {
{ host = "192.168.1.150", port = 9092 },
{ host = "192.168.1.151", port = 9092 },
{ host = "192.168.1.152", port = 9092 },
}
local log_json = {}
log_json["uri"]=ngx.var.uri
log_json["args"]=ngx.var.args
log_json["host"]=ngx.var.host
log_json["cookie"]=ngx.var.http_cookie
log_json["method"]=ngx.var.request_method
log_json["request_body"]=ngx.var.request_body
log_json["remote_addr"] = ngx.var.remote_addr
log_json["remote_user"] = ngx.var.remote_user
log_json["time_local"] = ngx.var.time_local
log_json["status"] = ngx.var.status
log_json["body_bytes_sent"] = ngx.var.body_bytes_sent
log_json["http_referer"] = ngx.var.http_referer
log_json["http_user_agent"] = ngx.var.http_user_agent
log_json["http_x_forwarded_for"] = ngx.var.http_x_forwarded_for
log_json["upstream_response_time"] = ngx.var.upstream_response_time
log_json["http_current_user"] = ngx.var.upstream_http_x_current_user
log_json["request_time"] = ngx.var.request_time
local message = cjson.encode(log_json);
local bp = producer:new(broker_list, { producer_type = "async" })
local ok, err = bp:send("accesslog", nil, message)
if not ok then
ngx.log(ngx.ERR, "kafka send err:", err)
return
end
';
}
}
}
安装Elasticsearch
https://www.elastic.co/downloads/elasticsearch
编辑中…
Kafka Consumer
编辑中…
安装Kibana
https://www.elastic.co/downloads/kibana
编辑中…