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

Tavaliselt kasutatakse Nginx-i töötamise jälgimiseks ja analüüsimiseks kommertstooteid või valmis open-source alternatiive, nagu Prometheus + Grafana. See on hea variant jälgimiseks või reaalajas analüüsiks, kuid mitte kuigi mugav ajaloo analüüsimiseks. Igas populaarseimais allikas kasvab Nginx-i logide andmemaht kiiresti ja suure andmemahtu analüüsimiseks on mõistlik kasutada midagi spetsialiseeritumat.

Selles artiklis räägin, kuidas kasutada Athena logide analüüsimiseks, võttes näiteks Nginx-i, ja näitan, kuidas neist andmetest koguda analüütiline juhtpaneel, kasutades open-source raamistikku cube.js. Siin on lahenduse täisarkitektuur:

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

TL:DR;
Link valmis juhtpaneelile.

Teabe kogumiseks kasutame Fluentd, töötlemiseks — AWS Kinesis Data Firehose ja AWS Glue, salvestamiseks — AWS S3. Selle kombinatsiooniga on võimalik salvestada mitte ainult Nginx-i logisid, vaid ka muid sündmusi ning logisid teistest teenustest. Saate asendada mõned osad sarnastega oma tehnoloogiahiiu jaoks, näiteks saate logisid kirjutada otse Kinesis-i otse Nginx-ist mööda Fluentd-d või kasutada selleks Logstash-i.

Kogume Nginx-i logisid

Vaikimisi näevad Nginx-i logid välja umbes nii:

4/9/2019 12:58:17 PM 1.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, nagu Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"
4/9/2019 12:58:17 PM 1.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, nagu Gecko) Chrome/73.0.3683.86 Safari/537.36" "-"

Need saab parsida, kuid palju lihtsam on muuta Nginx-i konfiguratsiooni, et see annaks logisid 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 salvestada ja analüüsida ühes kohas, kuna Athena saab töötada S3 andmetega otse. Artikli järgnevates osades räägin, kuidas loge õigesti koguda ja töödelda, kuid esmalt on meil vajalik puhas S3 ämbers, kus midagi muud ei salvestata. On mõistlik eelnevalt mõelda, millisest piirkonnast te ämbrit loote, kuna Athena ei pruugi kõigis piirkondades saadaval olla.

Loome skeem Athena konsoolis

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

Tabeli loomise SQL

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'i voolu

Kinesis Firehose kirjutab Nginx'ilt saadud andmed S3-sse valitud formaadis, jagades need kataloogideks formaadis AAAA/KUU/PÄEV/TUND. See on kasulik andmete lugemisel. Loomulikult saab andmeid otse S3-sse saata fluentd'iga, kuid siis tuleb kirjutada JSON, mis pole efektiivne suurte failide tõttu. Lisaks on JSON PrestoDB või Athena kasutamisel aeglaseim andmevorming. Nii et avame Kinesis Firehose konsooli, vajutame "Create delivery stream", valime "direct PUT" väljale "delivery":

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

Järgmises vahekaardis valime "Record format conversion" — "Enabled" ja valime "Apache ORC" kirjutamise formaadiks. Vastavalt mõne uuringu Owen O’Malley, on see PrestoDB ja Athena jaoks optimaalne formaat. Skeemina määrame tabeli, mille me ülal loome. Pange tähele, et Kinesis's saab S3 asukohta määrata mistahes, tabelis kasutatakse ainult skeemi. Kuid kui määrate teise S3 asukoha, ei saa te selle tabeli sisse kandeid lugeda.

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

Valime S3 ladustamiseks ja baketi, mille me varem lõime. Aws Glue spider, millest räägin natuke hiljem, ei oska S3 baketi prefiksitega töötada, seega on oluline, et see jääks tühjaks.

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

Ü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 oma tihendust.

Fluentd

Nüüd, kui meil on logide ladustamine ja vastuvõtt seadistatud, tuleb seadistada edastamine. Kasutame Fluentd, kuna mulle meeldib Ruby, kuid võite kasutada ka Logstash'i või saata logisid otse kinesis'e. Fluentd serverit saab käivitada mitmel viisil, räägin dockerist, kuna see on lihtne ja mugav.

