Ke sledování a analýze provozu Nginx se obvykle používají komerční produkty nebo hotové alternativy s otevřeným zdrojovým kódem, jako je Prometheus + Grafana. Toto je dobrá volba pro monitorování nebo analýzu v reálném čase, ale není příliš vhodná pro historickou analýzu. Na jakémkoli populárním zdroji objem dat z protokolů nginx rychle roste a pro analýzu velkého množství dat je logické použít něco specializovanějšího.
V tomto článku vám řeknu, jak můžete použít
TL:DR;
Ke sběru informací, které používáme
Shromažďování protokolů Nginx
Ve výchozím nastavení vypadají protokoly Nginx asi takto:
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" "-"
Lze je analyzovat, ale je mnohem jednodušší opravit konfiguraci Nginx tak, aby produkovala protokoly 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 pro skladování
K ukládání protokolů použijeme S3. To vám umožní ukládat a analyzovat protokoly na jednom místě, protože Athena může pracovat s daty přímo v S3. Později v článku vám řeknu, jak správně přidávat a zpracovávat protokoly, ale nejprve potřebujeme čistý kbelík v S3, ve kterém se nebude ukládat nic jiného. Vyplatí se předem zvážit, ve kterém regionu svůj kbelík vytvoříte, protože Athena není dostupná ve všech regionech.
Vytvoření okruhu v konzole Athena
Vytvořme tabulku v Atheně pro protokoly. Je potřeba pro psaní i čtení, pokud plánujete používat Kinesis Firehose. Otevřete konzolu Athena a vytvořte tabulku:
Vytvoření SQL tabulky
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');
Vytváření Kinesis Firehose Stream
Kinesis Firehose zapíše data přijatá z Nginx do S3 ve zvoleném formátu a rozdělí je do adresářů ve formátu YYYY/MM/DD/HH. To se bude hodit při čtení dat. Z fluentd můžete samozřejmě zapisovat přímo do S3, ale v tomto případě budete muset zapsat JSON a to je neefektivní kvůli velké velikosti souborů. Navíc při použití PrestoDB nebo Athena je JSON nejpomalejší datový formát. Otevřete tedy konzolu Kinesis Firehose, klikněte na „Vytvořit stream doručení“, v poli „doručení“ vyberte „přímé PUT“:
V další záložce vyberte „Převod formátu záznamu“ - „Povoleno“ a jako formát záznamu vyberte „Apache ORC“. Podle některých výzkumů
Vybereme S3 pro úložiště a bucket, který jsme vytvořili dříve. Aws Glue Crawler, o kterém budu mluvit o něco později, neumí pracovat s prefixy v kbelíku S3, takže je důležité nechat jej prázdný.
Zbývající možnosti lze změnit v závislosti na vaší zátěži, já obvykle používám výchozí. Všimněte si, že komprese S3 není k dispozici, ale ORC ve výchozím nastavení používá nativní kompresi.
Plynule
Nyní, když jsme nakonfigurovali ukládání a přijímání protokolů, musíme nakonfigurovat odesílání. budeme používat
Nejprve potřebujeme konfigurační soubor fluent.conf. Vytvořte jej a přidejte zdroj:
Port 24224
vazba 0.0.0.0
Nyní můžete spustit server Fluentd. Pokud potřebujete pokročilejší konfiguraci, přejděte 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
Tato konfigurace používá cestu /fluentd/log
uložit do mezipaměti protokoly před odesláním. Můžete se bez toho obejít, ale po restartu můžete ztratit vše uložené v mezipaměti s pracnou prací. Můžete také použít jakýkoli port; 24224 je výchozí port Fluentd.
Nyní, když máme spuštěný Fluentd, můžeme tam posílat protokoly Nginx. Nginx obvykle spouštíme v kontejneru Docker, v takovém případě má Docker nativní ovladač protokolování pro 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
Pokud Nginx spustíte jinak, můžete použít soubory protokolu, má Fluentd
Pojďme přidat analýzu protokolu nakonfigurovanou výše do konfigurace Fluent:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
A odesílání protokolů do Kinesis pomocí
<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
Pokud jste vše nakonfigurovali správně, po chvíli (ve výchozím nastavení Kinesis zaznamenává přijatá data každých 10 minut) byste měli vidět soubory protokolu v S3. V nabídce „monitorování“ Kinesis Firehose můžete vidět, kolik dat je zaznamenáno v S3, stejně jako chyby. Nezapomeňte roli Kinesis udělit přístup pro zápis do bucketu S3. Pokud Kinesis nemohla něco analyzovat, přidá chyby do stejného segmentu.
Nyní můžete data zobrazit v Atheně. Pojďme najít nejnovější požadavky, u kterých jsme vrátili chyby:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Skenování všech záznamů pro každý požadavek
Nyní byly naše protokoly zpracovány a uloženy v S3 v ORC, komprimovány a připraveny k analýze. Kinesis Firehose je dokonce uspořádal do adresářů pro každou hodinu. Dokud však tabulka není rozdělena na oddíly, bude Athena načítat všechna data u každého požadavku, až na vzácné výjimky. To je velký problém ze dvou důvodů:
- Objem dat neustále roste a zpomaluje dotazy;
- Athena je účtována na základě objemu naskenovaných dat, minimálně 10 MB na požadavek.
Abychom to napravili, používáme AWS Glue Crawler, který projde data v S3 a zapíše informace o oddílech do Glue Metastore. To nám umožní používat oddíly jako filtr při dotazování Atheny a prohledá pouze adresáře uvedené v dotazu.
Nastavení prohledávače Amazon Glue Crawler
Amazon Glue Crawler skenuje všechna data v bucketu S3 a vytváří tabulky s oddíly. Vytvořte Glue Crawler z konzoly AWS Glue a přidejte kbelík, kam ukládáte data. Jeden prolézací modul můžete použít pro několik segmentů, v takovém případě vytvoří v zadané databázi tabulky s názvy, které se shodují s názvy segmentů. Pokud plánujete tato data používat pravidelně, nezapomeňte nakonfigurovat plán spouštění Crawleru tak, aby vyhovoval vašim potřebám. Pro všechny stoly používáme jeden Crawler, který běží každou hodinu.
Dělené stoly
Po prvním spuštění prolézacího modulu by se v databázi zadané v nastavení měly objevit tabulky pro každý naskenovaný segment. Otevřete konzolu Athena a najděte tabulku s protokoly Nginx. Zkusme si něco přečíst:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Tento dotaz vybere všechny záznamy přijaté mezi 6:7 a 8:2019 XNUMX. dubna XNUMX. O co je to ale efektivnější než pouhé čtení z nerozdělené tabulky? Pojďme zjistit a vybrat stejné záznamy a filtrovat je podle časového razítka:
3.59 sekundy a 244.34 MB dat na datové sadě s pouhým týdnem protokolů. Zkusme filtrovat podle oddílu:
O něco rychlejší, ale hlavně – pouze 1.23 MB dat! Bylo by to mnohem levnější, nebýt minimálních 10 megabajtů na požadavek v ceně. Ale stále je to mnohem lepší a na velkých souborech dat bude rozdíl mnohem působivější.
Vytvoření řídicího panelu pomocí Cube.js
K sestavení dashboardu používáme analytický rámec Cube.js. Má poměrně hodně funkcí, ale nás zajímají dvě: možnost automatického používání filtrů oddílů a předagregace dat. Využívá datové schéma
Pojďme vytvořit novou aplikaci Cube.js. Vzhledem k tomu, že již používáme zásobník AWS, je logické použít pro nasazení Lambda. Pokud plánujete hostit backend Cube.js v Heroku nebo Dockeru, můžete použít expresní šablonu pro generování. Dokumentace popisuje ostatní
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Proměnné prostředí se používají ke konfiguraci přístupu k databázi v cube.js. Generátor vytvoří soubor .env, ve kterém můžete zadat své klíče
Teď potřebujeme
V adresáři schema
, vytvořte soubor Logs.js
. Zde je příklad datového modelu pro nginx:
Kód modelu
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`
}
}
});
Zde používáme proměnnou
Nastavíme také metriky a parametry, které chceme na dashboardu zobrazovat, a určíme předagregace. Cube.js vytvoří další tabulky s předem agregovanými daty a automaticky aktualizuje data, jakmile dorazí. To nejen zrychlí dotazy, ale také sníží náklady na používání Atheny.
Přidejte tyto informace do souboru schématu dat:
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 tomto modelu specifikujeme, že je nutné předem agregovat data pro všechny používané metriky a používat rozdělení podle měsíců.
Nyní můžeme sestavit palubní desku!
Backend Cube.js poskytuje
Server Cube.js přijme požadavek
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Nainstalujme klienta Cube.js a knihovnu komponent React přes NPM:
$ npm i --save @cubejs-client/core @cubejs-client/react
Dovážíme komponenty cubejs
и QueryRenderer
ke stažení dat a shromažďování řídicího panelu:
Kód řídicího panelu
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>
);
}}
/>
)
}
Zdroje řídicího panelu jsou k dispozici na
Zdroj: www.habr.com