Nginx log analytics utilizendu Amazon Athena è Cube.js

Di genere, i prudutti cummirciali o l'alternative open-source pronti, cum'è Prometheus + Grafana, sò usati per monitorà è analizà l'operazione di Nginx. Questa hè una bona opzione per u monitoraghju o l'analisi in tempu reale, ma micca assai cunvene per l'analisi storica. Nant'à ogni risorsa populari, u voluminu di dati da i logs nginx cresce rapidamente, è per analizà una grande quantità di dati, hè logicu di utilizà qualcosa di più specializatu.

In questu articulu vi dicu cumu pudete aduprà Athena per analizà i logs, pigliendu Nginx cum'è un esempiu, è vi mustrarà cumu assemble un dashboard analiticu da queste dati cù u framework open-source cube.js. Eccu l'architettura di suluzione cumpleta:

Nginx log analytics utilizendu Amazon Athena è Cube.js

TL: DR;
Link à u dashboard finitu.

Per cullà l'infurmazioni chì usemu fluentd, per trasfurmazioni - AWS Kinesis Data Firehose и Cola AWS, per u almacenamentu - AWS S3. Utilizendu stu bundle, pudete almacenà micca solu logs nginx, ma ancu altri avvenimenti, è ancu logs di altri servizii. Pudete rimpiazzà certi parti cù quelli simili per a vostra pila, per esempiu, pudete scrive logs à kinesis direttamente da nginx, bypassing fluentd, o utilizate logstash per questu.

Raccolta di logs Nginx

Per automaticamente, i logs di Nginx pareanu cusì:

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

Puderanu esse analizati, ma hè assai più faciule per correggerà a cunfigurazione Nginx in modu chì pruduce logs in 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 per u almacenamentu

Per almacenà logs, avemu aduprà S3. Stu vi permette di almacenà è analizà logs in un locu, postu chì Athena pò travaglià cù dati in S3 direttamente. In seguitu in l'articulu vi dicu cumu aghjunghje currettamente è processà i logs, ma prima avemu bisognu di un bucket pulito in S3, in quale nunda di più serà guardatu. Vale a pena cunsiderà in anticipu in quale regione creerete u vostru bucket, perchè Athena ùn hè micca dispunibule in tutte e regioni.

Crià un circuitu in a cunsola Athena

Creemu una tavola in Athena per i logs. Hè necessariu per scrive è leghje se pensa à aduprà Kinesis Firehose. Aprite a cunsola Athena è crea una tavola:

Creazione di tavule 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://<YOUR-S3-BUCKET>'
TBLPROPERTIES ('has_encrypted_data'='false');

Creazione di Kinesis Firehose Stream

Kinesis Firehose scriverà i dati ricevuti da Nginx à S3 in u formatu sceltu, dividendu in cartulari in u formatu AAAA/MM/DD/HH. Questu serà utile quandu leghje e dati. Pudete, sicuru, scrive direttamente à S3 da fluentd, ma in questu casu avete da scrive JSON, è questu hè inefficiente per via di a grandezza di i schedari. Inoltre, quandu si usa PrestoDB o Athena, JSON hè u formatu di dati più lento. Allora apre a cunsola Kinesis Firehose, cliccate "Crea un flussu di consegna", selezziunate "PUT direttu" in u campu "consegna":

Nginx log analytics utilizendu Amazon Athena è Cube.js

In a tabulazione dopu, selezziunate "Conversione di furmatu di registrazione" - "Enabled" è selezziunate "Apache ORC" cum'è furmatu di registrazione. Sicondu qualchi ricerca Owen O'Malley, questu hè u formatu ottimali per PrestoDB è Athena. Avemu aduprà a tavola chì avemu creatu sopra cum'è schema. Per piacè nutate chì pudete specificà ogni locu S3 in kinesis solu u schema hè utilizatu da a tavula. Ma s'è vo specificà un locu S3 differente, allura tu nun sarà capaci di leghje sti dischi da sta tavula.

Nginx log analytics utilizendu Amazon Athena è Cube.js

Selezziemu S3 per u almacenamiento è u bucket chì avemu creatu prima. Aws Glue Crawler, chì parleraghju un pocu dopu, ùn pò micca travaglià cù prefissi in un bucket S3, per quessa hè impurtante di lascià viotu.