Alustuseks vajame fluent.conf konfiguratsioonifaili. Looge see ja lisage source:

type forward
port 24224
bind 0.0.0.0

Nüüd saab käivitada Fluentd serveri. Kui vajate keerukamat konfiguratsiooni, siis Docker Hub on olemas üksikasjalik juhend, sealhulgas, kuidas luua oma pilt.

$ 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 konfiguratsioon kasutab teed /fluentd/log logivääringute vahemällu salvestamiseks enne saatmist. Saate toime tulla ka ilma selleta, kuid siis võib taaskäivitamisel kaduda kõik vahemällu salvestatud väärtused. Samuti saab kasutada mis tahes porti, 24224 on Fluentd vaikimisi port.

Nüüd, kui meie Fluentd on käivitatud, saame Nginx'i logisid sinna saata. Me tavaliselt käivitame Nginx'i Docker-konteineris, ja sel juhul on Dockeril Fluentd jaoks kohandatud logi 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'i muul viisil, võite kasutada logifailide algoritmi, Fluentd-s on olemas faili tail plugin.

Lisame Fluenti konfiguratsiooni logide parsimise, nagu see on eelnevalt seadistatud:

@type parser
  key_name log
  emit_invalid_record_to_error false
  
    @type json

Ja logide saatmine Kinesis'e, kasutades kinesis firehose plugin:

@type kinesis_firehose
    region region
    delivery_stream_name 
    aws_key_id 
    aws_sec_key

Athena

Kui olete kõik õigesti seadistanud, siis mõne aja pärast (vaikimisi Kinesis salvestab saadud andmeid iga 10 minuti järel) peaksite nägema logifailide S3. Kinesis Firehose'i „monitoring” menüüs näete, kui palju andmeid on S3-s salvestatud, samuti vigu. Ärge unustage anda Kinesis'i rollile S3-bucketi kirjutamisõigus. Kui Kinesis ei suuda midagi tõlgendada, kogub ta vead samasse bucketi.

Nüüd saame vaadata andmeid Athena-s. Otsime värskeid päringuid, mille jaoks andsime vead:

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

Iga päringu jaoks skaneeritakse kõiki kandeid

Nüüd on meie logid töödeldud ja salvestatud S3-s ORC formaadis, tihendatud ja analüüsi jaoks valmis. Kinesis Firehose on isegi paigutanud need kaustadesse iga tunni kaupa. Siiski, seni kuni tabel ei ole partitsioneeritud, laadib Athena iga päringu jaoks andmed kogu aja jooksul, harvadel juhtudel. See on suured probleemid kahe põhjusel:

  • Andmehulgas pidevalt kasvab, aeglustades päringuid;
  • Athena hind arvutatakse skaneeritud andmete mahu alusel, minimaalne on 10 MB iga päringu kohta.

Selle parandamiseks kasutame AWS Glue kraanikut, mis skannib andmeid S3s ja salvestab teabe partitsioonide kohta Glue Metastore'i. See võimaldab meil kasutada partitsioone kui filtrit Athena päringutes, skannib see ainult neid katalooge, mis on päringus määratud.

Seadistame Amazon Glue kraaniku

Amazon Glue kraanik skannib kõik andmed S3 ämbris ja loob partitsioonidega tabelid. Looge Glue kraanik AWS Glue konsoolist ja lisage ämber, kus andmeid hoiate. Saate kasutada ühte kraanikut mitme ämbriga, sel juhul loob see tabelid määratud andmebaasis, mille nimed vastavad ämbrite nimedele. Kui kavatsete neid andmeid pidevalt kasutada, ärge unustage seadistada kraaniku käivitamise aega vastavalt oma vajadustele. Me kasutame ühte kraanikut kõigi tabelite jaoks, mis käivitub iga tunni tagant.

Partitsioneeritud tabelid

