Në mënyrë tipike, produktet komerciale ose alternativat e gatshme me burim të hapur, si Prometheus + Grafana, përdoren për të monitoruar dhe analizuar funksionimin e Nginx. Ky është një opsion i mirë për monitorim ose analiza në kohë reale, por jo shumë i përshtatshëm për analiza historike. Në çdo burim popullor, vëllimi i të dhënave nga regjistrat nginx po rritet me shpejtësi, dhe për të analizuar një sasi të madhe të dhënash, është logjike të përdoret diçka më e specializuar.
Në këtë artikull do t'ju tregoj se si mund ta përdorni
TL:DR;
Për të mbledhur informacion që ne përdorim
Mbledhja e regjistrave Nginx
Si parazgjedhje, regjistrat e Nginx duken diçka si kjo:
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" "-"
Ato mund të analizohen, por është shumë më e lehtë të korrigjosh konfigurimin Nginx në mënyrë që të prodhojë regjistrat në 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 për ruajtje
Për të ruajtur regjistrat, ne do të përdorim S3. Kjo ju lejon të ruani dhe analizoni regjistrat në një vend, pasi Athena mund të punojë drejtpërdrejt me të dhënat në S3. Më vonë në artikull do t'ju tregoj se si të shtoni dhe përpunoni saktë regjistrat, por së pari na duhet një kovë e pastër në S3, në të cilën nuk do të ruhet asgjë tjetër. Vlen të merret parasysh paraprakisht se në cilin rajon do të krijoni kovën tuaj, sepse Athena nuk është e disponueshme në të gjitha rajonet.
Krijimi i një qarku në tastierën Athena
Le të krijojmë një tabelë në Athena për shkrimet. Është i nevojshëm si për shkrim ashtu edhe për lexim nëse planifikoni të përdorni Kinesis Firehose. Hapni konsolën Athena dhe krijoni një tabelë:
Krijimi i tabelës 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');
Krijimi i Kinesis Firehose Stream
Kinesis Firehose do të shkruajë të dhënat e marra nga Nginx në S3 në formatin e zgjedhur, duke i ndarë ato në drejtori në formatin YYYY/MM/DD/HH. Kjo do të jetë e dobishme kur lexoni të dhëna. Sigurisht, mund të shkruani direkt në S3 nga fluentd, por në këtë rast do t'ju duhet të shkruani JSON, dhe kjo është joefikase për shkak të madhësisë së madhe të skedarëve. Për më tepër, kur përdorni PrestoDB ose Athena, JSON është formati më i ngadaltë i të dhënave. Pra, hapni tastierën Kinesis Firehose, klikoni "Krijo transmetimin e dorëzimit", zgjidhni "PUT direkt" në fushën "dorëzimi":
Në skedën tjetër, zgjidhni "Konvertimi i formatit të regjistrimit" - "Aktivizuar" dhe zgjidhni "Apache ORC" si formatin e regjistrimit. Sipas disa hulumtimeve
Ne zgjedhim S3 për ruajtje dhe kovën që krijuam më parë. Aws Glue Crawler, për të cilin do të flas pak më vonë, nuk mund të funksionojë me parashtesa në një kovë S3, kështu që është e rëndësishme ta lini bosh.
Opsionet e mbetura mund të ndryshohen në varësi të ngarkesës suaj; Unë zakonisht përdor ato të paracaktuara. Vini re se kompresimi S3 nuk është i disponueshëm, por ORC përdor si parazgjedhje kompresimin vendas.
I rrjedhshëm
Tani që kemi konfiguruar ruajtjen dhe marrjen e regjistrave, duhet të konfigurojmë dërgimin. ne do të përdorim
Së pari, na duhet skedari i konfigurimit fluent.conf. Krijojeni atë dhe shtoni burimin:
porti 24224
lidh 0.0.0.0
Tani mund të nisni serverin Fluentd. Nëse keni nevojë për një konfigurim më të avancuar, shkoni te
$ 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
Ky konfigurim përdor shtegun /fluentd/log
për të ruajtur regjistrat para dërgimit. Ju mund të bëni pa këtë, por më pas kur të rindizni, mund të humbni gjithçka të ruajtur në memorien tuaj me punë të pakëndshme. Ju gjithashtu mund të përdorni çdo port; 24224 është porti i parazgjedhur Fluentd.
Tani që kemi funksionimin e Fluentd, ne mund të dërgojmë regjistrat e Nginx atje. Ne zakonisht e drejtojmë Nginx në një kontejner Docker, në të cilin rast Docker ka një drejtues logimi vendas për 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
Nëse e drejtoni Nginx ndryshe, mund të përdorni skedarë log, ka Fluentd
Le të shtojmë analizën e regjistrit të konfiguruar më lart në konfigurimin Fluent:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Dhe dërgimi i regjistrave në Kinesis duke përdorur
<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>
Athinë
Nëse keni konfiguruar gjithçka në mënyrë korrekte, atëherë pas një kohe (si parazgjedhje, Kinesis regjistron të dhënat e marra një herë në 10 minuta) duhet të shihni skedarët e regjistrave në S3. Në menynë e “monitorimit” të Kinesis Firehose mund të shihni se sa të dhëna janë regjistruar në S3, si dhe gabime. Mos harroni të jepni akses shkrimi në kovën S3 në rolin Kinesis. Nëse Kinesis nuk mund të analizojë diçka, ai do të shtojë gabimet në të njëjtën kovë.
Tani mund t'i shikoni të dhënat në Athena. Le të gjejmë kërkesat më të fundit për të cilat kemi kthyer gabime:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Skanimi i të gjitha të dhënave për secilën kërkesë
Tani regjistrat tanë janë përpunuar dhe ruajtur në S3 në ORC, të ngjeshur dhe gati për analizë. Kinesis Firehose madje i organizoi ato në drejtori për çdo orë. Megjithatë, për sa kohë që tabela nuk është e ndarë, Athena do të ngarkojë të dhënat e të gjitha kohërave për çdo kërkesë, me përjashtime të rralla. Ky është një problem i madh për dy arsye:
- Vëllimi i të dhënave po rritet vazhdimisht, duke ngadalësuar pyetjet;
- Athena faturohet në bazë të vëllimit të të dhënave të skanuara, me një minimum prej 10 MB për kërkesë.
Për ta rregulluar këtë, ne përdorim AWS Glue Crawler, i cili do të zvarritet të dhënat në S3 dhe do të shkruajë informacionin e ndarjes në Glue Metastore. Kjo do të na lejojë të përdorim ndarjet si filtër kur kërkojmë Athena dhe do të skanojmë vetëm drejtoritë e specifikuara në pyetje.
Konfigurimi i Amazon Glue Crawler
Amazon Glue Crawler skanon të gjitha të dhënat në kovën S3 dhe krijon tabela me ndarje. Krijoni një Glue Crawler nga tastiera AWS Glue dhe shtoni një kovë ku ruani të dhënat. Ju mund të përdorni një zvarritës për disa kova, në këtë rast ai do të krijojë tabela në bazën e të dhënave të specifikuar me emra që përputhen me emrat e kovave. Nëse planifikoni t'i përdorni këto të dhëna rregullisht, sigurohuni që të konfiguroni orarin e nisjes së Crawler për t'iu përshtatur nevojave tuaja. Ne përdorim një Crawler për të gjitha tabelat, i cili funksionon çdo orë.
Tavolina të ndara
Pas nisjes së parë të zvarritësit, tabelat për secilën kovë të skanuar duhet të shfaqen në bazën e të dhënave të specifikuar në cilësimet. Hapni konsolën Athena dhe gjeni tabelën me regjistrat Nginx. Le të përpiqemi të lexojmë diçka:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Ky pyetje do të zgjedhë të gjitha regjistrimet e marra midis orës 6 të mëngjesit dhe orës 7 të mëngjesit më 8 prill 2019. Por sa më efikase është kjo sesa thjesht leximi nga një tabelë jo e ndarë? Le të zbulojmë dhe zgjedhim të njëjtat regjistrime, duke i filtruar ato sipas vulës kohore:
3.59 sekonda dhe 244.34 megabajt të dhëna në një grup të dhënash me vetëm një javë regjistra. Le të provojmë një filtër sipas ndarjes:
Pak më shpejt, por më e rëndësishmja - vetëm 1.23 megabajt të dhëna! Do të ishte shumë më lirë nëse jo për 10 megabajt minimale për kërkesë në çmim. Por është akoma shumë më mirë, dhe në grupe të dhënash të mëdha ndryshimi do të jetë shumë më mbresëlënës.
Ndërtimi i një pulti duke përdorur Cube.js
Për të mbledhur pultin, ne përdorim kornizën analitike Cube.js. Ka mjaft funksione, por ne jemi të interesuar për dy: aftësinë për të përdorur automatikisht filtrat e ndarjeve dhe grumbullimin paraprak të të dhënave. Ai përdor skemën e të dhënave
Le të krijojmë një aplikacion të ri Cube.js. Meqenëse ne tashmë po përdorim pirgun AWS, është logjike të përdorim Lambda për vendosje. Mund të përdorni shabllonin ekspres për gjenerim nëse planifikoni të strehoni backend-in e Cube.js në Heroku ose Docker. Dokumentacioni përshkruan të tjerët
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Variablat e mjedisit përdoren për të konfiguruar aksesin në bazën e të dhënave në cube.js. Gjeneratori do të krijojë një skedar .env në të cilin mund të specifikoni çelësat tuaj
Tani na duhet
Në drejtori schema
, krijoni një skedar Logs.js
. Këtu është një shembull modeli i të dhënave për nginx:
Kodi i modelit
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`
}
}
});
Këtu po përdorim variablin
Ne gjithashtu vendosim matjet dhe parametrat që duam të shfaqim në panelin e kontrollit dhe specifikojmë grumbullimet paraprake. Cube.js do të krijojë tabela shtesë me të dhëna të grumbulluara paraprakisht dhe do të përditësojë automatikisht të dhënat kur të mbërrijnë. Kjo jo vetëm që shpejton pyetjet, por gjithashtu zvogëlon koston e përdorimit të Athena.
Le të shtojmë këtë informacion në skedarin e skemës së të dhënave:
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`
)
}
}
}
Ne specifikojmë në këtë model se është e nevojshme të grumbullohen paraprakisht të dhënat për të gjitha metrikat e përdorura dhe të përdoren ndarjet sipas muajve.
Tani mund të montojmë pultin!
Cube.js backend ofron
Serveri Cube.js pranon kërkesën në
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Le të instalojmë klientin Cube.js dhe bibliotekën e komponentëve React përmes NPM:
$ npm i --save @cubejs-client/core @cubejs-client/react
Ne importojmë komponentë cubejs
и QueryRenderer
për të shkarkuar të dhënat dhe për të mbledhur pultin:
Kodi i pultit
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>
);
}}
/>
)
}
Burimet e panelit të kontrollit janë në dispozicion në
Burimi: www.habr.com