Nginx logib analüütika Amazon Athena ja Cube.js abil

Tavaliselt kasutatakse Nginxi töö jälgimiseks ja analüüsimiseks kommertstooteid või valmis avatud lähtekoodiga alternatiive, nagu Prometheus + Grafana. See on hea valik jälgimiseks või reaalajas analüüsimiseks, kuid ajaloolise analüüsi jaoks mitte eriti mugav. Mis tahes populaarse ressursi puhul kasvab nginxi logide andmemaht kiiresti ja suure hulga andmete analüüsimiseks on loogiline kasutada midagi spetsiifilisemat.

Selles artiklis räägin teile, kuidas seda kasutada Athena logide analüüsimiseks, võttes näiteks Nginxi, ja näitan, kuidas nendest andmetest koostada analüütiline armatuurlaud, kasutades avatud lähtekoodiga cube.js raamistikku. Siin on täielik lahenduse arhitektuur:

Nginx logib analüütika Amazon Athena ja Cube.js abil

TL:DR;
Link valmis armatuurlauale.

Kasutatava teabe kogumiseks ladusalt, töötlemiseks - AWS Kinesis Data Firehose и AWS liim, ladustamiseks - AWS S3. Selle paketi abil saate salvestada mitte ainult nginxi logisid, vaid ka muid sündmusi, aga ka muude teenuste logisid. Sa võid mõne osa oma virna jaoks sarnaste vastu asendada, näiteks võid kirjutada logid kinesisesse otse nginxist, fluentd-st mööda minnes või kasutada selleks logstashi.

Nginxi logide kogumine

Vaikimisi näevad Nginxi logid välja umbes sellised:

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

Neid saab sõeluda, kuid Nginxi konfiguratsiooni on palju lihtsam parandada nii, et see looks logisid JSON-is:

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 ladustamiseks

Logide salvestamiseks kasutame S3. See võimaldab salvestada ja analüüsida logisid ühes kohas, kuna Athena saab S3-s otse andmetega töötada. Hiljem artiklis räägin teile, kuidas logisid õigesti lisada ja töödelda, kuid kõigepealt vajame S3-s puhast ämbrit, kuhu midagi muud ei salvestata. Tasub eelnevalt läbi mõelda, millises piirkonnas oma ämbri loote, sest Athena pole kõigis piirkondades saadaval.

Athena konsoolis vooluringi loomine

Loome Athenas logide jaoks tabeli. Seda on vaja nii kirjutamiseks kui lugemiseks, kui kavatsete kasutada Kinesis Firehose'i. Avage Athena konsool ja looge tabel:

SQL tabeli loomine

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 Streami loomine

Kinesis Firehose kirjutab Nginxist saadud andmed S3-le valitud vormingus, jagades need kataloogidesse vormingus AAAA/KK/PP/TT. See tuleb andmete lugemisel kasuks. Muidugi saate fluentd-st otse S3-le kirjutada, kuid sel juhul peate kirjutama JSON-i ja see on failide suure suuruse tõttu ebaefektiivne. Lisaks on PrestoDB või Athena kasutamisel JSON kõige aeglasem andmevorming. Nii et avage Kinesis Firehose'i konsool, klõpsake "Loo tarnevoog", valige väljal "tarne" "otsene PUT".

Nginx logib analüütika Amazon Athena ja Cube.js abil

Järgmisel vahekaardil valige "Salvestamisvormingu teisendamine" - "Lubatud" ja valige salvestusvorminguks "Apache ORC". Mõnede uuringute kohaselt Owen O'Malley, see on PrestoDB ja Athena jaoks optimaalne vorming. Skeemina kasutame ülaltoodud tabelit. Pange tähele, et kinesis saab määrata mis tahes S3 asukoha; tabelist kasutatakse ainult skeemi. Kuid kui määrate mõne muu S3 asukoha, ei saa te neid kirjeid sellest tabelist lugeda.

Nginx logib analüütika Amazon Athena ja Cube.js abil

Valime ladustamiseks S3 ja varem loodud ämbri. Aws Glue Crawler, millest räägin veidi hiljem, ei saa S3 ämbris eesliidetega töötada, seega on oluline see tühjaks jätta.

Nginx logib analüütika Amazon Athena ja Cube.js abil