Pärast kraaniku esimest käivitamist peaks määratud andmebaasis, mille määrasite seadetesse, ilmuma tabelid iga skannitud ämbriga. Avage Athena konsool ja leidke Nginxi logide tabel. Proovime nüüd 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 saadi 8. aprillil 2019 kell 6–7 hommikul. Kuid kui tõhus see on võrreldes lihtsalt mitte-partitsioneeritud tabeli lugemisega? Uurime välja ja valime samad kirjed, filtreerides need ajatempli järgi:

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

3.59 sekundit ja 244.34 megabaiti andmeid andmekogumis, kus on vaid nädal logisid. Proovime nüüd partitsioonide filtrit:

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

Veidi kiirem, kuid kõige olulisem — vaid 1.23 megabaiti andmeid! See oleks palju odavam, kui mitte minimaalne 10 megabaiti päringu kohta hinnakujunduses. Kuid see on siiski palju parem, ja suurte andmekogumite puhul on vahe veelgi muljetavaldavam.

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

Däshboardi loomiseks kasutame analüütilist raami Cube.js. Sellel on üsna palju funktsioone, kuid meid huvitavad kaks: võimalus automaatselt kasutada filtreid partitsioonide järgi ja andmete eel-agregeerimine. See kasutab andmeskeemi data schema, mis on kirjutatud Javascriptis, et genereerida SQL ja teostada päring andmebaasile. Meilt nõutakse vaid, et näitaksime, kuidas kasutada partitsioonifiltrit andmeskeemis.

Loome uus rakendus Cube.js. Kuna me juba kasutame AWS-i tehnoloogiat, on mõistlik kasutada Lambda-deploy'd. Kui plaanite Cube.js tagapinda Herokus või Dockeris hostida, saate genereerimiseks kasutada express-malli. Muud majutamisviisid on dokumentatsioonis kirjeldatud. meetodid.

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

Cube.js-s andmebaasi juurde pääsemiseks kasutatakse keskkonnamuutujaid. Generaator loob faili .env, kuhu saate sisestada oma võtmed Athena.

Nüüd on meil vaja andmemudelit, kus määrame, kuidas meie logid on salvestatud. Samuti saab määrata, kuidas arvutada mõõdikud armatuurlaudade jaoks.

Kaustas schema, looge 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: `Yes`
        }],
        else: { label: `No` }
      }
    },

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

Siin kasutame muutujat FILTER_PARAMS, et genereerida SQL-päring parameetrite filterimisega.

Seame samuti mõõdikud ja parameetrid, mille soovime armatuurlaudadele kuvada, ning määrame etteaggregeerimised. Cube.js loob lisatajad koos etteaggregeeritud andmetega ja värskendab andmeid automaatselt nende saabudes. 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`
      )
    }
  }
}

Näitame selles mudelis, et peame etteaggregeerima andmed kõigi kasutatud mõõdikutega ja kasutama kuude kaupa partitsioneerimist. Enneaggregeerimise partitsioneerimine võib oluliselt kiirendada andmete kogumist ja värskendamist.

Nüüd saame koostada dashauboard'i!

Cube.js-i backend pakub REST API ja komplekti klienditeekide jaoks populaarsetes frontend-raamistikedes. Me kasutame kliendi React versiooni dashauboard'i koostamiseks. Cube.js pakub vaid andmeid, seega on meil vaja visualiseerimistööriistu — mulle meeldib recharts, kuid võid kasutada ükskõik millist.

Cube.js server võtab vastu päringu JSON formaadis, kus on määratud vajalikud mõõdikud. Näiteks, et arvutada, kui palju vigu Nginx iga päev väljastas, tuleb saata järgmine päring:

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

Paigaldame Cube.js kliendi ja React-komponendi raamatukogu läbi NPM:

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

Impordime komponendid cubejs ja QueryRenderer, et andmeid laadida, ja koostame dashauboard'i:

Dashauboard'i 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 (
          
            
            
            
          
        );
      }}
    />
  )
}

Dashauboard'i lähtekood on saadaval CodeSandbox.

Allikas: habr.com

Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne hostimine veebilehtede jaoks DDoS-i kaitsega, VPS VDS serverid | ProHoster