Általában kereskedelmi termékeket vagy kész nyílt forráskódú alternatívákat, például Prometheus + Grafana-t használnak az Nginx működésének megfigyelésére és elemzésére. Ez egy jó lehetőség figyeléshez vagy valós idejű elemzéshez, de nem túl kényelmes történelmi elemzéshez. Bármely népszerű erőforráson az nginx naplókból származó adatok mennyisége gyorsan növekszik, és nagy mennyiségű adat elemzéséhez logikus, hogy valami speciálisabbat használjunk.
Ebben a cikkben elmondom, hogyan használhatod
TL:DR;
Az általunk használt információk gyűjtésére
Nginx naplók gyűjtése
Alapértelmezés szerint az Nginx naplók valahogy így néznek ki:
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" "-"
Elemezhetők, de sokkal könnyebb kijavítani az Nginx konfigurációt úgy, hogy az JSON-ban készítsen naplókat:
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 tároláshoz
A naplók tárolásához az S3-at fogjuk használni. Ez lehetővé teszi a naplók egy helyen történő tárolását és elemzését, mivel az Athena közvetlenül tud dolgozni az S3-ban lévő adatokkal. A cikk későbbi részében elmondom, hogyan kell helyesen hozzáadni és feldolgozni a naplókat, de először szükségünk van egy tiszta vödörre az S3-ban, amelyben semmi más nem kerül tárolásra. Érdemes előre megfontolni, hogy melyik régióban hozza létre a gyűjtőhelyet, mert az Athena nem érhető el minden régióban.
Áramkör létrehozása az Athena konzolban
Hozzunk létre egy táblázatot az Athénában a naplókhoz. Íráshoz és olvasáshoz egyaránt szükséges, ha a Kinesis Firehose használatát tervezi. Nyissa meg az Athena konzolt, és hozzon létre egy táblázatot:
SQL tábla létrehozása
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 Stream létrehozása
A Kinesis Firehose az Nginxtől kapott adatokat az S3-ba a kiválasztott formátumban írja, YYYY/MM/DD/ÓH formátumú könyvtárakra osztva. Ez hasznos lesz az adatok olvasásakor. A fluentd-ből természetesen közvetlenül S3-ba írhat, de ebben az esetben JSON-t kell írnia, és ez a fájlok nagy mérete miatt nem hatékony. Ezenkívül a PrestoDB vagy az Athena használatakor a JSON a leglassabb adatformátum. Tehát nyissa meg a Kinesis Firehose konzolt, kattintson a „Kézbesítési adatfolyam létrehozása” elemre, és válassza ki a „közvetlen PUT” lehetőséget a „szállítás” mezőben:
A következő lapon válassza a „Record format conversion” - „Enabled” lehetőséget, és válassza ki az „Apache ORC” felvételi formátumot. Egyes kutatások szerint
Tároláshoz az S3-at és a korábban létrehozott vödröt választjuk. Az Aws Glue Crawler, amelyről egy kicsit később fogok beszélni, nem tud működni az S3-as vödörben lévő előtagokkal, ezért fontos, hogy üresen hagyja.
A többi opció a terheléstől függően változtatható, én általában az alapértelmezetteket használom. Vegye figyelembe, hogy az S3 tömörítés nem elérhető, de az ORC alapértelmezés szerint natív tömörítést használ.
Fluentd
Most, hogy beállítottuk a naplók tárolását és fogadását, konfigurálnunk kell a küldést. Használni fogjuk
Először is szükségünk van a fluent.conf konfigurációs fájlra. Hozd létre és add hozzá a forrást:
port 24224
köt 0.0.0.0
Most elindíthatja a Fluentd szervert. Ha fejlettebb konfigurációra van szüksége, látogasson el ide
$ 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
Ez a konfiguráció az elérési utat használja /fluentd/log
a naplók gyorsítótárazásához küldés előtt. E nélkül is megteheti, de újraindításkor mindent elveszíthet, ami gyorsítótárban van a visszatörő munkával. Bármilyen portot is használhat; a 24224 az alapértelmezett Fluentd port.
Most, hogy a Fluentd fut, Nginx naplókat küldhetünk oda. Az Nginx-et általában Docker-tárolóban futtatjuk, ebben az esetben a Docker rendelkezik egy natív naplózási illesztőprogrammal a Fluentd számára:
$ 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
Ha az Nginxet másként futtatja, használhat naplófájlokat, a Fluentd ezt teszi
Adjuk hozzá a fent konfigurált naplóelemzést a Fluent konfigurációhoz:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
És naplók küldése a Kinesisnek segítségével
<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>
Athéné
Ha mindent helyesen konfigurált, akkor egy idő után (a Kinesis alapértelmezés szerint 10 percenként rögzíti a kapott adatokat) naplófájlokat kell látnia az S3-ban. A Kinesis Firehose „monitoring” menüjében láthatja, hogy mennyi adatot rögzít az S3, valamint a hibákat. Ne felejtsen el írási hozzáférést adni az S3 tárolóhoz a Kinesis szerepkör számára. Ha a Kinesis nem tudott valamit elemezni, akkor a hibákat ugyanabba a gyűjtőhelyre teszi.
Most megtekintheti az adatokat az Athénában. Nézzük meg a legutóbbi kéréseket, amelyeknél hibát adtunk vissza:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Az összes rekord szkennelése minden kérés esetén
Mostanra naplóinkat feldolgoztuk és az S3-ban tároltuk ORC-ben, tömörítve és elemzésre készen. A Kinesis Firehose még könyvtárakba is rendezte őket óránként. Mindaddig azonban, amíg a tábla nincs particionálva, az Athena ritka kivételektől eltekintve minden kérésre minden idők adatait betölti. Ez két okból is nagy probléma:
- Az adatok mennyisége folyamatosan növekszik, lassítva a lekérdezéseket;
- Az Athena számlázása a beolvasott adatok mennyisége alapján történik, kérésenként legalább 10 MB-tal.
Ennek kijavításához az AWS Glue Crawlert használjuk, amely feltérképezi az S3-ban lévő adatokat, és beírja a partíciós információkat a Glue Metastore-ba. Ez lehetővé teszi számunkra, hogy a partíciókat szűrőként használjuk az Athena lekérdezésekor, és csak a lekérdezésben megadott könyvtárakat vizsgálja.
Az Amazon Glue Crawler beállítása
Az Amazon Glue Crawler átvizsgálja az S3 vödörben lévő összes adatot, és partíciókat tartalmazó táblázatokat hoz létre. Hozzon létre egy Glue Crawlert az AWS Glue konzolból, és adjon hozzá egy tárolót, ahol tárolja az adatokat. Egy bejáró több gyűjtőcsoporthoz is használható, ebben az esetben a megadott adatbázisban táblákat hoz létre, amelyek neve megegyezik a gyűjtőzónák nevével. Ha rendszeresen szeretné használni ezeket az adatokat, ügyeljen arra, hogy igényeinek megfelelően konfigurálja a Crawler indítási ütemezését. Minden asztalhoz egy bejárót használunk, amely óránként fut.
Partícionált táblák
A bejáró első indítása után a beállításokban megadott adatbázisban minden beolvasott gyűjtőcsoporthoz tartozó táblázatoknak meg kell jelenniük. Nyissa meg az Athena konzolt, és keresse meg az Nginx-naplókat tartalmazó táblázatot. Próbáljunk meg olvasni valamit:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Ez a lekérdezés az összes rekordot kiválasztja, amely 6. április 7-án reggel 8 és reggel 2019 óra között érkezett. De mennyivel hatékonyabb ez, mint egy nem particionált táblából olvasni? Nézzük meg és jelöljük ki ugyanazokat a rekordokat, időbélyeg szerint szűrve őket:
3.59 másodperc és 244.34 megabájt adat egy adatkészleten, amely mindössze egy hét naplózást tartalmaz. Próbáljunk meg partíciónkénti szűrést:
Kicsit gyorsabb, de ami a legfontosabb - csak 1.23 megabájt adat! Sokkal olcsóbb lenne, ha nem a minimum 10 megabájt kérésenként az árazásban. De még mindig sokkal jobb, és a nagy adatkészleteken a különbség sokkal lenyűgözőbb lesz.
Irányítópult készítése a Cube.js használatával
Az irányítópult összeállításához a Cube.js elemzési keretrendszert használjuk. Elég sok funkciója van, de minket kettő érdekel: a partíciószűrők automatikus használatának lehetősége és az adatok előzetes összesítése. Adatsémát használ
Hozzon létre egy új Cube.js alkalmazást. Mivel már az AWS-vermet használjuk, logikus a Lambda használata a telepítéshez. Használhatja az expressz sablont a generáláshoz, ha a Cube.js háttérprogramot Herokuban vagy Dockerben kívánja tárolni. A dokumentáció másokat is leír
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
A környezeti változók segítségével konfigurálható az adatbázis-hozzáférés a cube.js fájlban. A generátor létrehoz egy .env fájlt, amelyben megadhatja a kulcsait
Most szükségünk van
Könyvtárban schema
, hozzon létre egy fájlt Logs.js
. Íme egy példa adatmodell az nginx számára:
Modell kód
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`
}
}
});
Itt a változót használjuk
Ezenkívül beállítjuk azokat a mérőszámokat és paramétereket, amelyeket meg szeretnénk jeleníteni a műszerfalon, és megadjuk az előzetes összesítéseket. A Cube.js további táblákat hoz létre előre összesített adatokkal, és automatikusan frissíti az adatokat, amint megérkeznek. Ez nemcsak felgyorsítja a lekérdezéseket, hanem csökkenti az Athena használatának költségeit is.
Adjuk hozzá ezt az információt az adatsémafájlhoz:
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`
)
}
}
}
Ebben a modellben megadjuk, hogy az összes használt metrika adatait előre összesíteni kell, és havi particionálást kell használni.
Most összeállíthatjuk a műszerfalat!
A Cube.js háttérprogramja biztosítja
A Cube.js szerver elfogadja a kérést
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Telepítsük a Cube.js klienst és a React komponens könyvtárat NPM-en keresztül:
$ npm i --save @cubejs-client/core @cubejs-client/react
Alkatrészeket importálunk cubejs
и QueryRenderer
az adatok letöltéséhez és az irányítópult összegyűjtéséhez:
Irányítópult kódja
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>
);
}}
/>
)
}
Az irányítópult forrásai a címen érhetők el
Forrás: will.com