Vanligtvis anvÀnds kommersiella produkter eller fÀrdiga open-source-alternativ som Prometheus + Grafana för att övervaka och analysera Nginx:s prestanda. Detta Àr ett bra alternativ för övervakning eller realtidsanalys, men inte sÀrskilt praktiskt för historisk analys. PÄ varje populÀr resurs vÀxer datamÀngden frÄn Nginx-loggar snabbt, och för att analysera en stor mÀngd data Àr det logiskt att anvÀnda nÄgot mer specialiserat.
I den hÀr artikeln kommer jag att berÀtta hur man kan anvÀnda för att analysera loggar, med Nginx som exempel, och visa hur man samlar dessa data för att skapa en analytisk dashboard med hjÀlp av det open-source ramverket cube.js. HÀr Àr hela lösningens arkitektur:

TL:DR;
.
För att samla in information anvĂ€nder vi , för bearbetning â och , för lagring â . Med denna koppling kan man lagra inte bara Nginx-loggar, utan Ă€ven andra hĂ€ndelser samt loggar frĂ„n andra tjĂ€nster. Du kan byta ut vissa delar mot motsvarande för din stack, till exempel kan du skriva loggar direkt till Kinesis frĂ„n Nginx, utan att gĂ„ via Fluentd, eller anvĂ€nda Logstash för detta.
Samla loggar frÄn Nginx
Som standard ser Nginx-loggar ut ungefÀr sÄ hÀr:
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" "-"De kan parsas, men det Àr mycket enklare att justera Nginx-konfigurationen sÄ att loggarna ges i JSON-format:
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 för lagring
För att lagra loggar kommer vi att anvÀnda S3. Detta möjliggör lagring och analys av loggar pÄ ett stÀlle, eftersom Athena kan arbeta med data i S3 direkt. LÀngre fram i artikeln kommer jag att förklara hur man korrekt lagrar och bearbetar loggar, men först behöver vi en ren bucket i S3, dÀr inget annat kommer att lagras. Det Àr bra att i förvÀg tÀnka pÄ i vilken region du kommer att skapa bucketen, eftersom Athena inte Àr tillgÀnglig i alla regioner.
Skapa ett schema i Athena-konsolen
Vi kommer att skapa en tabell i Athena för loggar. Den behövs bĂ„de för inmatning och lĂ€sning, om du planerar att anvĂ€nda Kinesis Firehose. Ăppna Athena-konsolen och skapa en tabell:
SQL för att skapa tabellen
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');Skapa Kinesis Firehose Stream
Kinesis Firehose kommer att skriva data som mottas frĂ„n Nginx till S3 i det valda formatet, uppdelat i mappar enligt formatet Ă Ă Ă Ă /MM/DD/HH. Detta kommer att vara anvĂ€ndbart vid lĂ€sning av data. Du kan sjĂ€lvklart skriva direkt till S3 frĂ„n fluentd, men i sĂ„ fall mĂ„ste du skriva JSON, vilket Ă€r ineffektivt pĂ„ grund av stora filstorlekar. Dessutom Ă€r JSON det lĂ„ngsammaste dataformatet nĂ€r du anvĂ€nder PrestoDB eller Athena. SĂ„, öppna Kinesis Firehose-konsolen, klicka pĂ„ âCreate delivery streamâ, vĂ€lj âdirect PUTâ i fĂ€ltet âdeliveryâ:

I nĂ€sta flik vĂ€ljer vi âRecord format conversionâ â âEnabledâ och vĂ€ljer âApache ORCâ som format för skrivning. Enligt forskning frĂ„n vissa , Ă€r detta det optimala formatet för PrestoDB och Athena. Som schema anger vi tabellen som vi skapade ovan. Observera att S3-platsen i Kinesis kan anges till valfri, bara schemat frĂ„n tabellen anvĂ€nds. Men om du anger en annan S3-plats kommer dessa poster inte att kunna lĂ€sas frĂ„n den hĂ€r tabellen.

VÀlj S3 för lagring och den bucket som vi skapade tidigare. AWS Glue Crawler, som jag kommer att berÀtta mer om senare, kan inte arbeta med prefix i S3-bucket, sÄ det Àr viktigt att lÀmna den tom.

