Analýza protokolov Nginx pomocou Amazon Athena a Cube.js

Na monitorovanie a analýzu fungovania Nginx sa zvyčajne používajú komerčné produkty alebo hotové alternatívy s otvoreným zdrojom, ako napríklad Prometheus + Grafana. Je to dobrá možnosť na monitorovanie alebo analýzu v reálnom čase, ale nie je veľmi vhodná na analýzu histórie. Na akomkoľvek populárnom zdroji objem údajov z protokolov nginx rýchlo rastie a na analýzu veľkého množstva údajov je logické použiť niečo špecializovanejšie.

V tomto článku vám poviem, ako ho môžete použiť Athena analyzovať protokoly, pričom ako príklad použijem Nginx a ukážem, ako zostaviť analytický dashboard z týchto údajov pomocou open-source rámca cube.js. Tu je kompletná architektúra riešenia:

Analýza protokolov Nginx pomocou Amazon Athena a Cube.js

TL:DR;
Odkaz na hotový informačný panel.

Na zhromažďovanie informácií, ktoré používame Plynulé, na spracovanie - AWS Kinesis Data Firehose и AWS lepidlo, na uskladnenie - Aws s3. Pomocou tohto balíka môžete ukladať nielen protokoly nginx, ale aj iné udalosti, ako aj protokoly iných služieb. Niektoré časti môžete nahradiť podobnými pre váš stack, napríklad môžete zapisovať protokoly do kinesis priamo z nginx, obísť fluentd, alebo na to použiť logstash.

Zbieranie denníkov Nginx

V predvolenom nastavení vyzerajú 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" "-"

Môžu byť analyzované, ale je oveľa jednoduchšie opraviť konfiguráciu Nginx tak, aby vytvárala 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 na uskladnenie

Na ukladanie protokolov použijeme S3. To vám umožňuje ukladať a analyzovať protokoly na jednom mieste, pretože Athena môže pracovať s údajmi priamo v S3. Ďalej v článku vám poviem, ako správne pridávať a spracovávať protokoly, ale najprv potrebujeme čisté vedro v S3, v ktorom nebude uložené nič iné. Oplatí sa vopred zvážiť, v ktorom regióne budete svoj vedro vytvárať, pretože Athena nie je dostupná vo všetkých regiónoch.

Vytvorenie okruhu v konzole Athena

V Athene vytvoríme tabuľku pre protokoly. Je potrebný na písanie aj čítanie, ak plánujete používať Kinesis Firehose. Otvorte konzolu Athena a vytvorte tabuľku:

Vytvorenie SQL tabuľky

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');

Vytvorenie Kinesis Firehose Stream

Kinesis Firehose zapíše dáta prijaté z Nginx do S3 vo zvolenom formáte a rozdelí ich do adresárov vo formáte RRRR/MM/DD/HH. To sa vám bude hodiť pri čítaní údajov. Z fluentd môžete samozrejme zapisovať priamo do S3, ale v tomto prípade budete musieť napísať JSON, čo je neefektívne kvôli veľkej veľkosti súborov. Navyše, keď používate PrestoDB alebo Athena, JSON je najpomalší dátový formát. Otvorte teda konzolu Kinesis Firehose, kliknite na „Vytvoriť stream doručenia“, v poli „doručenie“ vyberte „priame PUT“:

Analýza protokolov Nginx pomocou Amazon Athena a Cube.js

Na ďalšej karte vyberte „Konverzia formátu záznamu“ - „Povolené“ a ako formát záznamu vyberte „Apache ORC“. Podľa niektorých výskumov Owen O'Malley, toto je optimálny formát pre PrestoDB a Athena. Ako schému používame tabuľku, ktorú sme vytvorili vyššie. Upozorňujeme, že v kinezii môžete zadať ľubovoľné umiestnenie S3; použije sa iba schéma z tabuľky. Ak však zadáte iné umiestnenie S3, nebudete môcť čítať tieto záznamy z tejto tabuľky.

Analýza protokolov Nginx pomocou Amazon Athena a Cube.js

Na uloženie vyberieme S3 a vedro, ktoré sme vytvorili skôr. Aws Glue Crawler, o ktorom budem hovoriť o niečo neskôr, nemôže pracovať s predponami vo vedre S3, takže je dôležité nechať ho prázdny.

Analýza protokolov Nginx pomocou Amazon Athena a Cube.js

Zostávajúce možnosti je možné zmeniť v závislosti od vašej záťaže; zvyčajne používam predvolené. Upozorňujeme, že kompresia S3 nie je dostupná, ale ORC štandardne používa natívnu kompresiu.