Ülejäänud valikuid saab muuta sõltuvalt teie koormusest; tavaliselt kasutan vaikevalikuid. Pange tähele, et S3 pakkimine pole saadaval, kuid ORC kasutab vaikimisi natiivset tihendamist.

ladusalt

Nüüd, kui oleme logide salvestamise ja vastuvõtmise konfigureerinud, peame konfigureerima saatmise. Me kasutame ladusalt, sest mulle meeldib Ruby, kuid võite kasutada Logstashi või saata logid otse kinesisesse. Fluentd serverit saab käivitada mitmel viisil, ma räägin teile dockerist, sest see on lihtne ja mugav.

Esiteks vajame konfiguratsioonifaili fluent.conf. Looge see ja lisage allikas:

tüüp edasi
port 24224
siduda 0.0.0.0

Nüüd saate käivitada Fluentd serveri. Kui vajate täpsemat konfiguratsiooni, minge aadressile Dockeri jaotur Seal on üksikasjalik juhend, sealhulgas pildi kokkupanemine.

$ 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

See konfiguratsioon kasutab teed /fluentd/log logide vahemällu salvestamiseks enne saatmist. Saate ka ilma selleta hakkama, kuid taaskäivitamisel võite kaotada kõik, mis on vahemällu salvestatud. Võite kasutada ka mis tahes porti; 24224 on vaikimisi Fluentd-port.

Nüüd, kui Fluentd töötab, saame sinna saata Nginxi logisid. Tavaliselt käitame Nginxit Dockeri konteineris, sel juhul on Dockeril Fluentdi jaoks natiivne logidraiver:

$ 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

Kui kasutate Nginxit teisiti, saate kasutada logifaile, Fluentd on seda teinud failisaba plugin.

Lisame Fluenti konfiguratsioonile ülal konfigureeritud logi sõelumise:

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

Ja logide saatmine Kinesisele kasutades kinesis firehose plugin:

<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

Kui oled kõik õigesti seadistanud, siis mõne aja pärast (vaikimisi Kinesis salvestab saadud andmed kord 10 minuti jooksul) peaks S3-s nägema logifaile. Kinesis Firehose'i jälgimise menüüs näete, kui palju andmeid S3-s salvestatakse, ja ka vigu. Ärge unustage anda Kinesise rollile S3 ämbrile kirjutamisõigust. Kui Kinesis ei saanud midagi sõeluda, lisab see vead samasse ämbrisse.

Nüüd saate andmeid Athenas vaadata. Otsime üles viimased päringud, mille puhul tagastasime vead:

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

Kõigi kirjete skannimine iga päringu jaoks

Nüüd on meie logid töödeldud ja S3-s ORC-s salvestatud, tihendatud ja analüüsimiseks valmis. Kinesis Firehose korraldas need isegi iga tunni kohta kataloogidesse. Kuid seni, kuni tabel pole sektsioonideks jagatud, laadib Athena iga päringu korral kõigi aegade andmeid, välja arvatud harvad erandid. See on suur probleem kahel põhjusel:

  • Andmemaht kasvab pidevalt, päringuid aeglustades;
  • Athenale esitatakse arve skannitud andmete mahu alusel, vähemalt 10 MB päringu kohta.

Selle parandamiseks kasutame AWS Glue Crawleri, mis roomab S3 andmetes ja kirjutab partitsiooniteabe Glue Metastore'i. See võimaldab meil kasutada Athena päringu tegemisel sektsioone filtrina ja see skannib ainult päringus määratud katalooge.

Amazon Glue Crawleri seadistamine

Amazon Glue Crawler skannib kõik S3 ämbris olevad andmed ja loob vaheseintega tabeleid. Looge AWS Glue'i konsoolist liimiroomik ja lisage ämber, kuhu andmeid salvestate. Ühte roomajat saab kasutada mitme ämbri jaoks, sel juhul loob see määratud andmebaasi tabelid nimedega, mis vastavad ämbrite nimedele. Kui kavatsete neid andmeid regulaarselt kasutada, konfigureerige kindlasti roomaja käivitamise ajakava vastavalt oma vajadustele. Kõigi laudade jaoks kasutame ühte Crawlerit, mis töötab iga tund.

Jaotatud lauad

Pärast roomaja esmakordset käivitamist peaksid seadetes määratud andmebaasis ilmuma iga skannitud ämbri tabelid. Avage Athena konsool ja leidke Nginxi logidega tabel. Proovime midagi lugeda:

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