Ăvriga alternativ kan Ă€ndras beroende pĂ„ din belastning, jag anvĂ€nder vanligtvis standardinstĂ€llningarna. Observera att S3-komprimering inte Ă€r tillgĂ€nglig, men ORC anvĂ€nder egen standardkomprimering.
Fluentd
Nu nÀr vi har stÀllt in lagring och mottagning av loggar mÄste vi konfigurera sÀndningen. Vi kommer att anvÀnda , eftersom jag Àlskar Ruby, men du kan anvÀnda Logstash eller skicka loggar till Kinesis direkt. Fluentd-servern kan startas pÄ flera sÀtt, jag kommer att prata om Docker, eftersom det Àr enkelt och bekvÀmt.
För att börja, behöver vi en konfigurationsfil fluent.conf. Skapa den och lÀgg till kÀllan:
framÄt
port 24224
bind 0.0.0.0
Nu kan du starta Fluentd-servern. Om du behöver en mer avancerad konfiguration finns det en detaljerad guide, inklusive hur man bygger sin egen bild.
$ 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:stableDenna konfiguration anvÀnder vÀgen /fluentd/log för att cacha loggar innan de skickas. Det gÄr att klara sig utan detta, men dÄ kan all cachelagrad data gÄ förlorad vid en omstart. Du kan Àven anvÀnda valfri port, 24224 Àr den standardport som Fluentd anvÀnder.
Nu nÀr vi har Fluentd igÄng kan vi skicka Nginx-loggar dit. Vi kör vanligtvis Nginx i en Docker-container, och i det hÀr fallet har Docker en inbyggd loggdrivare för Fluentd:
$ docker run
--log-driver=fluentd
--log-opt fluentd-address=
--log-opt tag="{{.Name}}"
-v /some/content:/usr/share/nginx/html:ro
-d
nginxOm du kör Nginx pÄ ett annat sÀtt kan du anvÀnda loggfiler; Fluentd har en .
LÄt oss lÀgga till loggarparsing i Fluent-konfigurationen, som vi har stÀllt in ovan:
@type parser
key_name log
emit_invalid_record_to_error false
@type jsonOch skicka loggar till Kinesis genom att anvÀnda :
@type kinesis_firehose
region region
delivery_stream_name
aws_key_id
aws_sec_keyAthena
Om du har konfigurerat allt korrekt bör du efter en stund (Kinesis registrerar mottagna data som standard var 10:e minut) se loggfiler i S3. I menyn "monitoring" för Kinesis Firehose kan du se hur mycket data som har skrivits till S3 samt fel. Glöm inte att ge skrivbehörighet till S3-bucketen för Kinesis-rollen. Om Kinesis inte kan parsa nÄgot lÀgger den fel i samma bucket.
Nu kan vi titta pÄ data i Athena. LÄt oss hitta de senaste frÄgorna som vi fick fel pÄ:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;Genomsökning av alla poster vid varje frÄga
Nu har vÄra loggar bearbetats och lagrats i S3 i ORC-format, komprimerade och redo för analys. Kinesis Firehose har till och med sorterat dem i kataloger per timme. Men sÄ lÀnge tabellen inte Àr partitionerad kommer Athena att ladda data frÄn hela tiden varje gÄng, med nÄgra fÄ undantag. Detta Àr ett stort problem av tvÄ skÀl:
- DatamÀngden vÀxer stÀndigt, vilket saktar ner frÄgorna;
- Kostnaden för Athena baseras pÄ mÀngden scannade data, med ett minimum pÄ 10 MB per frÄga.
För att korrigera detta anvÀnder vi AWS Glue Crawler, som skannar data i S3 och skriver ner information om partitioner i Glue Metastore. Detta gör att vi kan anvÀnda partitionerna som filter vid frÄgor i Athena, och den kommer endast att skanna de kataloger som anges i frÄgan.
Konfigurerar Amazon Glue Crawler
Amazon Glue Crawler skannar all data i S3-facket och skapar tabeller med partitioner. Skapa en Glue Crawler frÄn AWS Glue-konsolen och lÀgg till facket dÀr du lagrar data. Du kan anvÀnda en crawler för flera fack, i sÄ fall kommer den att skapa tabeller i den angivna databasen med namn som stÀmmer överens med fackens namn. Om du planerar att anvÀnda dessa data kontinuerligt, kom ihÄg att stÀlla in ett schema för att köra Crawler enligt dina behov. Vi anvÀnder en crawler för alla tabeller som körs varje timme.
Partitionerade tabeller
Efter den första körningen av crawlern bör tabeller för varje skannat fack visas i databasen som anges i instĂ€llningarna. Ăppna Athena-konsolen och leta efter tabellen med Nginx-loggar. LĂ„t oss försöka lĂ€sa nĂ„got:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);Denna frÄga kommer att vÀlja alla poster som mottogs mellan 6 och 7 pÄ morgonen den 8 april 2019. Men hur mycket effektivare Àr detta Àn att bara lÀsa frÄn en icke-partitionerad tabell? LÄt oss ta reda pÄ det och vÀlja samma poster, filtrera dem efter tidsstÀmpel:

3.59 sekunder och 244.34 megabyte data pÄ ett dataset som har en veckas loggar. LÄt oss prova partitioneringsfilter:

Lite snabbare, men det viktigaste â endast 1.23 megabyte data! Det skulle vara mycket billigare om det inte vore för de minimala 10 megabyte per frĂ„ga i prissĂ€ttningen. Men det Ă€r Ă€ndĂ„ mycket bĂ€ttre, och pĂ„ stora dataset kommer skillnaden att vara mycket mer imponerande.
ĐĄĐŸĐ±ĐžŃĐ°Đ”ĐŒ ĐŽŃŃĐ±ĐŸŃĐŽ Ń ĐżĐŸĐŒĐŸŃŃŃ Cube.js
För att skapa en instrumentpanel anvÀnder vi den analytiska ramverket Cube.js. Det har ganska mÄnga funktioner, men vi Àr intresserade av tvÄ: möjligheten att automatiskt anvÀnda filter baserat pÄ partitioner och pre-aggregationen av data. Det anvÀnder dataskema , skriven i Javascript, för att generera SQL och utföra frÄgor mot databasen. Det som krÀvs av oss Àr bara att ange hur vi ska anvÀnda partitioneringsfilter i dataskema.
Vi kommer att skapa en ny Cube.js-applikation. Eftersom vi redan anvÀnder en AWS-stack Àr det logiskt att anvÀnda Lambda för distribution. Du kan anvÀnda express-mallen för att generera om du planerar att hyra ut Cube.js backend pÄ Heroku eller Docker. I dokumentationen beskrivs andra .
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athenaFör att konfigurera Ätkomst till databasen i cube.js anvÀnds miljövariabler. Generatorn skapar en fil .env dÀr du kan ange dina nycklar för .
Nu behöver vi en , dÀr vi anger hur vÄra loggar lagras. DÀr kan vi ocksÄ ange hur man berÀknar metrik för dashboards.
I katalogen schema, skapa en fil Logs.js. HÀr Àr ett exempel pÄ datamodell för nginx:
Kod för modellen
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: `Yes`
}],
else: { label: `No` }
}
},
createdAt: {
sql: `from_unixtime(created_at)`,
type: `time`
}
}
});HÀr anvÀnder vi variabeln , för att generera en SQL-frÄga med filter för partitioner.
Vi specificerar ocksÄ metrik och parametrar som vi vill visa pÄ dashboarden och anger pre-aggregations. Cube.js kommer att skapa ytterligare tabeller med pre-aggregated data och automatiskt uppdatera data allteftersom de kommer in. Detta gör att vi kan snabba upp förfrÄgningar och minska kostnaden för att anvÀnda Athena.
Vi lÀgger till denna information i dataschemat:
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`
)
}
}
}I denna modell anger vi att data mÄste pre-aggregaras för alla anvÀnda metrik, och att vi ska anvÀnda partitionering per mÄnad. kan betydligt pÄskynda insamlingen och uppdateringen av data.
Nu kan vi skapa en dashboard!
Backend Cube.js tillhandahĂ„ller och ett set med klientbibliotek för populĂ€ra frontend-ramverk. Vi kommer att anvĂ€nda React-versionen av klienten för att bygga dashboarden. Cube.js tillhandahĂ„ller endast data, sĂ„ vi behöver ett bibliotek för visualiseringar â jag föredrar , men du kan anvĂ€nda vilken som helst.
Servern Cube.js tar emot förfrÄgningar i , dÀr de nödvÀndiga metrikarna anges. Till exempel, för att rÀkna hur mÄnga fel Nginx har returnerat per dag, mÄste du skicka en sÄdan förfrÄgan:
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}Vi installerar Cube.js-klienten och React-komponentbiblioteket via NPM:
$ npm i --save @cubejs-client/core @cubejs-client/reactVi importerar komponenterna cubejs och QueryRenderer, för att hÀmta data, och vi bygger dashboarden:
Dashboard-koden
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 'Loading...';
}
return (
);
}}
/>
)
}KÀllkoden för dashboarden finns tillgÀnglig pÄ .
KĂ€lla: habr.com
