Analýza protokolů Nginx pomocí Amazon Athena a Cube.js

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 Athena analyzovat protokoly, přičemž jako příklad vezmu Nginx, a ukážu, jak z těchto dat sestavit analytický dashboard pomocí open-source rámce cube.js. Zde je kompletní architektura řešení:

Analýza protokolů Nginx pomocí Amazon Athena a Cube.js

TL:DR;
Odkaz na hotový dashboard.

Ke sběru informací, které používáme Plynule, pro zpracování - AWS Kinesis Data Firehose и Lepidlo AWS, na uskladnění - AWS S3. Pomocí tohoto balíčku můžete ukládat nejen protokoly nginx, ale také další události a také protokoly dalších služeb. Některé části můžete nahradit podobnými pro váš stack, například můžete zapisovat logy do kinesis přímo z nginx, obejít fluentd, nebo k tomu použít logstash.

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“:

Analýza protokolů Nginx pomocí Amazon Athena a Cube.js

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ů Owen O'Malley, toto je optimální formát pro PrestoDB a Athena. Jako schéma použijeme tabulku, kterou jsme vytvořili výše. Vezměte prosím na vědomí, že v kinezi můžete zadat libovolné umístění S3, použije se pouze schéma z tabulky. Pokud však zadáte jiné umístění S3, nebudete moci tyto záznamy z této tabulky číst.

Analýza protokolů Nginx pomocí Amazon Athena a Cube.js

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ý.

Analýza protokolů Nginx pomocí Amazon Athena a Cube.js

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 Plynule, protože Ruby miluji, ale můžete použít Logstash nebo poslat logy přímo do kinesis. Server Fluentd lze spustit několika způsoby, řeknu vám o dockeru, protože je jednoduchý a pohodlný.

Nejprve potřebujeme konfigurační soubor fluent.conf. Vytvořte jej a přidejte zdroj:

typ vpřed
Port 24224
vazba 0.0.0.0

Nyní můžete spustit server Fluentd. Pokud potřebujete pokročilejší konfiguraci, přejděte na Docker hub K dispozici je podrobný návod, včetně toho, jak sestavit obrázek.

$ 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 plugin ocasu souboru.

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í 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

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:

Analýza protokolů Nginx pomocí Amazon Athena a Cube.js

3.59 sekundy a 244.34 MB dat na datové sadě s pouhým týdnem protokolů. Zkusme filtrovat podle oddílu:

Analýza protokolů Nginx pomocí Amazon Athena a Cube.js

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 datové schéma, napsaný v Javascriptu pro generování SQL a provádění databázového dotazu. Potřebujeme pouze uvést, jak použít filtr oddílů v datovém schématu.

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í metody hostování.

$ 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 Athena.

Teď potřebujeme datové schéma, ve kterém přesně uvedeme, jak jsou naše protokoly uloženy. Zde můžete také určit, jak vypočítat metriky pro řídicí panely.

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 FILTER_PARAMSvygenerovat SQL dotaz s filtrem oddílů.

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ů. Předagregační rozdělení může výrazně urychlit sběr a aktualizaci dat.

Nyní můžeme sestavit palubní desku!

Backend Cube.js poskytuje REST API a sadu klientských knihoven pro populární front-end frameworky. K sestavení dashboardu použijeme verzi klienta React. Cube.js poskytuje pouze data, takže budeme potřebovat vizualizační knihovnu – to se mi líbí překresluje, ale můžete použít jakýkoli.

Server Cube.js přijme požadavek formát JSON, který specifikuje požadované metriky. Chcete-li například vypočítat, kolik chyb Nginx poskytl za den, musíte odeslat následující 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 и QueryRendererke 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 kód sandbox.

Zdroj: www.habr.com

Přidat komentář