See päring valib kõik kirjed, mis on saabunud 6. aprillil 7 kella 8–2019. Kuid kui palju tõhusam see on kui lihtsalt lugemine jaotamata tabelist? Uurime välja ja valime samad kirjed, filtreerides need ajatempli järgi:

Nginx logib analüütika Amazon Athena ja Cube.js abil

3.59 sekundit ja 244.34 megabaiti andmeid andmekogus, mis sisaldab vaid nädala logisid. Proovime filtrit partitsiooni järgi:

Nginx logib analüütika Amazon Athena ja Cube.js abil

Natuke kiirem, aga mis kõige tähtsam – ainult 1.23 megabaiti andmemahtu! See oleks palju odavam, kui mitte hinnakujunduses olevad minimaalsed 10 megabaiti päringu kohta. Kuid see on siiski palju parem ja suurte andmekogumite puhul on erinevus palju muljetavaldavam.

Armatuurlaua loomine Cube.js-i abil

Armatuurlaua kokkupanemiseks kasutame Cube.js analüütilist raamistikku. Sellel on üsna palju funktsioone, kuid meid huvitavad kaks: partitsioonifiltrite automaatse kasutamise võimalus ja andmete eelliitmine. See kasutab andmeskeemi andmeskeem, mis on kirjutatud Javascriptis SQL-i genereerimiseks ja andmebaasipäringu täitmiseks. Peame ainult näitama, kuidas andmeskeemis partitsioonifiltrit kasutada.

Loome uue Cube.js rakenduse. Kuna me juba kasutame AWS-i pinu, on loogiline kasutada juurutamiseks Lambdat. Kui kavatsete Cube.js-i taustaprogrammi majutada Herokus või Dockeris, saate genereerimiseks kasutada ekspressmalli. Dokumentatsioon kirjeldab teisi hostimismeetodid.

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

Keskkonnamuutujaid kasutatakse faili cube.js andmebaasi juurdepääsu konfigureerimiseks. Generaator loob .env-faili, milles saate määrata oma võtmed Athena.

Nüüd vajame andmeskeem, milles näitame täpselt, kuidas meie palke salvestatakse. Seal saate ka määrata, kuidas armatuurlaudade jaoks mõõdikuid arvutada.

Kataloogis schema, looge fail Logs.js. Siin on nginxi andmemudeli näide:

Mudeli kood

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`
    }
  }
});

Siin kasutame muutujat FILTER_PARAMSpartitsioonifiltriga SQL-päringu genereerimiseks.

Samuti määrame mõõdikud ja parameetrid, mida tahame armatuurlaual kuvada, ning määrame eelagregatsioonid. Cube.js loob täiendavaid tabeleid eelkoondandmetega ja värskendab neid saabumisel automaatselt. See mitte ainult ei kiirenda päringuid, vaid vähendab ka Athena kasutamise kulusid.

Lisame selle teabe andmeskeemi faili:

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`
      )
    }
  }
}

Täpsustame selles mudelis, et kõigi kasutatud mõõdikute andmed tuleb eelnevalt koondada ja kasutada kuude kaupa jaotamist. Koondamiseelne partitsioonid võib oluliselt kiirendada andmete kogumist ja uuendamist.

Nüüd saame armatuurlaua kokku panna!

Cube.js taustaprogramm pakub REST API ja klienditeekide komplekt populaarsete esiotsa raamistike jaoks. Armatuurlaua koostamiseks kasutame kliendi Reacti versiooni. Cube.js pakub ainult andmeid, seega vajame visualiseerimise teeki – see meeldib mulle uuesti kaardid, kuid võite kasutada mis tahes.

Cube.js server võtab päringu vastu JSON-vormingus, mis määrab vajalikud mõõdikud. Näiteks selleks, et arvutada, kui palju vigu Nginx päeva jooksul andis, peate saatma järgmise päringu:

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

Installime NPM-i kaudu Cube.js-kliendi ja Reacti komponenditeegi:

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

Toome sisse komponente cubejs и QueryRendererandmete allalaadimiseks ja armatuurlaua kogumiseks tehke järgmist.

Armatuurlaua kood

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>
        );
      }}
    />
  )
}

Armatuurlaua allikad on saadaval aadressil koodi liivakast.

Allikas: www.habr.com

Lisa kommentaar