Аналитика логов Nginx с помощью Amazon Athena и Cube.js

Tavaliselt Nginxi jälgimiseks ja analüüsimiseks kasutatakse kaubanduslikke tooteid või valmis open-source alternatiive, nagu Prometheus + Grafana. See on hea võimalus jälgimiseks või reaalaja analüüsiks, kuid mitte eriti mugav ajalooliseks analüüsiks. Iga populaarse ressursi puhul kasvab Nginxi logide maht kiiresti ja suure hulga andmete analüüsimiseks on mõistlik kasutada midagi spetsialiseeritumat.

Selles artiklis räägin, kuidas kasutada Athena logide analüüsimiseks, kasutades Nginxi näitena, ning näitan, kuidas neist andmetest kokku panna analüütiline armatuurlaud open-source raamistiku cube.js abil. Siin on lahenduse täpparchitecture:

Аналитика логов Nginx с помощью Amazon Athena и Cube.js

TL:DR;
Link valmis armatuurlaud.

Informatsiooni kogumiseks kasutame Fluentd, töötlemiseks — AWS Kinesis Data Firehose ja AWS Glue, salvestamiseks — AWS S3. Selle koosseisuga on võimalik salvestada mitte ainult Nginxi logisid, vaid ka teisi sündmusi ning ka teiste teenuste logisid. Saate mõned osad asendada sarnastega oma tech stack'ist, näiteks kirjutada logisid otse Kinesis'sse Nginxist, vahele jättes fluentd, või kasutada logstash'i.

Kogume Nginxi logisid

Vaikimisi näevad Nginxi logid välja enam-vähem nii:

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 analüüsida, kuid palju lihtsam on muuta Nginxi konfiguratsiooni, et logid väljastataks JSON formaadis:

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 salvestamiseks

Logide salvestamiseks kasutame S3. See võimaldab logisid ühes kohas salvestada ja analüüsida, kuna Athena saab otse S3-s andmetega töötada. Edasi artiklis räägin, kuidas logisid õigesti korraldada ja töödelda, kuid kõigepealt vajame puhast S3 ämbrit, kus midagi muud ei hoita. Tasub eelnevalt mõelda, millises regioonis te ämbrit loodud, kuna Athena ei ole kõikides piirkondades saadaval.

Loome skeemi Athena konsoolis

Loome Athena-s logide jaoks tabeli. See on vajalik nii kirjutamiseks kui lugemiseks, kui kavatsete kasutada Kinesis Firehose'i. Avage Athena konsool ja looge tabel:

SQL tabeli loomiseks

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://'
TBLPROPERTIES ('has_encrypted_data'='false');

Loome Kinesis Firehose Stream'i

Kinesis Firehose salvestab Nginxilt saadud andmed S3-s valitud formaadis, jagades need kaustadesse formaadis AASTA/KUUPÄEV/TUND. See on kasulik andmete lugemisel. Loomulikult võib otse S3-sse kirjutada fluentd-st, kuid sel juhul tuleb kirjutada JSON-i, mis ei ole efektiivne suurte failide tõttu. Lisaks sellele, kui kasutatakse PrestoDB või Athena't, on JSON kõige aeglasem andmevorm.

Аналитика логов Nginx с помощью Amazon Athena и Cube.js

Avame Kinesis Firehose konsooli, klõpsame 'Create delivery stream', valime 'direct PUT' 'delivery' väljal: Järgmises vahekaardis valime 'Record format conversion' — 'Enabled' ja valime 'Apache ORC' kirjutamisformaadiks. Teatud uuringute kohaseltOwen O’Malley

Аналитика логов Nginx с помощью Amazon Athena и Cube.js

, see on PrestoDB ja Athena jaoks optimaalne formaat. Skeemina näitame tabelit, mille me eelnevalt lõime. Pange tähele, et Kinesis's saab S3 asukoha määrata igasuguseks, tabelis kasutatakse vaid skeemi. Kuid kui määrate teistsuguse S3 asukoha, siis ei õnnestu neid kirjeid selle tabeli kaudu lugeda.

Аналитика логов Nginx с помощью Amazon Athena и Cube.js

Valime S3 salvestamiseks ja ämbri, mille me varem lõime. Aws Glue Crawler, millest räägin veidi hiljem, ei oska töötada S3 ämbri prefiksitega, seega on oluline see tühi hoida.

Fluentd

Ülejäänud valikuid saab muuta vastavalt teie koormusele, mina kasutan tavaliselt vaikeseadeid. Pange tähele, et S3 tihendamine ei ole saadaval, kuid ORC kasutab vaikimisi enda tihendust. FluentdNüüd, kui me oleme seadnud logide salvestamise ja hankimise, peame seadma edastamise. Kasutame

