Tyypillisesti Nginxin toiminnan seurantaan ja analysointiin käytetään kaupallisia tuotteita tai valmiita avoimen lähdekoodin vaihtoehtoja, kuten Prometheus + Grafana. Tämä on hyvä vaihtoehto seurantaan tai reaaliaikaiseen analytiikkaan, mutta ei kovin kätevä historialliseen analyysiin. Missä tahansa suositussa resurssissa nginx-lokien tietojen määrä kasvaa nopeasti, ja suuren tietomäärän analysointiin on loogista käyttää jotain erikoisempaa.
Tässä artikkelissa kerron sinulle, kuinka voit käyttää
TL:DR;
Käytämme tietojen keräämiseen
Nginx-lokien kerääminen
Oletusarvoisesti Nginx-lokit näyttävät tältä:
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" "-"
Ne voidaan jäsentää, mutta Nginx-kokoonpanon korjaaminen on paljon helpompaa niin, että se tuottaa lokit JSONissa:
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 säilytykseen
Lokien tallentamiseen käytämme S3:a. Tämän avulla voit tallentaa ja analysoida lokeja yhdessä paikassa, koska Athena voi käsitellä tietoja suoraan S3:ssa. Myöhemmin artikkelissa kerron kuinka lokit lisätään ja käsitellään oikein, mutta ensin tarvitsemme puhtaan kauhan S3: ssa, johon mitään muuta ei tallenneta. Kannattaa harkita etukäteen, mille alueelle luot kauhan, koska Athena ei ole saatavilla kaikilla alueilla.
Piirin luominen Athena-konsolissa
Luodaan Athenaan taulukko lokeille. Sitä tarvitaan sekä kirjoittamiseen että lukemiseen, jos aiot käyttää Kinesis Firehosea. Avaa Athena-konsoli ja luo taulukko:
SQL-taulukon luominen
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 Streamin luominen
Kinesis Firehose kirjoittaa Nginxistä saadut tiedot S3:lle valitussa muodossa ja jakaa ne hakemistoihin muodossa VVVV/KK/PP/TT. Tästä on hyötyä dataa luettaessa. Voit tietysti kirjoittaa suoraan S3:een fluentd:stä, mutta tässä tapauksessa sinun on kirjoitettava JSON, mikä on tehotonta tiedostojen suuren koon vuoksi. Lisäksi PrestoDB:tä tai Athenaa käytettäessä JSON on hitain tietomuoto. Avaa siis Kinesis Firehose -konsoli, napsauta "Luo toimitusvirta", valitse "toimitus"-kentästä "suora PUT":
Valitse seuraavassa välilehdessä "Tallennusmuodon muuntaminen" - "Käytössä" ja valitse tallennusmuodoksi "Apache ORC". Joidenkin tutkimusten mukaan
Valitsemme säilytykseen S3:n ja aiemmin luomamme kauhan. Aws Glue Crawler, josta puhun hieman myöhemmin, ei voi toimia S3-ämpärien etuliitteiden kanssa, joten on tärkeää jättää se tyhjäksi.
Loput vaihtoehdot voidaan muuttaa kuormituksestasi riippuen; käytän yleensä oletusasetuksia. Huomaa, että S3-pakkaus ei ole käytettävissä, mutta ORC käyttää oletusarvoisesti alkuperäistä pakkausta.
Sujuva
Nyt kun olemme määrittäneet lokien tallentamisen ja vastaanottamisen, meidän on määritettävä lähetys. Me käytämme
Ensin tarvitsemme fluent.conf-määritystiedoston. Luo se ja lisää lähde:
portti 24224
sitoa 0.0.0.0
Nyt voit käynnistää Fluentd-palvelimen. Jos tarvitset kehittyneempiä määrityksiä, siirry osoitteeseen
$ 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
Tämä kokoonpano käyttää polkua /fluentd/log
lokit välimuistiin ennen lähettämistä. Voit pärjätä ilman tätä, mutta kun käynnistät uudelleen, voit menettää kaiken välimuistissa olevan työvoiman. Voit myös käyttää mitä tahansa porttia; 24224 on oletusarvoinen Fluentd-portti.
Nyt kun Fluentd on käynnissä, voimme lähettää Nginx-lokit sinne. Käytämme yleensä Nginxiä Docker-säiliössä, jolloin Dockerilla on natiivi lokiohjain Fluentdille:
$ 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
Jos käytät Nginxiä eri tavalla, voit käyttää lokitiedostoja, Fluentd on tehnyt
Lisätään Fluent-kokoonpanoon yllä määritetty lokin jäsennys:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Ja lokien lähettäminen Kinesikseen käyttäen
<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>
Athena
Jos olet määrittänyt kaiken oikein, jonkin ajan kuluttua (oletusarvoisesti Kinesis tallentaa vastaanotetut tiedot 10 minuutin välein) sinun pitäisi nähdä lokitiedostot S3:ssa. Kinesis Firehosen ”seuranta”-valikossa näet kuinka paljon tietoja S3:ssa on tallennettu, sekä virheet. Älä unohda antaa S3-ämpäriin kirjoitusoikeutta Kinesis-roolille. Jos Kinesis ei voinut jäsentää jotain, se lisää virheet samaan ryhmään.
Nyt voit tarkastella tietoja Athenassa. Etsitään viimeisimmät pyynnöt, joille olemme palauttaneet virheitä:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Kaikkien tietueiden skannaus jokaista pyyntöä varten
Nyt lokimme on käsitelty ja tallennettu S3:een ORC:ssa, pakattuina ja valmiina analysoitavaksi. Kinesis Firehose jopa järjesti ne hakemistoihin jokaiselle tunnille. Kuitenkin niin kauan kuin taulukkoa ei ole osioitu, Athena lataa kaikkien aikojen tiedot jokaisesta pyynnöstä, harvoja poikkeuksia lukuun ottamatta. Tämä on suuri ongelma kahdesta syystä:
- Tietojen määrä kasvaa jatkuvasti, mikä hidastaa kyselyitä;
- Athena laskutetaan skannatun tiedon määrän perusteella, vähintään 10 Mt per pyyntö.
Korjaamme tämän käyttämällä AWS Glue Crawleria, joka indeksoi tiedot S3:ssa ja kirjoittaa osiotiedot Glue Metastoreen. Tämä antaa meille mahdollisuuden käyttää osioita suodattimena tehdessämme kyselyä Athenasta, ja se tarkistaa vain kyselyssä määritetyt hakemistot.
Amazon Glue Crawlerin määrittäminen
Amazon Glue Crawler skannaa kaikki S3-säihön tiedot ja luo taulukoita osioineen. Luo AWS Glue -konsolista Glue Crawler ja lisää ämpäri, johon tallennat tiedot. Voit käyttää yhtä indeksointirobottia useille ryhmille, jolloin se luo määritettyyn tietokantaan taulukoita, joiden nimet vastaavat ryhmien nimiä. Jos aiot käyttää näitä tietoja säännöllisesti, muista määrittää indeksointirobotin käynnistysaikataulu tarpeidesi mukaan. Käytämme yhtä indeksointirobottia kaikille pöydille, joka käy tunnin välein.
Osioidut pöydät
Indeksointirobotin ensimmäisen käynnistyksen jälkeen jokaisen skannatun segmentin taulukoiden pitäisi näkyä asetuksissa määritettyyn tietokantaan. Avaa Athena-konsoli ja etsi Nginx-lokit sisältävä taulukko. Yritetään lukea jotain:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Tämä kysely valitsee kaikki tietueet, jotka on vastaanotettu 6. huhtikuuta 7 kello 8–2019. Mutta kuinka paljon tehokkaampaa tämä on kuin pelkkä lukeminen osittamattomasta taulukosta? Selvitetään ja valitaan samat tietueet suodattamalla ne aikaleiman mukaan:
3.59 sekuntia ja 244.34 megatavua dataa tietojoukossa, jossa on vain viikon lokit. Kokeillaan suodatinta osion mukaan:
Hieman nopeampi, mutta mikä tärkeintä - vain 1.23 megatavua dataa! Se olisi paljon halvempaa, ellei hinnoittelussa olisi vähintään 10 megatavua per pyyntö. Mutta se on silti paljon parempi, ja suurilla tietojoukoilla ero on paljon vaikuttavampi.
Hallintapaneelin rakentaminen Cube.js:n avulla
Käytämme kojelaudan kokoamiseen Cube.js-analyyttistä kehystä. Siinä on melko paljon toimintoja, mutta olemme kiinnostuneita kahdesta: kyky käyttää automaattisesti osiosuodattimia ja tietojen esikokoaminen. Se käyttää dataskeemaa
Luodaan uusi Cube.js-sovellus. Koska käytämme jo AWS-pinoa, on loogista käyttää Lambdaa käyttöönottoon. Voit käyttää pikamallia sukupolven luomiseen, jos aiot isännöidä Cube.js-taustaohjelmaa Herokussa tai Dockerissa. Dokumentaatio kuvaa muita
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Ympäristömuuttujia käytetään määrittämään tietokannan käyttö cube.js:ssä. Generaattori luo .env-tiedoston, jossa voit määrittää avaimesi
Nyt tarvitsemme
Hakemistossa schema
, luo tiedosto Logs.js
. Tässä on esimerkki nginx-tietomallista:
Mallikoodi
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`
}
}
});
Tässä käytämme muuttujaa
Asetamme myös mittarit ja parametrit, jotka haluamme näyttää kojelaudassa, ja määritämme esikoontit. Cube.js luo lisää taulukoita, joissa on esikoottuja tietoja, ja päivittää tiedot automaattisesti niiden saapuessa. Tämä ei vain nopeuttaa kyselyitä, vaan myös vähentää Athenen käyttökustannuksia.
Lisätään nämä tiedot dataskeematiedostoon:
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ääritämme tässä mallissa, että kaikkien käytettyjen mittareiden tiedot on esikoottava etukäteen ja käytettävä kuukausittaista osiointia.
Nyt voimme koota kojelaudan!
Cube.js-taustaohjelma tarjoaa
Cube.js-palvelin hyväksyy pyynnön
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Asennetaan Cube.js-asiakas ja React-komponenttikirjasto NPM:n kautta:
$ npm i --save @cubejs-client/core @cubejs-client/react
Tuomme komponentteja maahan cubejs
и QueryRenderer
ladataksesi tiedot ja kerätäksesi kojetaulun:
Kojelaudan koodi
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>
);
}}
/>
)
}
Kojelaudan lähteet ovat saatavilla osoitteessa
Lähde: will.com