Biasana, produk komersil atanapi alternatif open-source anu siap, sapertos Prometheus + Grafana, dianggo pikeun ngawas sareng nganalisa operasi Nginx. Ieu mangrupikeun pilihan anu saé pikeun ngawaskeun atanapi analitik sacara real-time, tapi henteu cocog pisan pikeun analisa sajarah. Dina naon waé sumber populér, volume data tina log nginx ngembang pesat, sareng pikeun nganalisis jumlah data anu ageung, logis ngagunakeun anu langkung khusus.
Dina tulisan ieu kuring bakal nyarioskeun ka anjeun kumaha anjeun tiasa nganggo
TL: DR;
Pikeun ngumpulkeun informasi kami nganggo
Ngumpulkeun log Nginx
Sacara standar, log Nginx katingali sapertos kieu:
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" "-"
Éta tiasa diusir, tapi langkung gampang pikeun ngabenerkeun konfigurasi Nginx supados ngahasilkeun log di 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 pikeun neundeun
Pikeun nyimpen log, urang bakal nganggo S3. Ieu ngamungkinkeun anjeun pikeun nyimpen sareng nganalisis log dina hiji tempat, sabab Athena tiasa damel sareng data dina S3 langsung. Engké dina tulisan kuring bakal nyarioskeun ka anjeun kumaha cara nambihkeun sareng ngolah log anu leres, tapi mimitina urang peryogi ember bersih dina S3, dimana teu aya anu bakal disimpen. Éta patut mertimbangkeun sateuacanna di daérah mana anjeun badé nyiptakeun ember, sabab Athena henteu sayogi di sadaya daérah.
Nyiptakeun sirkuit dina konsol Athena
Hayu urang nyieun tabel di Athena pikeun log. Diperyogikeun pikeun nyerat sareng maca upami anjeun badé nganggo Kinesis Firehose. Buka konsol Athena sareng jieun tabel:
Nyieun tabel 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');
Nyiptakeun Kinesis Firehose Stream
Kinesis Firehose bakal nyerat data anu ditampi tina Nginx ka S3 dina format anu dipilih, ngabagi kana diréktori dina format YYYY/MM/DD/HH. Ieu bakal mangpaat nalika maca data. Anjeun tiasa, tangtosna, nyerat langsung ka S3 ti fluentd, tapi dina hal ieu anjeun kedah nyerat JSON, sareng ieu henteu cekap kusabab ukuran file anu ageung. Salaku tambahan, nalika nganggo PrestoDB atanapi Athena, JSON mangrupikeun format data anu paling laun. Janten buka konsol Kinesis Firehose, klik "Jieun aliran pangiriman", pilih "langsung PUT" dina widang "pangiriman":
Dina tab salajengna, pilih "Rekam format konversi" - "Diaktipkeun" tur pilih "Apache ORC" salaku format rekaman. Numutkeun sababaraha panalungtikan
Urang milih S3 pikeun neundeun jeung ember nu urang dijieun saméméhna. Aws Glue Crawler, anu kuring bakal ngobrol engké, teu tiasa dianggo sareng awalan dina ember S3, janten penting pikeun ngantepkeun kosong.
Pilihan sésana tiasa dirobih gumantung kana beban anjeun; Kuring biasana nganggo anu standar. Catet yén komprési S3 henteu sayogi, tapi ORC nganggo komprési asli sacara standar.
Fluentd
Ayeuna urang geus ngonpigurasi nyimpen jeung narima log, urang kudu ngonpigurasikeun ngirim. Urang bakal ngagunakeun
Kahiji, urang peryogi file konfigurasi fluent.conf. Jieun eta sarta tambahkeun sumber:
port 24224
meungkeut 0.0.0.0
Ayeuna anjeun tiasa ngamimitian server Fluentd. Upami anjeun peryogi konfigurasi anu langkung maju, angkat ka
$ 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
Konfigurasi ieu ngagunakeun jalur /fluentd/log
ka cache log saméméh ngirim. Anjeun tiasa ngalakukeun tanpa ieu, tapi lajeng mun anjeun balikan deui, anjeun bisa leungit sagalana sindangan jeung kuli deui-megatkeun. Anjeun ogé tiasa nganggo port mana waé; 24224 mangrupikeun port Fluentd standar.
Ayeuna urang parantos ngajalankeun Fluentd, urang tiasa ngirim log Nginx ka dinya. Kami biasana ngajalankeun Nginx dina wadah Docker, dina hal ieu Docker ngagaduhan supir logging asli pikeun 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
Upami anjeun ngajalankeun Nginx béda, anjeun tiasa nganggo file log, Fluentd gaduh
Hayu urang tambahkeun parsing log anu dikonpigurasi di luhur kana konfigurasi Fluent:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Jeung ngirim log ka Kinesis maké
<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>
pundah
Upami anjeun parantos ngonpigurasi sadayana leres, teras saatos sababaraha waktos (sacara standar, rékaman Kinesis nampi data sakali unggal 10 menit) anjeun kedah ningali file log dina S3. Dina menu "monitoring" Kinesis Firehose anjeun tiasa ningali sabaraha data anu kacatet dina S3, kitu ogé kasalahan. Tong hilap masihan aksés nyerat kana ember S3 kana peran Kinesis. Lamun Kinesis teu bisa parse hal, éta bakal nambahan kasalahan ka LIPI sarua.
Ayeuna anjeun tiasa ningali data dina Athena. Hayu urang milarian pamenta anu pangahirna anu kami balikkeun kasalahan:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Nyeken sadaya rékaman pikeun tiap pamundut
Ayeuna log kami parantos diolah sareng disimpen dina S3 di ORC, dikomprés sareng siap pikeun dianalisis. Kinesis Firehose malah ngatur kana diréktori pikeun unggal jam. Tapi, salami tabel henteu dipisahkeun, Athena bakal ngamuat data sadaya waktos dina unggal pamundut, sareng pengecualian anu jarang. Ieu masalah badag pikeun dua alesan:
- Volume data anu terus tumuwuh, slowing turun queries;
- Athena ditagih dumasar kana volume data anu diseken, kalayan minimum 10 MB per pamundut.
Pikeun ngalereskeun ieu, kami nganggo AWS Glue Crawler, anu bakal ngorondang data dina S3 sareng nyerat inpormasi partisi kana Metastore Glue. Ieu bakal ngamungkinkeun urang ngagunakeun partisi salaku saringan nalika naroskeun Athena, sareng éta ngan ukur nyeken diréktori anu ditunjuk dina pamundut.
Nyetél Amazon Glue Crawler
Amazon Glue Crawler nyeken sadaya data dina ember S3 sareng nyiptakeun tabel sareng partisi. Jieun Crawler lem tina konsol AWS Glue tur tambahkeun ember dimana anjeun nyimpen data. Anjeun tiasa make hiji Mapay pikeun sababaraha ember, nu hal eta bakal nyieun tabel dina database dieusian kalawan ngaran nu cocog jeung ngaran ember. Upami anjeun ngarencanakeun ngagunakeun data ieu sacara rutin, pastikeun pikeun ngonpigurasikeun jadwal peluncuran Crawler pikeun nyocogkeun ka kabutuhan anjeun. Urang make hiji Crawler pikeun sakabéh tabel, nu ngalir unggal jam.
tabél partitioned
Saatos peluncuran munggaran Mapay, tabel pikeun tiap ember discan kedah muncul dina database dieusian dina setélan. Buka konsol Athena sareng panggihan tabel sareng log Nginx. Hayu urang coba maca hiji hal:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Paménta ieu bakal milih sadaya rékaman anu ditampi antara jam 6 énjing sareng 7 énjing dina 8 April 2019. Tapi sabaraha langkung éfisién ieu tibatan ngan ukur maca tina méja anu henteu dipisahkeun? Hayu urang manggihan tur pilih rékaman sarua, nyaring aranjeunna ku timestamp:
3.59 detik sareng 244.34 megabytes data dina set data anu ngan ukur saminggu log. Hayu urang coba saringan ku partisi:
Saeutik langkung gancang, tapi anu paling penting - ngan ukur 1.23 megabyte data! Eta bakal jadi laér leuwih murah lamun teu keur minimum 10 megabytes per pamundut di bedah. Tapi éta tetep langkung saé, sareng dina set data ageung bédana bakal langkung narik.
Ngawangun dasbor ngagunakeun Cube.js
Pikeun ngumpul dasbor, kami nganggo kerangka analitik Cube.js. Cai mibanda cukup loba fungsi, tapi urang museurkeun dua: kamampuhan pikeun otomatis ngagunakeun saringan partisi jeung data pre-aggregation. Éta ngagunakeun skéma data
Hayu urang nyieun aplikasi Cube.js anyar. Kusabab urang parantos nganggo tumpukan AWS, éta logis ngagunakeun Lambda pikeun panyebaran. Anjeun tiasa make template express pikeun generasi lamun rencana pikeun host Cube.js backend di Heroku atanapi Docker. Dokuméntasi ngajelaskeun batur
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
variabel lingkungan dipaké pikeun ngonpigurasikeun aksés database di cube.js. generator bakal nyieun file .env nu bisa nangtukeun konci Anjeun pikeun
Ayeuna urang peryogi
Dina diréktori schema
, jieun file Logs.js
. Ieu conto modél data pikeun nginx:
Kodeu modél
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`
}
}
});
Di dieu urang ngagunakeun variabel
Urang ogé nyetél métrik sareng parameter anu urang hoyong tunjukkeun dina dasbor sareng netepkeun pre-aggregations. Cube.js bakal nyieun tabel tambahan kalawan data pre-aggregated tur otomatis bakal ngamutahirkeun data sakumaha eta datang. Ieu teu ngan speeds up queries, tapi ogé ngurangan biaya pamakéan Athena.
Hayu urang tambahkeun inpormasi ieu kana file schema data:
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`
)
}
}
}
Urang tangtukeun dina modél ieu yén éta téh perlu pre-agrégat data pikeun sakabéh metrics dipaké, sarta ngagunakeun partitioning dumasar bulan.
Ayeuna urang tiasa ngumpul dasbor!
Cube.js backend nyadiakeun
Server Cube.js nampi pamundut di
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Hayu urang pasang klien Cube.js sareng perpustakaan komponén React via NPM:
$ npm i --save @cubejs-client/core @cubejs-client/react
Urang ngimpor komponén cubejs
и QueryRenderer
pikeun ngundeur data, sarta ngumpulkeun dasbor:
Kode dasbor
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>
);
}}
/>
)
}
sumber Dashboard sadia di
sumber: www.habr.com