Tavaliselt Nginxi jälgimiseks ja analüüsimiseks kasutatakse kaubanduslikke tooteid või valmis open-source alternatiive, nagu Prometheus + Grafana. See on hea võimalus jälgimiseks või reaalaja analüüsiks, kuid mitte eriti mugav ajalooliseks analüüsiks. Iga populaarse ressursi puhul kasvab Nginxi logide maht kiiresti ja suure hulga andmete analüüsimiseks on mõistlik kasutada midagi spetsialiseeritumat.
Selles artiklis räägin, kuidas kasutada logide analüüsimiseks, kasutades Nginxi näitena, ning näitan, kuidas neist andmetest kokku panna analüütiline armatuurlaud open-source raamistiku cube.js abil. Siin on lahenduse täpparchitecture:

TL:DR;
.
Informatsiooni kogumiseks kasutame , töötlemiseks — ja , salvestamiseks — . Selle koosseisuga on võimalik salvestada mitte ainult Nginxi logisid, vaid ka teisi sündmusi ning ka teiste teenuste logisid. Saate mõned osad asendada sarnastega oma tech stack'ist, näiteks kirjutada logisid otse Kinesis'sse Nginxist, vahele jättes fluentd, või kasutada logstash'i.
Kogume Nginxi logisid
Vaikimisi näevad Nginxi logid välja enam-vähem nii:
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" "-"Neid saab analüüsida, kuid palju lihtsam on muuta Nginxi konfiguratsiooni, et logid väljastataks JSON formaadis:
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 salvestamiseks
Logide salvestamiseks kasutame S3. See võimaldab logisid ühes kohas salvestada ja analüüsida, kuna Athena saab otse S3-s andmetega töötada. Edasi artiklis räägin, kuidas logisid õigesti korraldada ja töödelda, kuid kõigepealt vajame puhast S3 ämbrit, kus midagi muud ei hoita. Tasub eelnevalt mõelda, millises regioonis te ämbrit loodud, kuna Athena ei ole kõikides piirkondades saadaval.
Loome skeemi Athena konsoolis
Loome Athena-s logide jaoks tabeli. See on vajalik nii kirjutamiseks kui lugemiseks, kui kavatsete kasutada Kinesis Firehose'i. Avage Athena konsool ja looge tabel:
SQL tabeli loomiseks
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://'
TBLPROPERTIES ('has_encrypted_data'='false');Loome Kinesis Firehose Stream'i
Kinesis Firehose salvestab Nginxilt saadud andmed S3-s valitud formaadis, jagades need kaustadesse formaadis AASTA/KUUPÄEV/TUND. See on kasulik andmete lugemisel. Loomulikult võib otse S3-sse kirjutada fluentd-st, kuid sel juhul tuleb kirjutada JSON-i, mis ei ole efektiivne suurte failide tõttu. Lisaks sellele, kui kasutatakse PrestoDB või Athena't, on JSON kõige aeglasem andmevorm.

Avame Kinesis Firehose konsooli, klõpsame 'Create delivery stream', valime 'direct PUT' 'delivery' väljal: Owen O’Malley

, see on PrestoDB ja Athena jaoks optimaalne formaat. Skeemina näitame tabelit, mille me eelnevalt lõime. Pange tähele, et Kinesis's saab S3 asukoha määrata igasuguseks, tabelis kasutatakse vaid skeemi. Kuid kui määrate teistsuguse S3 asukoha, siis ei õnnestu neid kirjeid selle tabeli kaudu lugeda.

