Адатта, Nginxтин иштешин көзөмөлдөө жана талдоо үчүн Prometheus + Grafana сыяктуу коммерциялык продуктылар же даяр ачык булак альтернативалары колдонулат. Бул мониторинг же реалдуу убакыттагы аналитика үчүн жакшы вариант, бирок тарыхый талдоо үчүн абдан ыңгайлуу эмес. Ар кандай популярдуу ресурста 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 агымын түзүү
Kinesis Firehose тандалган форматта Nginxтен S3ге алынган маалыматтарды жазып, аны ЖЖЖЖ/АА/КК/СС форматындагы каталогдорго бөлөт. Бул маалыматтарды окуп жатканда пайдалуу болот. Сиз, албетте, Fluentdден түз S3ке жаза аласыз, бирок бул учурда сиз JSON жазууга туура келет жана бул файлдардын чоңдугуна байланыштуу натыйжасыз. Мындан тышкары, PrestoDB же Athena колдонуп жатканда, JSON эң жай маалымат форматы. Ошентип, Kinesis Firehose консолун ачып, "Жеткирүү агымын түзүү" баскычын чыкылдатып, "жеткирүү" талаасында "түз PUT" тандаңыз:
Кийинки өтмөктө "Жазуу форматын өзгөртүү" - "Иштелет" жана жазуу форматы катары "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-те канча маалымат жазылганын, ошондой эле каталарды көрө аласыз. Kinesis ролуна S3 чакага жазуу мүмкүнчүлүгүн берүүнү унутпаңыз. Эгерде Kinesis бир нерсени талдай албаса, анда ал каталарды ошол эле чакага кошот.
Эми сиз Athena маалыматтарды көрө аласыз. Биз каталарды кайтарган акыркы сурамдарды табалы:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Ар бир суроо үчүн бардык жазууларды сканерлөө
Азыр биздин журналдар ORCде S3 форматында иштетилип, сакталып, кысылып, анализге даяр. Kinesis Firehose аларды ар бир саат үчүн каталогдорго да уюштурган. Бирок, үстөл бөлүнбөсө, Athena сейрек учурларды эске албаганда, ар бир сурам боюнча бардык убактагы маалыматтарды жүктөйт. Бул эки себеп боюнча чоң көйгөй:
- Маалыматтын көлөмү тынымсыз өсүүдө, суроо-талаптарды жайлатууда;
- Athena үчүн эсеп сканерленген берилиштердин көлөмүнө жараша төлөнөт, ар бир суроо үчүн эң аз дегенде 10 МБ.
Муну оңдоо үчүн биз AWS Glue Crawler колдонобуз, ал S3 ичиндеги маалыматтарды сойлоп, Glue Metastore'го бөлүү маалыматын жазат. Бул бизге Athena сурамында бөлүмдөрдү фильтр катары колдонууга мүмкүндүк берет жана ал суроодо көрсөтүлгөн каталогдорду гана сканерлейт.
Amazon Glue Crawler орнотулууда
Amazon Glue Crawler S3 чакасындагы бардык маалыматтарды сканерлейт жана бөлүмдөрү бар таблицаларды түзөт. AWS Glue консолунан Glue Crawler түзүңүз жана дайындарды сактаган чака кошуңуз. Сиз бир жөрмөлөгүчтү бир нече чака үчүн колдоно аласыз, бул учурда ал көрсөтүлгөн маалымат базасында чакалардын атына дал келген аталыштар менен таблицаларды түзөт. Эгер сиз бул маалыматты үзгүлтүксүз колдонууну пландасаңыз, Crawlerin ишке киргизүү графигин сиздин муктаждыктарыңызга ылайыкташтырууну унутпаңыз. Биз бардык таблицалар үчүн бир 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 же Докерде жайгаштырууну пландап жатсаңыз, экспресс шаблонду муун үчүн колдоно аласыз. Документтер башкаларды сүрөттөйт
$ 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 алдын ала топтолгон маалыматтар менен кошумча таблицаларды түзөт жана ал келгенде автоматтык түрдө маалыматтарды жаңыртат. Бул сурамдарды тездетип гана койбостон, Афинаны колдонуунун баасын да азайтат.
Келгиле, бул маалыматты маалымат схемасы файлына кошолу:
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 backend камсыз кылат
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>
);
}}
/>
)
}
Куралдар тактасынын булактары бул жерден жеткиликтүү
Source: www.habr.com