Nginx log analytics utilizendu Amazon Athena è Cube.js

L'opzioni rimanenti ponu esse cambiate secondu a vostra carica, sò generalmente utilizatu quelli predeterminati. Nota chì a cumpressione S3 ùn hè micca dispunibule, ma ORC usa a cumpressione nativa per difettu.

fluentd

Avà chì avemu cunfiguratu l'almacenamiento è a ricezione di logs, avemu bisognu di cunfigurà l'invio. Avemu aduprà fluentd, Perchè mi piace Ruby, ma pudete aduprà Logstash o mandà logs à kinesis direttamente. U servitore Fluentd pò esse lanciatu in parechje manere, vi diceraghju di docker perchè hè simplice è cunvene.

Prima, avemu bisognu di u schedariu di cunfigurazione fluent.conf. Crea è aghjunghje a fonte:

activité avanti
portu 24224
ligà 0.0.0.0

Avà pudete inizià u servitore Fluentd. Sè avete bisognu di una cunfigurazione più avanzata, andate à Hub Docker Ci hè una guida dettagliata, cumprese cumu assemble a vostra imagina.

$ 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

Sta cunfigurazione usa a strada /fluentd/log per cache i logs prima di mandà. Pudete fà senza questu, ma dopu quandu riavviate, pudete perde tuttu in cache cù u travagliu back-breaking. Pudete ancu aduprà qualsiasi portu 24224 hè u portu Fluentd predeterminatu.

Avà chì avemu Fluentd in esecuzione, pudemu mandà logs Nginx quì. Di solitu eseguimu Nginx in un containeru Docker, in quale casu Docker hà un driver di logging nativu per 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

Se eseguite Nginx diversamente, pudete aduprà i schedarii di log, Fluentd hà file tail plugin.

Aghjunghjemu l'analisi di log cunfigurata sopra à a cunfigurazione Fluent:

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

È mandà logs à Kinesis usendu 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

Se avete cunfiguratu tuttu bè, dopu un pocu tempu (per difettu, Kinesis registra i dati ricevuti una volta ogni 10 minuti) duvete vede i schedarii di log in S3. In u menù di "surveglianza" di Kinesis Firehose pudete vede quantu dati sò registrati in S3, è ancu errori. Ùn vi scurdate di dà accessu à scrittura à u bucket S3 à u rolu Kinesis. Se Kinesis ùn pudia analizà qualcosa, aghjunghje l'errori à u stessu bucket.

Avà pudete vede i dati in Athena. Truvemu l'ultime dumande per quale avemu tornatu errori:

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

Scanning tutti i registri per ogni dumanda

Avà i nostri logs sò stati processati è almacenati in S3 in ORC, cumpressi è pronti per l'analisi. Kinesis Firehose li hà ancu urganizatu in cartulari per ogni ora. In ogni casu, finu à chì a tavula ùn hè micca partizionata, Athena caricarà dati di tutti i tempi nantu à ogni dumanda, cù rari eccezzioni. Questu hè un grande prublema per dui motivi:

  • U voluminu di dati hè in constantemente crescente, rallentendu e dumande;
  • Athena hè fattura basatu annantu à u voluminu di dati scansati, cù un minimu di 10 MB per dumanda.

Per riparà questu, usemu AWS Glue Crawler, chì rastrearà e dati in S3 è scrive l'infurmazioni di partizione à u Glue Metastore. Questu ci permetterà d'utilizà partizioni cum'è un filtru quandu si dumanda à Athena, è scanserà solu i cartulari specificati in a dumanda.

Configurazione di Amazon Glue Crawler

Amazon Glue Crawler scansa tutte e dati in u bucket S3 è crea tabelle cù partizioni. Crea un Glue Crawler da a cunsola AWS Glue è aghjunghje un bucket induve guardate i dati. Pudete utilizà un crawler per parechji buckets, in quale casu, creà tabelle in a basa di dati specifica cù nomi chì currispondenu à i nomi di i buckets. Se pensa à aduprà sta dati regularmente, assicuratevi di cunfigurà u calendariu di lanciamentu di Crawler per adattà à i vostri bisogni. Avemu aduprà un Crawler per tutte e tavule, chì corre ogni ora.