, sest mulle meeldib Ruby, kuid te võite kasutada Logstash'i või saata logisid otse Kinesis'sse. Fluentd serveri saab käivitada mitmel viisil, räägin docker'ist, kuna see on lihtne ja mugav.

type forward
port 24224
bind 0.0.0.0

Nüüd saab käivitada Fluentd serveri. Kui vajate keerukamat seadistust, Docker Hub on üksikasjalik juhend, sealhulgas kuidas luua oma pilti.

$ docker run 
  -d 
  -p 24224:24224 
  -p 24224:24224/udp 
  -v /data:/fluentd/log 
  -v :/fluentd/etc fluentd 
  -c /fluentd/etc/fluent.conf
  fluent/fluentd:stable

See seadistus kasutab teed /fluentd/log logide vahemällu salvestamiseks enne edastamist. Ilma selleta võib andmete kaotamine alates taaskäivitamisest juhtuda. Samuti võib kasutada mõnda muud porti, 24224 on Fluentd vaikimisi port.

Nüüd, kui meil on töötav Fluentd, saame edastada sinna Nginx logid. Me tavaliselt käivitame Nginx Docker konteineris ning sel juhul on Dockeril Fluentd jaoks natiivne logide draiver:

$ docker run 
--log-driver=fluentd 
--log-opt fluentd-address=
--log-opt tag="{{.Name}}" 
-v /some/content:/usr/share/nginx/html:ro 
-d 
nginx

Kui käitate Nginx muul viisil, saate kasutada logifailide, Fluentd-l on file tail plugin.

Lisame Fluenti seadistusse logide töötlemise, mis on seadistatud ülaltoodud:

@type parser
  key_name log
  emit_invalid_record_to_error false
  
    @type json

ja logide edastamine Kinesisesse, kasutades kinesis firehose plugin:

@type kinesis_firehose
    region region
    delivery_stream_name 
    aws_key_id 
    aws_sec_key

Athena

Kui olete kõik õigesti seadnud, siis mõne aja pärast (Kinesis salvestab saadud andmed iga 10 minuti tagant) peaksite nägema logifailide S3-s. Kinesis Firehose-i 'monitoring' menüüst näete, kui palju andmeid on S3-sse salvestatud ning ka vigu. Ärge unustage anda Kinesise rollile kirjutamisõigust S3 baketile. Kui Kinesis midagi ei suutnud töödelda, salvestab see vead samasse baketti.

Nüüd saame andmeid vaadata Athenas. Otsime uusi päringuid, millele oleme vead andnud:

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

Küsin kõiki kirjeid iga päringu jaoks

Nüüd on meie logid töödeldud ja salvestatud S3-s ORC-vormingus, komprimeeritud ja analüüsimiseks valmis. Kinesis Firehose on isegi jaganud need kaustadesse iga tunni kohta. Kuid seni, kuni tabel ei ole partitsioneeritud, laadib Athena igas päringus andmed kogu aja jooksul, eranditega. See on suur probleem kahel põhjusel:

  • Andmete maht kasvab pidevalt, aeglustades päringuid;
  • Athenale esitatav arve arvutatakse skaneeritud andmete mahu alusel, miinimumiga 10 MB iga päringu kohta.

Selle parandamiseks kasutame AWS Glue kraan, mis skaneerib andmeid S3-s ja salvestab teabe partitsioonide kohta Glue Metastore'i. See võimaldab meil partitsioone filtri kaudu päringutes kasutada, ja see skaneerib ainult katalooge, mis on päringus näidatud.

Seadistame Amazon Glue kraani

Amazon Glue kraan skaneerib kõik andmed S3 baketis ja loob tabelid partitsioonide kaupa. Looge Glue kraan AWS Glue konsoolist ja lisage baketis, kus andmeid hoiate. Saate kasutada ühte kraani mitme baketi jaoks, sel juhul loob see tabelid näidatud andmebaasis nimedega, mis vastavad bakettide nimedele. Kui kavatsete neid andmeid pidevalt kasutada, ärge unustage seadistada kraani käivitamise ajakava vastavalt oma vajadustele. Me kasutame ühte kraani, mis käivitub iga tunni tagant, kõigile tabelitele.

Partitsioneeritud tabelid