Valime S3 salvestamiseks ja ämbri, mille me varem lõime. Aws Glue Crawler, millest räägin veidi hiljem, ei oska töötada S3 ämbri prefiksitega, seega on oluline see tühi hoida.
Fluentd
Ülejäänud valikuid saab muuta vastavalt teie koormusele, mina kasutan tavaliselt vaikeseadeid. Pange tähele, et S3 tihendamine ei ole saadaval, kuid ORC kasutab vaikimisi enda tihendust. Nüüd, kui me oleme seadnud logide salvestamise ja hankimise, peame seadma edastamise. Kasutame
, sest mulle meeldib Ruby, kuid te võite kasutada Logstash'i või saata logisid otse Kinesis'sse. Fluentd serveri saab käivitada mitmel viisil, räägin docker'ist, kuna see on lihtne ja mugav.
forward
port 24224
bind 0.0.0.0
Nüüd saab käivitada Fluentd serveri. Kui vajate keerukamat seadistust, on üksikasjalik juhend, sealhulgas kuidas luua oma pilti.
$ docker run
-d
-p 24224:24224
-p 24224:24224/udp
-v /data:/fluentd/log
-v :/fluentd/etc fluentd
-c /fluentd/etc/fluent.conf
fluent/fluentd:stableSee seadistus kasutab teed /fluentd/log logide vahemällu salvestamiseks enne edastamist. Ilma selleta võib andmete kaotamine alates taaskäivitamisest juhtuda. Samuti võib kasutada mõnda muud porti, 24224 on Fluentd vaikimisi port.
Nüüd, kui meil on töötav Fluentd, saame edastada sinna Nginx logid. Me tavaliselt käivitame Nginx Docker konteineris ning sel juhul on Dockeril Fluentd jaoks natiivne logide draiver:
$ docker run
--log-driver=fluentd
--log-opt fluentd-address=
--log-opt tag="{{.Name}}"
-v /some/content:/usr/share/nginx/html:ro
-d
nginxKui käitate Nginx muul viisil, saate kasutada logifailide, Fluentd-l on .
Lisame Fluenti seadistusse logide töötlemise, mis on seadistatud ülaltoodud:
@type parser
key_name log
emit_invalid_record_to_error false
@type jsonja logide edastamine Kinesisesse, kasutades :
@type kinesis_firehose
region region
delivery_stream_name
aws_key_id
aws_sec_keyAthena
Kui olete kõik õigesti seadnud, siis mõne aja pärast (Kinesis salvestab saadud andmed iga 10 minuti tagant) peaksite nägema logifailide S3-s. Kinesis Firehose-i 'monitoring' menüüst näete, kui palju andmeid on S3-sse salvestatud ning ka vigu. Ärge unustage anda Kinesise rollile kirjutamisõigust S3 baketile. Kui Kinesis midagi ei suutnud töödelda, salvestab see vead samasse baketti.
Nüüd saame andmeid vaadata Athenas. Otsime uusi päringuid, millele oleme vead andnud:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;Küsin kõiki kirjeid iga päringu jaoks
Nüüd on meie logid töödeldud ja salvestatud S3-s ORC-vormingus, komprimeeritud ja analüüsimiseks valmis. Kinesis Firehose on isegi jaganud need kaustadesse iga tunni kohta. Kuid seni, kuni tabel ei ole partitsioneeritud, laadib Athena igas päringus andmed kogu aja jooksul, eranditega. See on suur probleem kahel põhjusel:
- Andmete maht kasvab pidevalt, aeglustades päringuid;
- Athenale esitatav arve arvutatakse skaneeritud andmete mahu alusel, miinimumiga 10 MB iga päringu kohta.
Selle parandamiseks kasutame AWS Glue kraan, mis skaneerib andmeid S3-s ja salvestab teabe partitsioonide kohta Glue Metastore'i. See võimaldab meil partitsioone filtri kaudu päringutes kasutada, ja see skaneerib ainult katalooge, mis on päringus näidatud.
Seadistame Amazon Glue kraani
Amazon Glue kraan skaneerib kõik andmed S3 baketis ja loob tabelid partitsioonide kaupa. Looge Glue kraan AWS Glue konsoolist ja lisage baketis, kus andmeid hoiate. Saate kasutada ühte kraani mitme baketi jaoks, sel juhul loob see tabelid näidatud andmebaasis nimedega, mis vastavad bakettide nimedele. Kui kavatsete neid andmeid pidevalt kasutada, ärge unustage seadistada kraani käivitamise ajakava vastavalt oma vajadustele. Me kasutame ühte kraani, mis käivitub iga tunni tagant, kõigile tabelitele.
Partitsioneeritud tabelid
Pärast kraani esimest käivitamist peaksid seadistustes määratud andmebaasis ilmnema tabelid iga skaneeritud baketi jaoks. Avage Athena konsool ja leidke Nginx logide tabel. Proovime midagi lugeda:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);See päring valib kõik kirjed, mis on saadud 8. aprillil 2019 kella 6-7 vahel. Kuid kui palju efektiivsem see on kui lihtsalt lugeda mitte-partitsioneeritud tabelist? Uurime ja valime samad kirjed, filtreerides neid ajatempli järgi:

