Kutime, komercaj produktoj aŭ pretaj malfermfontaj alternativoj, kiel Prometheus + Grafana, estas uzataj por monitori kaj analizi la funkciadon de Nginx. Ĉi tio estas bona elekto por monitorado aŭ realtempa analizo, sed ne tre oportuna por historia analizo. Sur iu ajn populara rimedo, la volumo de datumoj de nginx-protokoloj kreskas rapide, kaj por analizi grandan kvanton da datumoj, estas logike uzi ion pli specialan.
En ĉi tiu artikolo mi rakontos al vi kiel vi povas uzi
TL:DR;
Por kolekti informojn, kiujn ni uzas
Kolektante Nginx-protokolojn
Defaŭlte, Nginx-protokoloj aspektas kiel ĉi tio:
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" "-"
Ili povas esti analizitaj, sed estas multe pli facile korekti la agordon de Nginx tiel ke ĝi produktas protokolojn en 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 por stokado
Por stoki protokolojn, ni uzos S3. Ĉi tio permesas vin stoki kaj analizi protokolojn en unu loko, ĉar Athena povas labori kun datumoj en S3 rekte. Poste en la artikolo mi rakontos al vi kiel ĝuste aldoni kaj prilabori protokolojn, sed unue ni bezonas puran sitelon en S3, en kiu nenio alia estos stokita. Indas pripensi anticipe en kiu regiono vi kreos vian sitelon, ĉar Athena ne estas disponebla en ĉiuj regionoj.
Kreante cirkviton en la Athena konzolo
Ni kreu tabelon en Athena por protokoloj. Ĝi estas bezonata por kaj skribado kaj legado, se vi planas uzi Kinesis Firehose. Malfermu la Athena-konzolon kaj kreu tablon:
Kreado de SQL-tabelo
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');
Kreante Kinesis Firehose Stream
Kinesis Firehose skribos la datumojn ricevitajn de Nginx al S3 en la elektita formato, dividante ĝin en dosierujojn en la formato YYYY/MM/DD/HH. Ĉi tio utilos dum legado de datumoj. Vi povas, kompreneble, skribi rekte al S3 de fluentd, sed ĉi-kaze vi devos skribi JSON, kaj ĉi tio estas malefika pro la granda grandeco de la dosieroj. Aldone, kiam vi uzas PrestoDB aŭ Athena, JSON estas la plej malrapida datumformato. Do malfermu la Kinesis Firehose-konzolon, alklaku "Krei liveran fluon", elektu "rektan METU" en la kampo "livero":
En la sekva langeto, elektu "Rekorda formato konvertiĝo" - "Enabled" kaj elektu "Apache ORC" kiel la registra formato. Laŭ iuj esploroj
Ni elektas S3 por stokado kaj la sitelon, kiun ni kreis pli frue. Aws Glue Crawler, pri kiu mi parolos iom poste, ne povas funkcii kun prefiksoj en S3 sitelo, do gravas lasi ĝin malplena.
La ceteraj opcioj povas esti ŝanĝitaj depende de via ŝarĝo; mi kutime uzas la defaŭltajn. Notu, ke S3-kunpremado ne haveblas, sed ORC uzas indiĝenan kunpremadon defaŭlte.
fluad
Nun kiam ni agordis stokadon kaj ricevadon de protokoloj, ni devas agordi sendon. Ni uzos
Unue, ni bezonas la agordan dosieron fluent.conf. Kreu ĝin kaj aldonu fonton:
haveno 24224
ligi 0.0.0.0
Nun vi povas komenci la Fluentd-servilon. Se vi bezonas pli altnivelan agordon, iru al
$ 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
Ĉi tiu agordo uzas la vojon /fluentd/log
por konservi protokolojn antaŭ sendado. Vi povas malhavi ĉi tion, sed tiam, kiam vi rekomencas, vi povas perdi ĉion kaŝitan kun malantaŭa laboro. Vi ankaŭ povas uzi ajnan havenon; 24224 estas la defaŭlta Fluentd-haveno.
Nun kiam ni funkcias Fluentd, ni povas sendi Nginx-protokolojn tie. Ni kutime rulas Nginx en Docker-ujo, en kiu kazo Docker havas denaskan registradan pelilon por 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
Se vi rulas Nginx malsame, vi povas uzi protokolojn, kiel Fluentd havas
Ni aldonu la protokolan analizon agordita supre al la Flua agordo:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Kaj sendante protokolojn al Kinesis uzante
<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>
Ateneo
Se vi agordis ĉion ĝuste, tiam post iom da tempo (defaŭlte, Kinesis registras ricevitajn datumojn unufoje ĉiujn 10 minutojn) vi devus vidi protokolojn en S3. En la "monitorado" menuo de Kinesis Firehose vi povas vidi kiom da datumoj estas registritaj en S3, same kiel eraroj. Ne forgesu doni skriban aliron al la S3 sitelo al la rolo Kinesis. Se Kinesis ne povis analizi ion, ĝi aldonos la erarojn al la sama sitelo.
Nun vi povas vidi la datumojn en Athena. Ni trovu la plej novajn petojn, por kiuj ni resendis erarojn:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Skanante ĉiujn rekordojn por ĉiu peto
Nun niaj protokoloj estis prilaboritaj kaj stokitaj en S3 en ORC, kunpremitaj kaj pretaj por analizo. Kinesis Firehose eĉ organizis ilin en adresarojn por ĉiu horo. Tamen, dum la tablo ne estas dividita, Athena ŝarĝos ĉiamajn datumojn pri ĉiu peto, kun maloftaj esceptoj. Ĉi tio estas granda problemo pro du kialoj:
- La volumo de datumoj konstante kreskas, malrapidigante demandojn;
- Athena estas fakturita surbaze de la volumo de datumoj skanitaj, kun minimumo de 10 MB per peto.
Por ripari ĉi tion, ni uzas AWS Glue Crawler, kiu rampos la datumojn en S3 kaj skribos la sekcion-informojn al la Glue Metastore. Ĉi tio permesos al ni uzi sekciojn kiel filtrilon dum pridemando de Athena, kaj ĝi nur skanos la dosierujojn specifitajn en la konsulto.
Agordi Amazon Glue Crawler
Amazon Glue Crawler skanas ĉiujn datumojn en la S3 sitelo kaj kreas tabelojn kun sekcioj. Kreu Glue Crawler de la AWS Glue-konzolo kaj aldonu sitelon kie vi stokas la datumojn. Vi povas uzi unu crawler por pluraj siteloj, en kiu kazo ĝi kreos tabelojn en la specifita datumbazo kun nomoj kiuj kongruas kun la nomoj de la siteloj. Se vi planas uzi ĉi tiujn datumojn regule, nepre agordu la lanĉan horaron de Crawler laŭ viaj bezonoj. Ni uzas unu Crawler por ĉiuj tabloj, kiu funkcias ĉiun horon.
Dispartitaj tabloj
Post la unua lanĉo de la crawler, tabeloj por ĉiu skanita sitelo devus aperi en la datumbazo specifita en la agordoj. Malfermu la Athena-konzolon kaj trovu la tablon kun Nginx-protokoloj. Ni provu legi ion:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Ĉi tiu demando elektos ĉiujn rekordojn ricevitajn inter la 6-a kaj la 7-a horo de la 8-a de aprilo 2019. Sed kiom pli efika estas ĉi tio ol nur legado de nedispartita tabelo? Ni eltrovu kaj elektu la samajn rekordojn, filtrante ilin per tempomarko:
3.59 sekundoj kaj 244.34 megabajtoj da datumoj sur datumaro kun nur semajno da protokoloj. Ni provu filtrilon per dispartigo:
Iom pli rapide, sed plej grave - nur 1.23 megabajtoj da datumoj! Estus multe pli malmultekosta se ne por la minimumo 10 megabajtoj per peto en la prezo. Sed ĝi estas ankoraŭ multe pli bona, kaj sur grandaj datumaroj la diferenco estos multe pli impona.
Konstruante panelon per Cube.js
Por kunmeti la panelon, ni uzas la analizan kadron Cube.js. Ĝi havas sufiĉe multajn funkciojn, sed ni interesiĝas pri du: la kapablo aŭtomate uzi sekciofiltrilojn kaj antaŭ-agregadon de datumoj. Ĝi uzas datumskemon
Ni kreu novan aplikaĵon Cube.js. Ĉar ni jam uzas la AWS-stakon, estas logike uzi Lambda por disfaldi. Vi povas uzi la ekspresan ŝablonon por generacio se vi planas gastigi la backend Cube.js en Heroku aŭ Docker. La dokumentaro priskribas aliajn
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Mediaj variabloj estas uzataj por agordi datumbazan aliron en cube.js. La generatoro kreos .env dosieron en kiu vi povas specifi viajn ŝlosilojn por
Nun ni bezonas
En dosierujo schema
, kreu dosieron Logs.js
. Jen ekzemplo de datummodelo por nginx:
Modelkodo
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`
}
}
});
Ĉi tie ni uzas la variablon
Ni ankaŭ fiksas la metrikojn kaj parametrojn, kiujn ni volas montri sur la panelo kaj specifas antaŭajn agregadojn. Cube.js kreos pliajn tabelojn kun antaŭ-agregitaj datumoj kaj aŭtomate ĝisdatigos la datumojn kiam ĝi alvenos. Ĉi tio ne nur akcelas demandojn, sed ankaŭ reduktas la koston uzi Athena.
Ni aldonu ĉi tiujn informojn al la datumskemdosiero:
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`
)
}
}
}
Ni precizigas en ĉi tiu modelo, ke necesas antaŭ-agregi datumojn por ĉiuj uzataj metrikoj, kaj uzi dispartigo laŭ monato.
Nun ni povas kunmeti la instrumentpanelon!
Cube.js backend provizas
La Cube.js-servilo akceptas la peton en
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Ni instalu la klienton Cube.js kaj la komponan bibliotekon React per NPM:
$ npm i --save @cubejs-client/core @cubejs-client/react
Ni importas komponantojn cubejs
и QueryRenderer
por elŝuti la datumojn kaj kolekti la instrumentpanelon:
Dashboard-kodo
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>
);
}}
/>
)
}
Fontoj de panelo haveblas ĉe
fonto: www.habr.com