Običajno se za spremljanje in analizo delovanja Nginxa uporabljajo komercialni izdelki ali že pripravljene odprtokodne alternative, kot je Prometheus + Grafana. To je dobra možnost za spremljanje ali analitiko v realnem času, ni pa zelo priročna za zgodovinsko analizo. Na katerem koli priljubljenem viru količina podatkov iz dnevnikov nginx hitro narašča in za analizo velike količine podatkov je logično uporabiti nekaj bolj specializiranega.
V tem članku vam bom povedal, kako lahko uporabite
TL:DR;
Za zbiranje informacij, ki jih uporabljamo
Zbiranje dnevnikov Nginx
Privzeto so dnevniki Nginx videti nekako takole:
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" "-"
Lahko jih je razčleniti, vendar je veliko lažje popraviti konfiguracijo Nginx, tako da ustvarja dnevnike v 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 za shranjevanje
Za shranjevanje dnevnikov bomo uporabili S3. To vam omogoča shranjevanje in analizo dnevnikov na enem mestu, saj lahko Athena neposredno dela s podatki v S3. Kasneje v članku vam bom povedal, kako pravilno dodati in obdelati dnevnike, vendar najprej potrebujemo čisto vedro v S3, v katerem ne bo shranjeno nič drugega. Vnaprej je vredno razmisliti, v kateri regiji boste ustvarili svoje vedro, ker Athena ni na voljo v vseh regijah.
Ustvarjanje vezja v konzoli Athena
Ustvarimo tabelo v Atheni za dnevnike. Potreben je za pisanje in branje, če nameravate uporabljati Kinesis Firehose. Odprite konzolo Athena in ustvarite tabelo:
Izdelava tabele 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');
Ustvarjanje toka Kinesis Firehose
Kinesis Firehose bo podatke, prejete iz Nginxa, zapisal v S3 v izbranem formatu in jih razdelil v imenike v formatu LLLL/MM/DD/HH. To bo prišlo prav pri branju podatkov. Seveda lahko pišete neposredno v S3 iz fluentd, vendar boste v tem primeru morali pisati JSON, to pa je neučinkovito zaradi velike velikosti datotek. Poleg tega je pri uporabi PrestoDB ali Athena JSON najpočasnejši format podatkov. Torej odprite konzolo Kinesis Firehose, kliknite »Ustvari tok dostave«, v polju »dostava« izberite »neposredna PUT«:
V naslednjem zavihku izberite »Record format conversion« - »Enabled« in izberite »Apache ORC« kot format zapisa. Po nekaterih raziskavah
Izberemo S3 za shranjevanje in vedro, ki smo ga ustvarili prej. Aws Glue Crawler, o katerem bom govoril malo kasneje, ne more delovati s predponami v vedru S3, zato je pomembno, da ga pustite praznega.
Preostale možnosti je mogoče spremeniti glede na vašo obremenitev; običajno uporabljam privzete. Upoštevajte, da stiskanje S3 ni na voljo, vendar ORC privzeto uporablja izvorno stiskanje.
Tekoče
Zdaj, ko smo konfigurirali shranjevanje in prejemanje dnevnikov, moramo konfigurirati pošiljanje. Bomo uporabili
Najprej potrebujemo konfiguracijsko datoteko fluent.conf. Ustvarite ga in dodajte vir:
vrata 24224
vezati 0.0.0.0
Zdaj lahko zaženete strežnik Fluentd. Če potrebujete naprednejšo konfiguracijo, pojdite na
$ 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
Ta konfiguracija uporablja pot /fluentd/log
za predpomnjenje dnevnikov pred pošiljanjem. Lahko storite brez tega, vendar potem, ko znova zaženete, lahko izgubite vse, kar je predpomnjeno, z mukotrpnim delom. Uporabite lahko tudi katera koli vrata; 24224 so privzeta vrata Fluentd.
Zdaj, ko imamo Fluentd v teku, lahko tja pošljemo dnevnike Nginx. Običajno izvajamo Nginx v vsebniku Docker, v tem primeru ima Docker izvorni gonilnik za beleženje 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
Če Nginx zaženete drugače, lahko uporabite dnevniške datoteke, Fluentd jih ima
Dodajmo zgoraj konfigurirano razčlenjevanje dnevnika konfiguraciji Fluent:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
In pošiljanje dnevnikov v Kinesis z uporabo
<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
Če ste vse pravilno konfigurirali, bi morali čez nekaj časa (privzeto Kinesis beleži prejete podatke vsakih 10 minut) videti dnevniške datoteke v S3. V meniju »nadzor« Kinesis Firehose lahko vidite, koliko podatkov je zabeleženih v S3, kot tudi napake. Ne pozabite vlogi Kinesis dati dostopa za pisanje v vedro S3. Če Kinesis nečesa ne more razčleniti, bo napake dodal v isto vedro.
Zdaj si lahko ogledate podatke v Atheni. Poiščimo zadnje zahteve, za katere smo vrnili napake:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Pregledovanje vseh zapisov za vsako zahtevo
Zdaj so naši dnevniki obdelani in shranjeni v S3 v ORC, stisnjeni in pripravljeni za analizo. Kinesis Firehose jih je celo organiziral v imenike za vsako uro. Dokler pa tabela ni particionirana, bo Athena naložila podatke vseh časov na vsako zahtevo, z redkimi izjemami. To je velika težava iz dveh razlogov:
- Obseg podatkov nenehno narašča, kar upočasnjuje poizvedbe;
- Athena se zaračuna glede na količino skeniranih podatkov, z najmanj 10 MB na zahtevo.
Da bi to odpravili, uporabimo AWS Glue Crawler, ki bo preiskal podatke v S3 in zapisal informacije o particiji v Glue Metastore. To nam bo omogočilo uporabo particij kot filtra pri poizvedovanju Athene, ta pa bo pregledala samo imenike, določene v poizvedbi.
Nastavitev Amazon Glue Crawler
Amazon Glue Crawler skenira vse podatke v vedru S3 in ustvari tabele s particijami. Ustvarite Glue Crawler iz konzole AWS Glue in dodajte vedro, kamor shranjujete podatke. En pajek lahko uporabite za več veder, v tem primeru bo ustvaril tabele v določeni bazi podatkov z imeni, ki se ujemajo z imeni veder. Če nameravate te podatke redno uporabljati, ne pozabite konfigurirati razporeda zagona pajka tako, da bo ustrezal vašim potrebam. Za vse tabele uporabljamo enega pajka, ki deluje vsako uro.
Predelne mize
Po prvem zagonu pajka se morajo tabele za vsako skenirano vedro prikazati v bazi podatkov, določeni v nastavitvah. Odprite konzolo Athena in poiščite tabelo z dnevniki Nginx. Poskusimo nekaj prebrati:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Ta poizvedba bo izbrala vse zapise, prejete med 6. in 7. uro 8. aprila 2019. Toda koliko bolj učinkovito je to kot samo branje iz neparticionirane tabele? Ugotovimo in izberemo iste zapise ter jih filtriramo po časovnem žigu:
3.59 sekunde in 244.34 megabajtov podatkov v naboru podatkov s samo tednom dnevnikov. Poskusimo filter po particiji:
Malce hitreje, a kar je najpomembneje - le 1.23 megabajta podatkov! Bilo bi veliko ceneje, če v ceniku ne bi bilo najmanj 10 megabajtov na zahtevo. Vendar je še vedno veliko boljši in na velikih zbirkah podatkov bo razlika veliko bolj impresivna.
Izdelava nadzorne plošče z uporabo Cube.js
Za sestavo nadzorne plošče uporabljamo analitično ogrodje Cube.js. Ima precej funkcij, vendar nas zanimata dve: možnost samodejne uporabe particijskih filtrov in predzdruževanje podatkov. Uporablja podatkovno shemo
Ustvarimo novo aplikacijo Cube.js. Ker že uporabljamo sklad AWS, je logično, da za uvajanje uporabimo Lambda. Če nameravate zaledje Cube.js gostiti v Heroku ali Dockerju, lahko uporabite ekspresno predlogo za generiranje. Dokumentacija opisuje druge
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Spremenljivke okolja se uporabljajo za konfiguracijo dostopa do baze podatkov v cube.js. Generator bo ustvaril datoteko .env, v kateri lahko podate svoje ključe
Zdaj potrebujemo
V imeniku schema
, ustvarite datoteko Logs.js
. Tukaj je primer podatkovnega modela za nginx:
Koda modela
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`
}
}
});
Tukaj uporabljamo spremenljivko
Nastavimo tudi metrike in parametre, ki jih želimo prikazati na nadzorni plošči, ter določimo predzdruževanja. Cube.js bo ustvaril dodatne tabele s predhodno združenimi podatki in samodejno posodobil podatke, ko bodo prispeli. To ne le pospeši poizvedbe, ampak tudi zmanjša stroške uporabe Athene.
Dodajmo te informacije v datoteko podatkovne sheme:
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`
)
}
}
}
V tem modelu določamo, da je treba vnaprej združiti podatke za vse uporabljene metrike in uporabiti razdelitev po mesecih.
Zdaj lahko sestavimo armaturno ploščo!
Zaledje Cube.js zagotavlja
Strežnik Cube.js sprejme zahtevo v
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Namestimo odjemalca Cube.js in knjižnico komponent React prek NPM:
$ npm i --save @cubejs-client/core @cubejs-client/react
Uvažamo komponente cubejs
и QueryRenderer
za prenos podatkov in zbiranje nadzorne plošče:
Koda nadzorne plošče
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>
);
}}
/>
)
}
Viri nadzorne plošče so na voljo na
Vir: www.habr.com