Odatda, Nginx ishlashini kuzatish va tahlil qilish uchun Prometey + Grafana kabi tijorat mahsulotlari yoki tayyor ochiq manbali alternativalardan foydalaniladi. Bu monitoring yoki real vaqtda tahlil qilish uchun yaxshi variant, ammo tarixiy tahlil uchun juda qulay emas. Har qanday mashhur manbada nginx jurnallaridan olingan ma'lumotlar hajmi tez sur'atlar bilan o'sib bormoqda va katta hajmdagi ma'lumotlarni tahlil qilish uchun ko'proq ixtisoslashgan narsadan foydalanish mantiqan to'g'ri keladi.
Ushbu maqolada men sizga qanday qilib foydalanishingiz mumkinligini aytaman
TL: DR;
Ma'lumot to'plash uchun biz foydalanamiz
Nginx jurnallarini yig'ish
Odatiy bo'lib, Nginx jurnallari quyidagicha ko'rinadi:
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" "-"
Ularni tahlil qilish mumkin, ammo Nginx konfiguratsiyasini JSONda jurnallar yaratish uchun tuzatish ancha oson:
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;
Saqlash uchun S3
Jurnallarni saqlash uchun biz S3 dan foydalanamiz. Bu sizga jurnallarni bir joyda saqlash va tahlil qilish imkonini beradi, chunki Athena bevosita S3-dagi ma'lumotlar bilan ishlashi mumkin. Keyinchalik maqolada men sizga jurnallarni qanday qilib to'g'ri qo'shish va qayta ishlash kerakligini aytaman, lekin avval S3-da toza chelak kerak, unda boshqa hech narsa saqlanmaydi. Qaysi mintaqada chelak yaratishingizni oldindan ko'rib chiqishga arziydi, chunki Afina barcha mintaqalarda mavjud emas.
Afina konsolida sxema yaratish
Keling, Afinada jurnallar uchun jadval yarataylik. Agar siz Kinesis Firehose-dan foydalanishni rejalashtirmoqchi bo'lsangiz, u yozish va o'qish uchun kerak. Athena konsolini oching va jadval yarating:
SQL jadvalini yaratish
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 yaratish
Kinesis Firehose Nginx-dan S3-ga olingan ma'lumotlarni tanlangan formatda yozadi va uni YYYY/MM/DD/HH formatidagi kataloglarga ajratadi. Bu ma'lumotlarni o'qishda foydali bo'ladi. Siz, albatta, fluentd dan to'g'ridan-to'g'ri S3 ga yozishingiz mumkin, ammo bu holda siz JSON yozishingiz kerak bo'ladi va bu fayllarning kattaligi tufayli samarasiz. Bundan tashqari, PrestoDB yoki Athena-dan foydalanganda, JSON eng sekin ma'lumotlar formatidir. Shunday qilib, Kinesis Firehose konsolini oching, "Etkazib berish oqimini yaratish" tugmasini bosing, "etkazib berish" maydonida "to'g'ridan-to'g'ri PUT" ni tanlang:
Keyingi yorliqda "Yozuv formatini o'zgartirish" - "Yoqilgan" ni tanlang va yozish formati sifatida "Apache ORC" ni tanlang. Ba'zi tadqiqotlarga ko'ra
Saqlash uchun S3 ni va avval yaratgan chelakni tanlaymiz. Men biroz keyinroq gaplashadigan Aws Glue Crawler S3 paqiridagi prefikslar bilan ishlay olmaydi, shuning uchun uni bo'sh qoldirish muhimdir.
Qolgan variantlar yukingizga qarab o'zgartirilishi mumkin; Men odatda standart variantlardan foydalanaman. E'tibor bering, S3 siqish mavjud emas, lekin ORC sukut bo'yicha mahalliy siqishni ishlatadi.
Fluentd
Endi biz jurnallarni saqlash va qabul qilishni sozlaganmiz, biz yuborishni sozlashimiz kerak. foydalanamiz
Birinchidan, bizga fluent.conf konfiguratsiya fayli kerak. Uni yarating va manba qo'shing:
24224 porti
bog'lash 0.0.0.0
Endi siz Fluentd serverini ishga tushirishingiz mumkin. Agar sizga yanada rivojlangan konfiguratsiya kerak bo'lsa, o'ting
$ 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
Ushbu konfiguratsiya yo'ldan foydalanadi /fluentd/log
yuborishdan oldin jurnallarni keshlash uchun. Siz bunisiz ham qilishingiz mumkin, lekin keyin qayta ishga tushirganingizda, orqaga qaytish mehnati bilan keshlangan hamma narsani yo'qotishingiz mumkin. Siz har qanday portdan ham foydalanishingiz mumkin; 24224 standart Fluentd portidir.
Endi bizda Fluentd ishlayotgan bo'lsa, biz u erga Nginx jurnallarini yuborishimiz mumkin. Biz odatda Nginx-ni Docker konteynerida ishga tushiramiz, bu holda Docker-da Fluentd uchun mahalliy jurnal drayveri mavjud:
$ 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
Agar siz Nginx-ni boshqacha ishlatsangiz, log fayllardan foydalanishingiz mumkin, Fluentd bor
Keling, Fluent konfiguratsiyasiga yuqorida sozlangan jurnal tahlilini qo'shamiz:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Va yordamida Kinesis jurnallarini yuborish
<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>
Afina
Agar siz hamma narsani to'g'ri sozlagan bo'lsangiz, bir muncha vaqt o'tgach (sukut bo'yicha, Kinesis olingan ma'lumotlarni har 10 daqiqada bir marta yozib oladi) S3-da jurnal fayllarini ko'rishingiz kerak. Kinesis Firehose-ning "monitoring" menyusida siz S3-da qancha ma'lumot yozilganligini, shuningdek xatolarni ko'rishingiz mumkin. Kinesis roliga S3 paqiriga yozish huquqini berishni unutmang. Agar Kinesis biror narsani tahlil qila olmasa, u xatolarni bir xil paqirga qo'shadi.
Endi siz Afinada ma'lumotlarni ko'rishingiz mumkin. Xatolarni qaytargan so'nggi so'rovlarni topamiz:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Har bir so'rov uchun barcha yozuvlarni skanerlash
Endi bizning jurnallarimiz qayta ishlandi va S3 da ORC da saqlangan, siqilgan va tahlilga tayyor. Kinesis Firehose hatto ularni har soat uchun kataloglarga ajratdi. Biroq, jadval bo'linmagan ekan, Athena har bir so'rov bo'yicha barcha vaqt ma'lumotlarini yuklaydi, kamdan-kam holatlar bundan mustasno. Bu ikki sababga ko'ra katta muammo:
- Ma'lumotlar hajmi doimiy ravishda o'sib bormoqda, so'rovlarni sekinlashtiradi;
- Afina uchun to'lov skanerlangan ma'lumotlar hajmiga qarab amalga oshiriladi, har bir so'rov uchun kamida 10 MB.
Buni tuzatish uchun biz AWS Glue Crawler-dan foydalanamiz, u S3-dagi ma'lumotlarni tekshiradi va bo'lim ma'lumotlarini Glue Metastore-ga yozadi. Bu bizga Athena so'rovida bo'limlardan filtr sifatida foydalanish imkonini beradi va u faqat so'rovda ko'rsatilgan kataloglarni skanerlaydi.
Amazon Glue Crawler-ni sozlash
Amazon Glue Crawler S3 paqiridagi barcha ma'lumotlarni skanerlaydi va bo'limlar bilan jadvallar yaratadi. AWS Glue konsolidan Glue Crawler yarating va ma'lumotlarni saqlaydigan chelak qo'shing. Bir nechta chelaklar uchun bitta brauzerdan foydalanishingiz mumkin, bu holda u belgilangan ma'lumotlar bazasida chelaklarning nomlariga mos keladigan nomlar bilan jadvallarni yaratadi. Agar siz ushbu ma'lumotlardan muntazam foydalanishni rejalashtirmoqchi bo'lsangiz, Crawler dasturini ishga tushirish jadvalini ehtiyojlaringizga mos ravishda sozlaganingizga ishonch hosil qiling. Biz har soatda ishlaydigan barcha jadvallar uchun bitta Crawlerdan foydalanamiz.
Bo'lingan jadvallar
Brauzerni birinchi ishga tushirgandan so'ng, sozlamalarda ko'rsatilgan ma'lumotlar bazasida har bir skanerlangan chelak uchun jadvallar paydo bo'lishi kerak. Athena konsolini oching va Nginx jurnallari bilan jadvalni toping. Keling, biror narsani o'qishga harakat qilaylik:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Bu soΚ»rov 6-yil 7-aprel kuni soat 8 dan 2019 gacha qabul qilingan barcha yozuvlarni tanlaydi. Ammo bu bo'linmagan jadvaldan o'qishdan ko'ra qanchalik samaraliroq? Keling, vaqt tamg'asi bo'yicha filtrlash orqali bir xil yozuvlarni aniqlaymiz va tanlaymiz:
3.59 soniya va 244.34 megabayt ma'lumotlar to'plamida faqat bir haftalik jurnallar mavjud. Keling, bo'lim bo'yicha filtrni sinab ko'raylik:
Bir oz tezroq, lekin eng muhimi - atigi 1.23 megabayt ma'lumot! Narxlarda har bir so'rov uchun kamida 10 megabayt bo'lmasa, bu ancha arzonroq bo'lar edi. Ammo bu hali ham yaxshiroq va katta ma'lumotlar to'plamlarida farq ancha ta'sirli bo'ladi.
Cube.js yordamida asboblar panelini yaratish
Boshqaruv panelini yig'ish uchun biz Cube.js analitik ramkasidan foydalanamiz. U juda ko'p funktsiyalarga ega, ammo bizni ikkitasi qiziqtiradi: bo'lim filtrlarini avtomatik ravishda ishlatish va ma'lumotlarni oldindan yig'ish qobiliyati. U ma'lumotlar sxemasidan foydalanadi
Keling, yangi Cube.js ilovasini yarataylik. Biz allaqachon AWS stekidan foydalanayotganimiz sababli, joylashtirish uchun Lambda-dan foydalanish mantiqan to'g'ri keladi. Agar siz Cube.js backend-ni Heroku yoki Docker-da joylashtirishni rejalashtirmoqchi bo'lsangiz, avlod uchun ekspress shablondan foydalanishingiz mumkin. Hujjatlar boshqalarni tavsiflaydi
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Muhit o'zgaruvchilari cube.js da ma'lumotlar bazasiga kirishni sozlash uchun ishlatiladi. Generator .env faylini yaratadi, unda siz kalitlaringizni belgilashingiz mumkin
Endi bizga kerak
Katalogda schema
, fayl yarating Logs.js
. Mana nginx uchun namuna ma'lumotlar modeli:
Model kodi
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`
}
}
});
Bu erda biz o'zgaruvchidan foydalanamiz
Shuningdek, biz asboblar panelida ko'rsatmoqchi bo'lgan ko'rsatkichlar va parametrlarni o'rnatamiz va oldindan yig'ilishlarni aniqlaymiz. Cube.js oldindan jamlangan ma'lumotlarga ega qo'shimcha jadvallarni yaratadi va ma'lumotlar kelishi bilan avtomatik ravishda yangilanadi. Bu nafaqat so'rovlarni tezlashtiradi, balki Athena'dan foydalanish narxini ham kamaytiradi.
Keling, ushbu ma'lumotni ma'lumotlar sxemasi fayliga qo'shamiz:
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 ushbu modelda foydalanilgan barcha ko'rsatkichlar uchun ma'lumotlarni oldindan jamlash va oylar bo'yicha qismlarga ajratish zarurligini aniqlaymiz.
Endi biz asboblar panelini yig'ishimiz mumkin!
Cube.js backend taqdim etadi
Cube.js serveri so'rovni qabul qiladi
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
NPM orqali Cube.js mijozi va React komponentlar kutubxonasini o'rnatamiz:
$ npm i --save @cubejs-client/core @cubejs-client/react
Biz komponentlarni import qilamiz cubejs
ΠΈ QueryRenderer
ma'lumotlarni yuklab olish va asboblar panelini yig'ish uchun:
Boshqaruv paneli kodi
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>
);
}}
/>
)
}
Boshqaruv paneli manbalari bu yerda mavjud
Manba: www.habr.com