3.59 sekundit ja 244.34 megabaiti andmeid andmesetis, kus on vaid nädal logisid. Proovime partitsioonide põhjal filtrit:

Veidi kiiremini, kuid kõige olulisem — ainult 1.23 megabaiti andmeid! See oleks palju odavam, kui mitte minimaalne 10 megabaiti iga päringu hinda. Kuid siiski palju parem, ja suuremate andmesettidega on erinevus palju muljetavaldavam.
Собираем дэшборд с помощью Cube.js
Däshbordi loomiseks kasutame analüütilist raamistiku Cube.js. Sellel on päris palju funktsioone, kuid meid huvitavad kaks: võimalus automaatselt kasutada filtreid partitsioonide põhjal ja andmete eelkokkuvõtmist. See kasutab andmeskeemi , mis on kirjutatud JavaScriptis, et genereerida SQL ja teostada päring andmebaasile. Meilt nõutakse vaid partitsioonifiltri kasutamise määramist andmeskeemis.
Loome uus Cube.js rakendus. Kuna me juba kasutame AWS-stäkki, on mõistlik kasutada Lambda rakenduse juurutamiseks. Saate kasutada express-malli, kui plaanite Cube.js tagaplaati majutada Herokus või Dockeris. Dokumentatsioonis on kirjas teised .
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athenaCube.js-sse andmebaasi juurdepääsu seadistamiseks kasutatakse keskkonnamuutujaid. Generaator loob .env faili, kuhu saate sisestada oma võtmed .
Nüüd vajame , kus määratleme, kuidas meie logisid salvestatakse. Seal on ka võimalik märkida, kuidas arvutada mõõdikud juhtpaneelide jaoks.
Kataloogis skeemaga, tehke uus fail Logs.js. Siin on näide andmemudelist nginx'i jaoks:
Mudeli kood
const partitionFilter = (from, to) => `
date(from_iso8601_timestamp(${from})) = 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: `Jah`
}],
else: { label: `Ei` }
}
},
createdAt: {
sql: `from_unixtime(created_at)`,
type: `time`
}
}
});Siin kasutame muutujaid , et genereerida SQL päring koos partitsioonide filtriga.
Seame ka mõõdikud ja parameetrid, mida soovime juhtpaneelil kuvada, ning määratleme eel-agregeerimised. Cube.js loob täiendavad tabelid eel-agregeeritud andmete jaoks ja uuendab andmeid automaatsete tulude ajal. See mitte ainult ei kiirenda päringute täitmist, vaid vähendab ka Athena kasutamise kulusid.
Lisame selle teabe andmemudeli faili:
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`
)
}
}
}Märgitame selles mudelis, et andmed tuleb eel-agregeerida kõigi kasutatavate mõõdikutega ja kasutada partitsioneerimist kuude kaupa. võib tõhusalt kiirendada andmete kogumist ja uuendamist.
Nüüd saame juhtpaneeli kokku panna!
Cube.js tagaplaan pakub ja komplekti klienditeeke populaarsete front-end raamistike jaoks. Kasutame juhtpaneeli kokkupanekuks React-i kliendi versiooni. Cube.js pakub ainult andmeid, seega vajame visualiseerimiste teeki — mulle meeldib , kuid võite kasutada ükskõik millist.
Cube.js server aktsepteerib päringut , kus on määratletud vajalikud mõõdikud. Näiteks, et küsida, kui palju vigu Nginx igapäevaselt tagastas, tuleb saata järgmine päring:
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}Installime Cube.js kliendi ja React-komponendi teegi läbi NPM:
$ npm i --save @cubejs-client/core @cubejs-client/reactImporime komponendid cubejs ja QueryRenderer, et andmeid laadida, ja koondame juhtpaneeli:
Juhtpaneeli kood
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 (
{
if (!resultSet) {
return 'Laadimine...';
}
return (
);
}}
/>
)
}Juhtpaneeli lähtekood on saadaval .
Allikas: habr.com
