Одатан, маҳсулоти тиҷоратӣ ё алтернативаҳои кушодаи кушода, ба монанди Prometheus + Grafana, барои назорат ва таҳлили кори Nginx истифода мешаванд. Ин як варианти хуб барои мониторинг ё таҳлили вақти воқеӣ аст, аммо барои таҳлили таърихӣ чандон қулай нест. Дар ҳама гуна манбаи маъмул, ҳаҷми маълумот аз гузоришҳои nginx босуръат меафзояд ва барои таҳлили миқдори зиёди маълумот, истифодаи чизи махсусгардонидашуда мантиқист.
Дар ин мақола ман ба шумо мегӯям, ки чӣ тавр шумо метавонед истифода баред
TL: DR;
Барои ҷамъоварии маълумот мо истифода мебарем
Ҷамъоварии гузоришҳои Nginx
Бо нобаёнӣ, гузоришҳои Nginx чунинанд:
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" "-"
Онҳоро метавон таҳлил кард, аммо ислоҳ кардани конфигуратсияи Nginx хеле осонтар аст, то он дар JSON гузоришҳоро тавлид кунад:
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;
S3 барои нигоҳдорӣ
Барои нигоҳ доштани гузоришҳо, мо S3-ро истифода мебарем. Ин ба шумо имкон медиҳад, ки гузоришҳоро дар як ҷо нигоҳ доред ва таҳлил кунед, зеро Athena метавонад мустақиман бо маълумот дар S3 кор кунад. Баъдтар дар мақола ман ба шумо мегӯям, ки чӣ гуна сабтҳоро дуруст илова кардан ва коркард кардан лозим аст, аммо аввал ба мо як сатили тоза дар S3 лозим аст, ки дар он ҳеҷ чизи дигар нигоҳ дошта намешавад. Бояд пешакӣ баррасӣ кард, ки шумо сатили худро дар кадом минтақа эҷод мекунед, зеро Афина дар ҳама минтақаҳо дастрас нест.
Эҷоди схема дар консол Athena
Биёед дар Athena барои гузоришҳо ҷадвал эҷод кунем. Он ҳам барои навиштан ва ҳам хондан лозим аст, агар шумо нақшаи истифодаи Kinesis Firehose-ро дошта бошед. Консоли Athena -ро кушоед ва ҷадвал эҷод кунед:
Эҷоди ҷадвали SQL
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
Kinesis Firehose маълумоти аз Nginx ба S3 гирифташударо дар формати интихобшуда менависад ва онро ба директорияҳо дар формати YYYY/MM/DD/HH тақсим мекунад. Ин ҳангоми хондани маълумот муфид хоҳад буд. Шумо, албатта, метавонед мустақиман ба S3 аз fluentd нависед, аммо дар ин ҳолат шумо бояд JSON нависед ва ин аз сабаби андозаи калони файлҳо бесамар аст. Илова бар ин, ҳангоми истифодаи PrestoDB ё Athena, JSON формати сусттарини додаҳо мебошад. Пас, консоли Kinesis Firehose -ро кушоед, "Эҷод кардани ҷараёни интиқол" -ро клик кунед, дар майдони "расмкунӣ" "ПУСи мустақим" -ро интихоб кунед:
Дар ҷадвали навбатӣ, "Табдилдиҳии формати сабт" - "Фаъол" -ро интихоб кунед ва ҳамчун формати сабт "Apache ORC" -ро интихоб кунед. Мувофики баъзе тадкикотхо
Мо S3-ро барои нигоҳдорӣ ва сатил, ки қаблан сохта будем, интихоб мекунем. Aws Glue Crawler, ки ман каме дертар дар бораи он сӯҳбат хоҳам кард, наметавонад бо префиксҳо дар сатили S3 кор кунад, аз ин рӯ муҳим аст, ки онро холӣ гузоред.
Вариантҳои боқимонда метавонанд вобаста ба сарбории шумо тағир дода шаванд; Ман одатан имконоти пешфарзро истифода мебарам. Дар хотир доред, ки фишурдани S3 дастрас нест, аммо ORC бо нобаёнӣ фишурдани маҳаллиро истифода мебарад.
равон
Акнун, ки мо сабт ва қабули сабтҳоро танзим кардем, мо бояд ирсолро танзим кунем. истифода мебарем
Аввалан, ба мо файли конфигуратсияи fluent.conf лозим аст. Онро эҷод кунед ва манбаъ илова кунед:
нуқтаи 24224
баста 0.0.0.0
Акнун шумо метавонед сервери Fluentd-ро оғоз кунед. Агар ба шумо конфигуратсияи пешрафта лозим бошад, ба он равед
$ 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
Ин конфигуратсия роҳро истифода мебарад /fluentd/log
пеш аз фиристодан сабтҳоро кэш кунед. Шумо метавонед бе ин кор кунед, аммо вақте ки шумо бозоғоз мекунед, шумо метавонед ҳама чизеро, ки бо меҳнати қафомонда кэш карда шудааст, аз даст диҳед. Шумо инчунин метавонед ягон портро истифода баред; 24224 бандари пешфарз Fluentd аст.
Ҳоло, ки мо Fluentd кор карда истодаем, мо метавонем гузоришҳои Nginx-ро ба он ҷо фиристем. Мо одатан Nginx-ро дар як контейнери Docker иҷро мекунем, дар ин ҳолат Docker дорои драйвери сабти сабти аслии Fluentd мебошад:
$ 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-ро ба таври дигар иҷро кунед, шумо метавонед файлҳои сабтро истифода баред, Fluentd дорад
Биёед таҳлили сабти дар боло танзимшударо ба конфигуратсияи Fluent илова кунем:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Ва фиристодани гузоришҳо ба Kinesis бо истифода аз
<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>
Афина
Агар шумо ҳама чизро дуруст танзим карда бошед, пас аз муддате (бо нобаёнӣ, Kinesis маълумоти гирифташударо дар ҳар 10 дақиқа як маротиба сабт мекунад) шумо бояд файлҳои сабтро дар S3 бинед. Дар менюи "мониторинг"-и Kinesis Firehose шумо метавонед бубинед, ки чӣ қадар маълумот дар S3 сабт шудааст ва инчунин хатогиҳо. Фаромӯш накунед, ки дастрасии навиштан ба сатили S3 ба нақши Kinesis. Агар Kinesis чизеро таҳлил карда натавонад, он хатогиҳоро ба ҳамон сатил илова мекунад.
Акнун шумо метавонед маълумотро дар Афина дидан кунед. Биёед дархостҳои охиринро пайдо кунем, ки мо хатогиҳоро баргардонидем:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Скан кардани ҳама сабтҳо барои ҳар як дархост
Ҳоло гузоришҳои мо дар S3 дар ORC коркард ва нигоҳ дошта шудаанд, фишурда шудаанд ва барои таҳлил омодаанд. Kinesis Firehose ҳатто онҳоро ба феҳристҳо барои ҳар соат ташкил дод. Аммо, то он даме, ки ҷадвал тақсим карда нашавад, Athena маълумоти ҳама вақтро дар ҳар дархост, ба истиснои истисноҳои нодир бор мекунад. Ин як мушкили бузург барои ду сабаб аст:
- Ҳаҷми маълумот пайваста афзоиш ёфта, дархостҳоро суст мекунад;
- Athena дар асоси ҳаҷми маълумоти сканшуда бо ҳадди ақал 10 МБ барои як дархост ҳисоб карда мешавад.
Барои ислоҳи ин, мо AWS Glue Crawler-ро истифода мебарем, ки он маълумотро дар S3 ҷустуҷӯ мекунад ва маълумоти тақсимотро ба Glue Metastore менависад. Ин ба мо имкон медиҳад, ки қисмҳоро ҳамчун филтр ҳангоми дархости Athena истифода барем ва он танҳо директорияҳои дар дархост нишондодашударо скан мекунад.
Насб кардани Amazon Glue Crawler
Amazon Glue Crawler тамоми маълумотро дар сатили S3 скан мекунад ва ҷадвалҳо бо қисмҳо эҷод мекунад. Аз консоли AWS Glue Crawler Glue эҷод кунед ва сатилеро илова кунед, ки шумо маълумотро нигоҳ медоред. Шумо метавонед як браузерро барои якчанд сатил истифода баред, дар ин ҳолат он дар базаи додашуда ҷадвалҳоро бо номҳое месозад, ки ба номи сатилҳо мувофиқат мекунанд. Агар шумо нақшаи истифодаи мунтазами ин маълумотро дошта бошед, боварӣ ҳосил кунед, ки ҷадвали оғози Crawler-ро мувофиқи эҳтиёҷоти худ танзим кунед. Мо барои ҳама ҷадвалҳо як Crawler истифода мебарем, ки ҳар соат кор мекунад.
Ҷадвалҳои тақсимшуда
Пас аз оғози аввалини кроулер, ҷадвалҳо барои ҳар як сатили сканшуда бояд дар пойгоҳи додаҳои дар танзимот нишондодашуда пайдо шаванд. Консол Athena -ро кушоед ва ҷадвалро бо гузоришҳои Nginx пайдо кунед. Биёед кӯшиш кунем, ки чизе бихонем:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Ин дархост ҳамаи сабтҳои аз соати 6 то 7 субҳи 8 апрели соли 2019 гирифташударо интихоб мекунад. Аммо ин аз хондан аз ҷадвали тақсимнашуда то чӣ андоза самараноктар аст? Биёед ҳамон сабтҳоро фаҳмем ва интихоб кунем ва онҳоро аз рӯи тамғаи вақт филтр кунем:
3.59 сония ва 244.34 мегабайт маълумот дар маҷмӯи додаҳо бо танҳо як ҳафтаи гузоришҳо. Биёед филтрро аз рӯи қисмат санҷем:
Каме тезтар, вале муҳимтар аз ҳама - танҳо 1.23 мегабайт маълумот! Ин хеле арзонтар мебуд, агар на камтар аз 10 мегабайт барои як дархост дар нархгузорӣ. Аммо он ҳоло ҳам хеле беҳтар аст ва дар маҷмӯи додаҳои калон фарқият хеле таъсирбахштар хоҳад буд.
Сохтани панели идоракунӣ бо истифода аз Cube.js
Барои ҷамъ кардани панели идоракунӣ, мо чаҳорчӯбаи таҳлилии Cube.js -ро истифода мебарем. Он дорои функсияҳои хеле зиёд аст, аммо мо ба ду чиз таваҷҷӯҳ дорем: қобилияти ба таври худкор истифода бурдани филтрҳои тақсимот ва ҷамъоварии пешакии додаҳо. Он схемаи маълумотро истифода мебарад
Биёед як барномаи нави Cube.js эҷод кунем. Азбаски мо аллакай стеки AWS-ро истифода мебарем, истифодаи Lambda барои ҷойгиркунӣ мантиқист. Шумо метавонед қолаби экспрессро барои насл истифода баред, агар шумо ният доред, ки пуштибонии Cube.js-ро дар Heroku ё Docker ҷойгир кунед. Ҳуҷҷатҳо дигаронро тавсиф мекунанд
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Тағирёбандаҳои муҳити зист барои танзим кардани дастрасии пойгоҳи додаҳо дар cube.js истифода мешаванд. Генератор файли .env эҷод мекунад, ки дар он шумо калидҳои худро барои он муайян карда метавонед
Акнун ба мо лозим аст
Дар директория schema
, файл эҷод кунед Logs.js
. Дар ин ҷо як намунаи маълумот барои nginx:
Рамзи намунавӣ
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`
}
}
});
Дар ин ҷо мо тағирёбандаро истифода мебарем
Мо инчунин ченакҳо ва параметрҳоеро муқаррар мекунем, ки мо мехоҳем дар панели идоракунӣ намоиш диҳем ва ҷамъбасти пешакӣ муайян кунем. Cube.js бо маълумоти пешакӣ ҷамъшуда ҷадвалҳои иловагӣ эҷод мекунад ва ҳангоми расидан ба таври худкор маълумотро нав мекунад. Ин на танҳо дархостҳоро суръат мебахшад, балки арзиши истифодаи Athena-ро коҳиш медиҳад.
Биёед ин маълумотро ба файли схемаи додаҳо илова кунем:
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`
)
}
}
}
Мо дар ин модел муайян мекунем, ки маълумотро барои ҳама ченакҳои истифодашуда пешакӣ ҷамъоварӣ кардан ва тақсимкуниро аз рӯи моҳ истифода бурдан лозим аст.
Акнун мо метавонем панели идоракуниро ҷамъ кунем!
Cube.js пуштибониро таъмин мекунад
Сервери Cube.js дархостро дар
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Биёед муштарии Cube.js ва китобхонаи ҷузъҳои Reactро тавассути NPM насб кунем:
$ npm i --save @cubejs-client/core @cubejs-client/react
Мо ҷузъҳоро ворид мекунем cubejs
и QueryRenderer
Барои зеркашии маълумот ва ҷамъоварии панели идоракунӣ:
Рамзи панели идоракунӣ
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>
);
}}
/>
)
}
Сарчашмаҳои панели дастрас дар
Манбаъ: will.com