Openresty学习使用(一)记录爬虫结果日志
业务场景
日志记录很多时候是一种高并发场景的解决方案,对于不那么重要或者及时的场景可以通过异步记录日志的方式,异步将日志存储成文件,可以加快业务的返回,后续可以用ELK等框架对日志进行分析处理。
本文所说的爬虫都是垂直领域的爬虫,结果都以JSON格式进行返回。由于爬虫整体的不稳定性,我们把爬虫结果分为两大部分,一部分是基本的状态信息,包含爬取站点,爬取参数,爬取状态等,一部分是爬取结果,我们将基本的状态信息利用ELK进行处理,利用ELK对日志进行分析,对爬虫整体情况进行分析统计告警,将另一部分爬取结果写入Hbase,用于结果存储。当然也可以是其他存储实现。
由于爬虫机器很多,如果每台机器都用Log4j等方式进行输出的话,部署都很麻烦,且对磁盘空间也有要求,所以我们采取了Nginx的方式,将日志统一收集到几台机器进行处理。
由于需要一些像lua脚本进行文件夹创建等操作,我们采用了openresty。
openresty安装
sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo
sudo yum install openresty
openresty是淘宝大神维护的产品,相对于nginx的高门槛,通过集成lua等方式,给我们提供了对nginx操作的更多可能
openresty配置
//记录消息体
log_format main '{ "timestamp":"$time_local",'
'"result":"$request_body"}';
client_body_buffer_size 1m;
client_body_in_single_buffer on;
log_escape_non_ascii off;
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location ~ /(.+)/(.+)$ {
if (!-e /data/server/nginx/logs/$1) {
//lua脚本 自动创建目录
content_by_lua '
local uri = ngx.var.request_uri
local t = string.match(uri,"/(.+)/.+")
local dir = "/data/server/nginx/logs/"..t
os.execute("mkdir " .. dir)
';
}
access_log /data/server/nginx/logs/$1/$2.log main;
echo_read_request_body;
}
说明
client_body_buffer_size设置nginx可以处理的最大request body大小。
client_body_in_single_buffer 让Nginx将所有的request body存储在一个缓冲当中
启用它可以优化读取$request_body变量时的I/O性能。
对于每一条日志记录,日志文件都将先打开文件,再写入日志记录,然后马上关闭。 为了提高包含变量的日志文件存放路径的性能,需要使用 open_log_file_cache 指令设置经常被使用的日志文件描述符缓存。
open_log_file_cache 指令的各项参数说明如下:
max: 设置缓存中的最大文件描述符数量。如果超过设置的最大文件描述符数量,则采用 LRU (Least Recently Used) 算法清除"较不常使用的文件描述符"。 LRU (Least Recently Used) 算 法的基本概念是:当内存缓冲区剩余的可用空间不够时,缓冲区尽可能地先保留使用者最常使用的数据,将最近未使用的数据移出内存,腾出空间来加载另外的数据。
inactive: 设置一个时间,如果在设置的时间内没有使用此文件描述符,则自动删除此描述符。 此参数为可选参数,默认的时间为 10 秒钟。
min_uses: 在参数 inactive 指定的时间范围内,如果日志文件超过被使用的次数,则将该日志文件的描述符记入缓存。默认次数为 1。
valid: 设置多长时间检查一次,看一看变量指定的日志文件路径与文件名是否仍然存在。默 认时间为 60秒。
off: 禁止使用缓存。
Java调用
static{
ConnectingIOReactor ioReactor;
try {
ioReactor = new DefaultConnectingIOReactor();
PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor);
cm.setMaxTotal(500);
httpAsyncClient = HttpAsyncClients.custom().setConnectionManager(cm).build();
httpAsyncClient.start();
} catch (IOReactorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void doPost(String tag,String xml){
try {
String htmlurl = PRE_URL+tag;
HttpPost post = new HttpPost(htmlurl);
post.setEntity(new StringEntity(xml,"utf-8"));
httpAsyncClient.execute(post, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
java侧采用HttpAsyncClient, HttpAsyncClient的出现并不是为了替换 HttpClient,而是作为一个补充,用于需要大量并发连接,对性能要求非常高的基于HTTP的原生数据通信,而且提供了事件驱动的 API。
问题
1.文件请求体太大,导致request_body返回内容为-
参考nginx配置中的client_body_buffer_size client_body_in_single_buffer 配置
2.x22格式的问题
nginx配置增加 log_escape_non_ascii off;
3.安全性问题
最好是能够在内网访问,如果是外网,最好添加白名单