Tipik olaraq, Nginx-in işini izləmək və təhlil etmək üçün Prometheus + Grafana kimi kommersiya məhsulları və ya hazır açıq mənbə alternativləri istifadə olunur. Bu monitorinq və ya real vaxt analitikası üçün yaxşı seçimdir, lakin tarixi təhlil üçün çox əlverişli deyil. İstənilən populyar resursda nginx qeydlərindən alınan məlumatların həcmi sürətlə artır və böyük miqdarda məlumatı təhlil etmək üçün daha ixtisaslaşmış bir şeydən istifadə etmək məntiqlidir.
Bu yazıda sizə necə istifadə edə biləcəyinizi söyləyəcəyəm
TL: DR;
İstifadə etdiyimiz məlumat toplamaq üçün
Nginx qeydlərinin toplanması
Varsayılan olaraq, Nginx qeydləri belə görünür:
4/9/2019 12:58:17 PM1.1.1.1 - - [09/Apr/2019:09:58:17 +0000] "GET /sign-up HTTP/2.0" 200 9168 "https://example.com/sign-in" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"
4/9/2019 12:58:17 PM1.1.1.1 - - [09/Apr/2019:09:58:17 +0000] "GET /sign-in HTTP/2.0" 200 9168 "https://example.com/sign-up" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"
Onları təhlil etmək olar, lakin Nginx konfiqurasiyasını JSON-da qeydlər yaratması üçün düzəltmək daha asandır:
log_format json_combined escape=json '{ "created_at": "$msec", '
'"remote_addr": "$remote_addr", '
'"remote_user": "$remote_user", '
'"request": "$request", '
'"status": $status, '
'"bytes_sent": $bytes_sent, '
'"request_length": $request_length, '
'"request_time": $request_time, '
'"http_referrer": "$http_referer", '
'"http_x_forwarded_for": "$http_x_forwarded_for", '
'"http_user_agent": "$http_user_agent" }';
access_log /var/log/nginx/access.log json_combined;
Saxlama üçün S3
Günlükləri saxlamaq üçün biz S3 istifadə edəcəyik. Bu, qeydləri bir yerdə saxlamağa və təhlil etməyə imkan verir, çünki Athena birbaşa S3-də məlumatlarla işləyə bilər. Daha sonra məqalədə qeydləri necə düzgün əlavə etmək və emal etmək barədə sizə məlumat verəcəyəm, lakin əvvəlcə S3-də başqa heç bir şeyin saxlanmayacağı təmiz bir çömçə lazımdır. Athena bütün bölgələrdə mövcud olmadığı üçün hansı bölgədə vedrənizi yaratacağınızı əvvəlcədən düşünməyə dəyər.
Athena konsolunda bir dövrə yaratmaq
Afinada loglar üçün cədvəl yaradaq. Kinesis Firehose istifadə etməyi planlaşdırırsınızsa, həm yazmaq, həm də oxumaq üçün lazımdır. Athena konsolunu açın və cədvəl yaradın:
SQL cədvəlinin yaradılması
CREATE EXTERNAL TABLE `kinesis_logs_nginx`(
`created_at` double,
`remote_addr` string,
`remote_user` string,
`request` string,
`status` int,
`bytes_sent` int,
`request_length` int,
`request_time` double,
`http_referrer` string,
`http_x_forwarded_for` string,
`http_user_agent` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.orc.OrcSerde'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.orc.OrcInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.orc.OrcOutputFormat'
LOCATION
's3://<YOUR-S3-BUCKET>'
TBLPROPERTIES ('has_encrypted_data'='false');
Kinesis Firehose Stream yaradılması
Kinesis Firehose seçilmiş formatda Nginx-dən S3-ə qəbul edilmiş məlumatları YYYY/AA/GG/HH formatında qovluqlara bölməklə yazacaq. Bu, məlumatları oxuyarkən faydalı olacaq. Siz əlbəttə ki, fluentd-dən birbaşa S3-ə yaza bilərsiniz, lakin bu halda siz JSON yazmalı olacaqsınız və bu, faylların böyük ölçüsünə görə səmərəsizdir. Bundan əlavə, PrestoDB və ya Athena istifadə edərkən, JSON ən yavaş məlumat formatıdır. Beləliklə, Kinesis Firehose konsolunu açın, "Çatdırılma axını yarat" düyməsini basın, "çatdırılma" sahəsində "birbaşa PUT" seçin:
Növbəti sekmədə "Record format conversion" - "Enabled" seçin və qeyd formatı kimi "Apache ORC" seçin. Bəzi araşdırmalara görə
Saxlama üçün S3-ü və əvvəllər yaratdığımız kovanı seçirik. Bir az sonra danışacağım Aws Glue Crawler, S3 vedrəsindəki prefikslərlə işləyə bilməz, ona görə də onu boş qoymaq vacibdir.
Qalan seçimlər yükünüzdən asılı olaraq dəyişdirilə bilər; Mən adətən standart olanlardan istifadə edirəm. Qeyd edək ki, S3 sıxılma mövcud deyil, lakin ORC standart olaraq yerli sıxılmadan istifadə edir.
səlis
İndi qeydlərin saxlanmasını və qəbulunu konfiqurasiya etdikdən sonra göndərməni konfiqurasiya etməliyik. istifadə edəcəyik
Əvvəlcə fluent.conf konfiqurasiya faylına ehtiyacımız var. Yaradın və mənbə əlavə edin:
port 24224
bağlama 0.0.0.0
İndi siz Fluentd serverinə başlaya bilərsiniz. Daha təkmil konfiqurasiyaya ehtiyacınız varsa, keçin
$ docker run
-d
-p 24224:24224
-p 24224:24224/udp
-v /data:/fluentd/log
-v <PATH-TO-FLUENT-CONF>:/fluentd/etc fluentd
-c /fluentd/etc/fluent.conf
fluent/fluentd:stable
Bu konfiqurasiya yoldan istifadə edir /fluentd/log
göndərməzdən əvvəl qeydləri keş etmək. Bunu etmədən də edə bilərsiniz, lakin sonra yenidən başlatdığınız zaman, geri çəkilən əməklə keşlənmiş hər şeyi itirə bilərsiniz. Siz həmçinin istənilən portdan istifadə edə bilərsiniz; 24224 standart Fluentd portudur.
İndi bizdə Fluentd işləyir, biz oraya Nginx qeydlərini göndərə bilərik. Biz adətən Nginx-i Docker konteynerində işlədirik, bu halda Docker-in Fluentd üçün yerli giriş sürücüsü var:
$ docker run
--log-driver=fluentd
--log-opt fluentd-address=<FLUENTD-SERVER-ADDRESS>
--log-opt tag="{{.Name}}"
-v /some/content:/usr/share/nginx/html:ro
-d
nginx
Nginx-i fərqli şəkildə işlədirsinizsə, Fluentd-də log fayllarından istifadə edə bilərsiniz
Yuxarıda konfiqurasiya edilmiş log təhlilini Fluent konfiqurasiyasına əlavə edək:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Və istifadə edərək, Kinesis-ə logların göndərilməsi
<match YOUR-NGINX-TAG.*>
@type kinesis_firehose
region region
delivery_stream_name <YOUR-KINESIS-STREAM-NAME>
aws_key_id <YOUR-AWS-KEY-ID>
aws_sec_key <YOUR_AWS-SEC_KEY>
</match>
Athena
Hər şeyi düzgün konfiqurasiya etmisinizsə, bir müddət sonra (standart olaraq, Kinesis alınan məlumatları hər 10 dəqiqədə bir dəfə qeyd edir) S3-də log fayllarını görməlisiniz. Kinesis Firehose-un "monitorinq" menyusunda S3-də nə qədər məlumatın qeydə alındığını, həmçinin səhvləri görə bilərsiniz. Kinesis roluna S3 vedrəsinə yazma imkanı verməyi unutmayın. Kinesis bir şeyi təhlil edə bilmədisə, səhvləri eyni vedrə əlavə edəcək.
İndi məlumatlara Athena-da baxa bilərsiniz. Səhvləri qaytardığımız ən son sorğuları tapaq:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Hər sorğu üçün bütün qeydlərin skan edilməsi
İndi jurnallarımız işlənmiş və S3-də ORC-də saxlanılmış, sıxılmış və təhlil üçün hazırdır. Kinesis Firehose hətta onları hər saat üçün kataloqlar şəklində təşkil etdi. Bununla belə, cədvəl bölünmədiyi müddətcə, Athena nadir istisnalar istisna olmaqla, hər sorğu üzrə bütün zaman məlumatlarını yükləyəcək. Bu iki səbəbə görə böyük problemdir:
- Məlumatların həcmi daim artır, sorğuları yavaşlatır;
- Athena, hər sorğu üçün minimum 10 MB olmaqla, skan edilmiş məlumatların həcminə əsasən hesablanır.
Bunu düzəltmək üçün biz S3-də məlumatları tarayacaq və bölmə məlumatlarını Glue Metastore-a yazacaq AWS Glue Crawler-dən istifadə edirik. Bu, Athena sorğusu zamanı arakəsmələrdən filtr kimi istifadə etməyə imkan verəcək və o, yalnız sorğuda göstərilən qovluqları skan edəcək.
Amazon Glue Crawler-ın qurulması
Amazon Glue Crawler S3 kovasındakı bütün məlumatları skan edir və arakəsmələrlə cədvəllər yaradır. AWS Glue konsolundan Glue Crawler yaradın və məlumatları saxladığınız yerə bir vedrə əlavə edin. Bir neçə vedrə üçün bir sürünəndən istifadə edə bilərsiniz, bu halda o, müəyyən edilmiş verilənlər bazasında vedrələrin adlarına uyğun adlarla cədvəllər yaradacaqdır. Bu məlumatları müntəzəm olaraq istifadə etməyi planlaşdırırsınızsa, Crawler-in işə salınma cədvəlini ehtiyaclarınıza uyğun olaraq konfiqurasiya etdiyinizə əmin olun. Biz hər saat işləyən bütün cədvəllər üçün bir Crawler istifadə edirik.
Bölünmüş masalar
Tarayıcının ilk işə salınmasından sonra, parametrlərdə göstərilən verilənlər bazasında hər bir skan edilmiş vedrə üçün cədvəllər görünməlidir. Athena konsolunu açın və Nginx qeydləri olan cədvəli tapın. Gəlin bir şey oxumağa çalışaq:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Bu sorğu 6 aprel 7-cu il tarixində səhər saat 8-dan səhər 2019-dək qəbul edilmiş bütün qeydləri seçəcək. Bəs bu, bölünməmiş cədvəldən oxumaqdan nə qədər səmərəlidir? Gəlin eyni qeydləri tapıb seçək, onları vaxt damğasına görə süzək:
3.59 saniyə və 244.34 meqabayt məlumat toplusunda cəmi bir həftəlik qeydlər. Gəlin bölmə üzrə filtri sınayaq:
Bir az daha sürətli, lakin ən əsası - yalnız 1.23 meqabayt məlumat! Qiymətləndirmədə hər sorğu üçün minimum 10 meqabayt olmasaydı, daha ucuz olardı. Ancaq yenə də daha yaxşıdır və böyük məlumat dəstlərində fərq daha təsir edici olacaq.
Cube.js istifadə edərək tablosunun qurulması
İdarə panelini yığmaq üçün biz Cube.js analitik çərçivəsindən istifadə edirik. Onun kifayət qədər çox funksiyası var, lakin bizi iki maraqlandırır: bölmə filtrlərindən avtomatik istifadə etmək və məlumatların əvvəlcədən yığılması. Məlumat sxemindən istifadə edir
Gəlin yeni Cube.js tətbiqi yaradaq. Artıq AWS yığınından istifadə etdiyimiz üçün yerləşdirmə üçün Lambda-dan istifadə etmək məntiqlidir. Cube.js backendini Heroku və ya Docker-də yerləşdirməyi planlaşdırırsınızsa, nəsil üçün ekspress şablondan istifadə edə bilərsiniz. Sənədlər başqalarını təsvir edir
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Ətraf dəyişənləri cube.js-də verilənlər bazasına girişi konfiqurasiya etmək üçün istifadə olunur. Generator açarlarınızı təyin edə biləcəyiniz .env faylı yaradacaq
İndi ehtiyacımız var
Kataloqda schema
, fayl yaradın Logs.js
. Nginx üçün nümunə məlumat modeli:
Model kodu
const partitionFilter = (from, to) => `
date(from_iso8601_timestamp(${from})) <= date_parse(partition_0 || partition_1 || partition_2, '%Y%m%d') AND
date(from_iso8601_timestamp(${to})) >= date_parse(partition_0 || partition_1 || partition_2, '%Y%m%d')
`
cube(`Logs`, {
sql: `
select * from part_demo_kinesis_bucket
WHERE ${FILTER_PARAMS.Logs.createdAt.filter(partitionFilter)}
`,
measures: {
count: {
type: `count`,
},
errorCount: {
type: `count`,
filters: [
{ sql: `${CUBE.isError} = 'Yes'` }
]
},
errorRate: {
type: `number`,
sql: `100.0 * ${errorCount} / ${count}`,
format: `percent`
}
},
dimensions: {
status: {
sql: `status`,
type: `number`
},
isError: {
type: `string`,
case: {
when: [{
sql: `${CUBE}.status >= 400`, label: `Yes`
}],
else: { label: `No` }
}
},
createdAt: {
sql: `from_unixtime(created_at)`,
type: `time`
}
}
});
Burada dəyişəndən istifadə edirik
Biz həmçinin tablosunda göstərmək istədiyimiz ölçüləri və parametrləri təyin edirik və əvvəlcədən birləşmələri təyin edirik. Cube.js əvvəlcədən yığılmış data ilə əlavə cədvəllər yaradacaq və məlumat gələn kimi avtomatik yenilənəcək. Bu, sorğuları sürətləndirməklə yanaşı, Athena-dan istifadə xərclərini də azaldır.
Gəlin bu məlumatı verilənlər sxemi faylına əlavə edək:
preAggregations: {
main: {
type: `rollup`,
measureReferences: [count, errorCount],
dimensionReferences: [isError, status],
timeDimensionReference: createdAt,
granularity: `day`,
partitionGranularity: `month`,
refreshKey: {
sql: FILTER_PARAMS.Logs.createdAt.filter((from, to) =>
`select
CASE WHEN from_iso8601_timestamp(${to}) + interval '3' day > now()
THEN date_trunc('hour', now()) END`
)
}
}
}
Biz bu modeldə qeyd edirik ki, istifadə olunan bütün ölçülər üçün məlumatları əvvəlcədən toplamaq və aylar üzrə bölmədən istifadə etmək lazımdır.
İndi tablosunu yığa bilərik!
Cube.js backend təmin edir
Cube.js serveri sorğunu qəbul edir
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
NPM vasitəsilə Cube.js müştərisini və React komponent kitabxanasını quraşdıraq:
$ npm i --save @cubejs-client/core @cubejs-client/react
Biz komponentləri idxal edirik cubejs
и QueryRenderer
məlumatları yükləmək və tablosunu toplamaq üçün:
İdarə paneli kodu
import React from 'react';
import { LineChart, Line, XAxis, YAxis } from 'recharts';
import cubejs from '@cubejs-client/core';
import { QueryRenderer } from '@cubejs-client/react';
const cubejsApi = cubejs(
'YOUR-CUBEJS-API-TOKEN',
{ apiUrl: 'http://localhost:4000/cubejs-api/v1' },
);
export default () => {
return (
<QueryRenderer
query={{
measures: ['Logs.errorCount'],
timeDimensions: [{
dimension: 'Logs.createdAt',
dateRange: ['2019-01-01', '2019-01-07'],
granularity: 'day'
}]
}}
cubejsApi={cubejsApi}
render={({ resultSet }) => {
if (!resultSet) {
return 'Loading...';
}
return (
<LineChart data={resultSet.rawData()}>
<XAxis dataKey="Logs.createdAt"/>
<YAxis/>
<Line type="monotone" dataKey="Logs.errorCount" stroke="#8884d8"/>
</LineChart>
);
}}
/>
)
}
Dashboard mənbələri burada mövcuddur
Mənbə: www.habr.com