Plynulé

Teraz, keď sme nakonfigurovali ukladanie a prijímanie protokolov, musíme nakonfigurovať odosielanie. Budeme používať Plynulé, pretože milujem Ruby, ale môžete použiť Logstash alebo poslať logy priamo do kinesis. Server Fluentd je možné spustiť niekoľkými spôsobmi, poviem vám o docker, pretože je to jednoduché a pohodlné.

Najprv potrebujeme konfiguračný súbor fluent.conf. Vytvorte ho a pridajte zdroj:

typ vpred
Port 24224
viazať 0.0.0.0

Teraz môžete spustiť server Fluentd. Ak potrebujete pokročilejšiu konfiguráciu, prejdite na Docker hub K dispozícii je podrobný návod vrátane toho, ako zostaviť obrázok.

$ 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

Táto konfigurácia používa cestu /fluentd/log pred odoslaním uložiť denníky do vyrovnávacej pamäte. Môžete to urobiť bez toho, ale po reštarte môžete stratiť všetko, čo je uložené vo vyrovnávacej pamäti. Môžete tiež použiť ľubovoľný port; 24224 je predvolený port Fluentd.

Teraz, keď máme spustený Fluentd, môžeme tam posielať protokoly Nginx. Nginx zvyčajne spúšťame v kontajneri Docker, v takom prípade má Docker natívny ovládač protokolovania pre 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

Ak spustíte Nginx inak, môžete použiť protokolové súbory, ktoré má Fluentd doplnok file tail.

Pridajme analýzu protokolu nakonfigurovanú vyššie do konfigurácie Fluent:

<filter YOUR-NGINX-TAG.*>
  @type parser
  key_name log
  emit_invalid_record_to_error false
  <parse>
    @type json
  </parse>
</filter>

A odosielanie protokolov do Kinesis pomocou plugin kinesis firehose:

<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

Ak ste všetko nakonfigurovali správne, po chvíli (štandardne Kinesis zaznamenáva prijaté údaje raz za 10 minút) by ste mali vidieť log súbory v S3. V ponuke „monitorovanie“ Kinesis Firehose môžete vidieť, koľko údajov je zaznamenaných v S3, ako aj chyby. Nezabudnite dať rolu Kinesis prístup na zápis do bloku S3. Ak Kinesis niečo nedokáže analyzovať, pridá chyby do toho istého vedra.

Teraz si môžete prezerať údaje v Athene. Poďme nájsť najnovšie žiadosti, pre ktoré sme vrátili chyby:

SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;

Skenovanie všetkých záznamov pre každú požiadavku

Teraz sú naše protokoly spracované a uložené v S3 v ORC, komprimované a pripravené na analýzu. Kinesis Firehose ich dokonca usporiadal do adresárov na každú hodinu. Pokiaľ však tabuľka nie je rozdelená na partície, Athena načíta všetky údaje pri každej požiadavke, až na zriedkavé výnimky. Toto je veľký problém z dvoch dôvodov:

  • Objem dát neustále rastie, čím sa spomaľujú dopyty;
  • Athena sa účtuje na základe objemu naskenovaných dát, pričom na žiadosť je minimálne 10 MB.

Aby sme to vyriešili, používame AWS Glue Crawler, ktorý prehľadá údaje v S3 a zapíše informácie o oddieloch do Glue Metastore. To nám umožní použiť oddiely ako filter pri dopytovaní Atheny a bude skenovať iba adresáre uvedené v dotaze.

Nastavenie prehľadávača Amazon Glue Crawler

Amazon Glue Crawler naskenuje všetky údaje vo vedre S3 a vytvorí tabuľky s oddielmi. Vytvorte Glue Crawler z konzoly AWS Glue a pridajte vedro, kde ukladáte dáta. Jeden prehľadávač môžete použiť pre niekoľko segmentov, v takom prípade vytvorí tabuľky v zadanej databáze s názvami, ktoré sa zhodujú s názvami segmentov. Ak plánujete tieto údaje používať pravidelne, nezabudnite nakonfigurovať plán spúšťania Crawlera tak, aby vyhovoval vašim potrebám. Na všetky stoly používame jeden Crawler, ktorý beží každú hodinu.

Rozdelené stoly

Po prvom spustení prehľadávača by sa tabuľky pre každý naskenovaný segment mali objaviť v databáze špecifikovanej v nastaveniach. Otvorte konzolu Athena a nájdite tabuľku s protokolmi Nginx. Skúsme si niečo prečítať:

SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
  partition_0 = '2019' AND
  partition_1 = '04' AND
  partition_2 = '08' AND
  partition_3 = '06'
  );

Tento dopyt vyberie všetky záznamy prijaté medzi 6:7 a 8:2019 dňa XNUMX. apríla XNUMX. O čo je to však efektívnejšie ako len čítanie z nerozdelenej tabuľky? Poďme zistiť a vybrať rovnaké záznamy, filtrovať ich podľa časovej pečiatky:

Analýza protokolov Nginx pomocou Amazon Athena a Cube.js

3.59 sekundy a 244.34 megabajtov údajov v súbore údajov iba s týždennými protokolmi. Skúsme filtrovať podľa oddielu:

Analýza protokolov Nginx pomocou Amazon Athena a Cube.js

O niečo rýchlejšie, ale čo je najdôležitejšie – iba 1.23 MB dát! Bolo by to oveľa lacnejšie, ak by v cene nebolo minimálne 10 megabajtov na požiadavku. Stále je to však oveľa lepšie a na veľkých súboroch údajov bude rozdiel oveľa pôsobivejší.

Vytvorenie dashboardu pomocou Cube.js

Na zostavenie dashboardu používame analytický rámec Cube.js. Má pomerne veľa funkcií, ale nás zaujímajú dve: možnosť automatického používania filtrov partícií a predagregácie dát. Používa dátovú schému dátová schéma, napísaný v Javascripte na generovanie SQL a spustenie databázového dotazu. Musíme len uviesť, ako použiť filter oddielov v dátovej schéme.

Poďme vytvoriť novú aplikáciu Cube.js. Keďže už používame zásobník AWS, je logické použiť na nasadenie Lambda. Express šablónu môžete použiť na generovanie, ak plánujete hostiť backend Cube.js v Heroku alebo Docker. Dokumentácia popisuje ostatné metódy hosťovania.

$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena

Premenné prostredia sa používajú na konfiguráciu prístupu k databáze v cube.js. Generátor vytvorí súbor .env, v ktorom môžete špecifikovať svoje kľúče Athena.

Teraz potrebujeme dátová schéma, v ktorom presne uvedieme, ako sú naše protokoly uložené. Môžete tiež určiť, ako vypočítať metriky pre informačné panely.

V adresári schema, vytvorte súbor Logs.js. Tu je príklad dátového modelu pre 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`
    }
  }
});

Tu používame premennú FILTER_PARAMSna vygenerovanie dotazu SQL s filtrom oddielov.

Nastavíme tiež metriky a parametre, ktoré chceme zobraziť na dashboarde a určíme predagregácie. Cube.js vytvorí ďalšie tabuľky s vopred agregovanými údajmi a automaticky aktualizuje údaje, keď prídu. To nielen zrýchľuje dopyty, ale aj znižuje náklady na používanie Atheny.

Pridajme tieto informácie do súboru dátovej schémy:

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 modeli špecifikujeme, že je potrebné vopred agregovať údaje pre všetky použité metriky a použiť rozdelenie podľa mesiacov. Rozdelenie pred agregáciou môže výrazne urýchliť zber a aktualizáciu údajov.

Teraz môžeme zostaviť palubnú dosku!

Backend Cube.js poskytuje REST API a súbor klientskych knižníc pre populárne front-end rámce. Na zostavenie dashboardu použijeme React verziu klienta. Cube.js poskytuje len dáta, takže budeme potrebovať vizualizačnú knižnicu – to sa mi páči rechartov, ale môžete použiť akýkoľvek.

Server Cube.js prijme požiadavku formát JSON, ktorá špecifikuje požadované metriky. Ak chcete napríklad vypočítať, koľko chýb dal Nginx za deň, musíte odoslať nasledujúcu žiadosť:

{
  "measures": ["Logs.errorCount"],
  "timeDimensions": [
    {
      "dimension": "Logs.createdAt",
      "dateRange": ["2019-01-01", "2019-01-07"],
      "granularity": "day"
    }
  ]
}

Nainštalujeme klienta Cube.js a knižnicu komponentov React cez NPM:

$ npm i --save @cubejs-client/core @cubejs-client/react

Dovážame komponenty cubejs и QueryRendererstiahnuť údaje a zhromaždiť informačný panel:

Kód palubnej dosky

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 palubnej dosky sú dostupné na karanténa kódu.

Zdroj: hab.com

Pridať komentár