Tavulini spartuti

Dopu u primu lanciamentu di u crawler, i tabelli per ogni bucket scansatu devenu apparisce in a basa di dati specificata in i paràmetri. Apertura a cunsola Athena è truvate a tavola cù logs Nginx. Pruvemu di leghje qualcosa:

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

Questa dumanda selezziunà tutti i registri ricevuti trà 6 a.m. è 7 a.m. l'8 d'aprile 2019. Ma quantu più efficaci hè questu chì solu leghje da una tavula micca partizionata? Scupritemu è selezziunate i stessi registri, filtràli per timestamp:

Nginx log analytics utilizendu Amazon Athena è Cube.js

3.59 seconde è 244.34 megabytes di dati nantu à un dataset cù solu una settimana di logs. Pruvemu un filtru per partizione:

Nginx log analytics utilizendu Amazon Athena è Cube.js

Un pocu più veloce, ma u più impurtante - solu 1.23 megabyte di dati! Saria assai più prezzu s'ellu ùn hè micca per u minimu 10 megabytes per dumanda in u prezzu. Ma hè sempre assai megliu, è nantu à grande datasets a diferenza serà assai più impressiunanti.

Custruì un dashboard cù Cube.js

Per assemblà u dashboard, usemu u quadru analiticu Cube.js. Havi assai funzioni, ma ci interessanu dui: a capacità di utilizà automaticamente filtri di partizioni è pre-aggregazione di dati. Si usa schema di dati schema di dati, scrittu in Javascript per generà SQL è eseguisce una dumanda di basa di dati. Avemu solu bisognu di indicà cumu utilizà u filtru di partizione in u schema di dati.

Creemu una nova applicazione Cube.js. Siccomu avemu digià aduprendu a pila AWS, hè logicu aduprà Lambda per implementazione. Pudete utilizà u mudellu espressu per a generazione se pensa à ospitu u backend Cube.js in Heroku o Docker. A documentazione descrive l'altri metudi di hosting.

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

Variabili di l'ambiente sò usati per cunfigurà l'accessu à a basa di dati in cube.js. U generatore creà un schedariu .env in quale pudete specificà e vostre chjave per Athena.

Avà avemu bisognu schema di dati, in quale avemu da indicà esattamente cumu i nostri logs sò almacenati. Quì pudete ancu specificà cumu calculà e metriche per i dashboards.

In u cartulare schema, crea un schedariu Logs.js. Eccu un esempiu di mudellu di dati per nginx:

Codice di mudellu

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

Quì avemu aduprà a variàbbili FILTER_PARAMSper generà una dumanda SQL cù un filtru di partizione.

Avemu ancu stabilitu e metriche è i paràmetri chì vulemu vede nantu à u dashboard è specifichi pre-aggregazioni. Cube.js hà da creà tabelle supplementari cù dati pre-aggregati è aghjurnà automaticamente e dati cum'è ghjunghje. Questu ùn solu accelerà e dumande, ma riduce ancu u costu di l'usu di Athena.

Aghjunghjemu sta infurmazione à u schedariu di schema di dati:

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

Spicemu in questu mudellu chì hè necessariu di pre-aggregate dati per tutti i metrici utilizati, è aduprà a partizione per mese. Partitioning pre-aggregazione pò accelerà significativamente a raccolta di dati è l'aghjurnamentu.

Avà pudemu assemble u dashboard!

Cube.js backend furnisce REST API è un inseme di biblioteche cliente per i frameworks front-end populari. Useremu a versione React di u cliente per custruisce u dashboard. Cube.js furnisce solu dati, cusì avemu bisognu di una biblioteca di visualizazione - mi piace ricaricà, ma pudete aduprà qualsiasi.

U servitore Cube.js accetta a dumanda in Format JSON, chì specifica i metrici necessarii. Per esempiu, per calculà quanti errori Nginx hà datu di ghjornu, avete bisognu di mandà a seguente dumanda:

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

Stallà u cliente Cube.js è a biblioteca di cumpunenti React via NPM:

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

Importemu cumpunenti cubejs и QueryRendererper scaricà i dati, è raccoglie u dashboard:

Codice dashboard

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

I fonti di Dashboard sò dispunibili à codice sandbox.

Source: www.habr.com

Add a comment