Pärast kraani esimest käivitamist peaksid seadistustes määratud andmebaasis ilmnema tabelid iga skaneeritud baketi jaoks. Avage Athena konsool ja leidke Nginx logide 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 saadud 8. aprillil 2019 kella 6-7 vahel. Kuid kui palju efektiivsem see on kui lihtsalt lugeda mitte-partitsioneeritud tabelist? Uurime ja valime samad kirjed, filtreerides neid ajatempli järgi:

Аналитика логов Nginx с помощью Amazon Athena и Cube.js

3.59 sekundit ja 244.34 megabaiti andmeid andmesetis, kus on vaid nädal logisid. Proovime partitsioonide põhjal filtrit:

Аналитика логов Nginx с помощью Amazon Athena и Cube.js

Veidi kiiremini, kuid kõige olulisem — ainult 1.23 megabaiti andmeid! See oleks palju odavam, kui mitte minimaalne 10 megabaiti iga päringu hinda. Kuid siiski palju parem, ja suuremate andmesettidega on erinevus palju muljetavaldavam.

Собираем дэшборд с помощью Cube.js

Däshbordi loomiseks kasutame analüütilist raamistiku Cube.js. Sellel on päris palju funktsioone, kuid meid huvitavad kaks: võimalus automaatselt kasutada filtreid partitsioonide põhjal ja andmete eelkokkuvõtmist. See kasutab andmeskeemi data schema, mis on kirjutatud JavaScriptis, et genereerida SQL ja teostada päring andmebaasile. Meilt nõutakse vaid partitsioonifiltri kasutamise määramist andmeskeemis.

Loome uus Cube.js rakendus. Kuna me juba kasutame AWS-stäkki, on mõistlik kasutada Lambda rakenduse juurutamiseks. Saate kasutada express-malli, kui plaanite Cube.js tagaplaati majutada Herokus või Dockeris. Dokumentatsioonis on kirjas teised majutamise viisid.

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

Cube.js-sse andmebaasi juurdepääsu seadistamiseks kasutatakse keskkonnamuutujaid. Generaator loob .env faili, kuhu saate sisestada oma võtmed Athena.

Nüüd vajame andmemudelit, kus määratleme, kuidas meie logisid salvestatakse. Seal on ka võimalik märkida, kuidas arvutada mõõdikud juhtpaneelide jaoks.

Kataloogis skeemaga, tehke uus fail Logs.js. Siin on näide andmemudelist nginx'i jaoks:

Mudeli kood

const partitionFilter = (from, to) => `
    date(from_iso8601_timestamp(${from})) = 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: `Jah`
        }],
        else: { label: `Ei` }
      }
    },

    createdAt: {
      sql: `from_unixtime(created_at)`,
      type: `time`
    }
  }
});

Siin kasutame muutujaid FILTER_PARAMS, et genereerida SQL päring koos partitsioonide filtriga.

Seame ka mõõdikud ja parameetrid, mida soovime juhtpaneelil kuvada, ning määratleme eel-agregeerimised. Cube.js loob täiendavad tabelid eel-agregeeritud andmete jaoks ja uuendab andmeid automaatsete tulude ajal. See mitte ainult ei kiirenda päringute täitmist, vaid vähendab ka Athena kasutamise kulusid.

Lisame selle teabe andmemudeli 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`
      )
    }
  }
}

Märgitame selles mudelis, et andmed tuleb eel-agregeerida kõigi kasutatavate mõõdikutega ja kasutada partitsioneerimist kuude kaupa. Eel-agregeerimise partitsioneerimine võib tõhusalt kiirendada andmete kogumist ja uuendamist.

Nüüd saame juhtpaneeli kokku panna!

Cube.js tagaplaan pakub REST API ja komplekti klienditeeke populaarsete front-end raamistike jaoks. Kasutame juhtpaneeli kokkupanekuks React-i kliendi versiooni. Cube.js pakub ainult andmeid, seega vajame visualiseerimiste teeki — mulle meeldib recharts, kuid võite kasutada ükskõik millist.

Cube.js server aktsepteerib päringut JSON formaadis, kus on määratletud vajalikud mõõdikud. Näiteks, et küsida, kui palju vigu Nginx igapäevaselt tagastas, tuleb saata järgmine päring:

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

Installime Cube.js kliendi ja React-komponendi teegi läbi NPM:

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

Imporime komponendid cubejs ja QueryRenderer, et andmeid laadida, ja koondame juhtpaneeli:

Juhtpaneeli 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 (
     {
        if (!resultSet) {
          return 'Laadimine...';
        }

        return (
          
            
            
            
          
        );
      }}
    />
  )
}

Juhtpaneeli lähtekood on saadaval CodeSandbox.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster