ĐĐœĐ°Đ»ĐžŃ‚ĐžĐșа Đ»ĐŸĐłĐŸĐČ Nginx с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Amazon Athena Đž Cube.js

Vanligtvis anvÀnds kommersiella produkter eller fÀrdiga open-source-alternativ som Prometheus + Grafana för att övervaka och analysera Nginx:s prestanda. Detta Àr ett bra alternativ för övervakning eller realtidsanalys, men inte sÀrskilt praktiskt för historisk analys. PÄ varje populÀr resurs vÀxer datamÀngden frÄn Nginx-loggar snabbt, och för att analysera en stor mÀngd data Àr det logiskt att anvÀnda nÄgot mer specialiserat.

I den hÀr artikeln kommer jag att berÀtta hur man kan anvÀnda Athena för att analysera loggar, med Nginx som exempel, och visa hur man samlar dessa data för att skapa en analytisk dashboard med hjÀlp av det open-source ramverket cube.js. HÀr Àr hela lösningens arkitektur:

ĐĐœĐ°Đ»ĐžŃ‚ĐžĐșа Đ»ĐŸĐłĐŸĐČ Nginx с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Amazon Athena Đž Cube.js

TL:DR;
LÀnk till den fÀrdiga dashboarden.

För att samla in information anvĂ€nder vi Fluentd, för bearbetning — AWS Kinesis Data Firehose och AWS Glue, för lagring — AWS S3. Med denna koppling kan man lagra inte bara Nginx-loggar, utan Ă€ven andra hĂ€ndelser samt loggar frĂ„n andra tjĂ€nster. Du kan byta ut vissa delar mot motsvarande för din stack, till exempel kan du skriva loggar direkt till Kinesis frĂ„n Nginx, utan att gĂ„ via Fluentd, eller anvĂ€nda Logstash för detta.

Samla loggar frÄn Nginx

Som standard ser Nginx-loggar ut ungefÀr sÄ hÀr:

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

De kan parsas, men det Àr mycket enklare att justera Nginx-konfigurationen sÄ att loggarna ges i JSON-format:

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 för lagring

För att lagra loggar kommer vi att anvÀnda S3. Detta möjliggör lagring och analys av loggar pÄ ett stÀlle, eftersom Athena kan arbeta med data i S3 direkt. LÀngre fram i artikeln kommer jag att förklara hur man korrekt lagrar och bearbetar loggar, men först behöver vi en ren bucket i S3, dÀr inget annat kommer att lagras. Det Àr bra att i förvÀg tÀnka pÄ i vilken region du kommer att skapa bucketen, eftersom Athena inte Àr tillgÀnglig i alla regioner.

Skapa ett schema i Athena-konsolen

Vi kommer att skapa en tabell i Athena för loggar. Den behövs bĂ„de för inmatning och lĂ€sning, om du planerar att anvĂ€nda Kinesis Firehose. Öppna Athena-konsolen och skapa en tabell:

SQL för att skapa tabellen

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');

Skapa Kinesis Firehose Stream

Kinesis Firehose kommer att skriva data som mottas frĂ„n Nginx till S3 i det valda formatet, uppdelat i mappar enligt formatet ÅÅÅÅ/MM/DD/HH. Detta kommer att vara anvĂ€ndbart vid lĂ€sning av data. Du kan sjĂ€lvklart skriva direkt till S3 frĂ„n fluentd, men i sĂ„ fall mĂ„ste du skriva JSON, vilket Ă€r ineffektivt pĂ„ grund av stora filstorlekar. Dessutom Ă€r JSON det lĂ„ngsammaste dataformatet nĂ€r du anvĂ€nder PrestoDB eller Athena. SĂ„, öppna Kinesis Firehose-konsolen, klicka pĂ„ „Create delivery stream“, vĂ€lj „direct PUT“ i fĂ€ltet „delivery“:

ĐĐœĐ°Đ»ĐžŃ‚ĐžĐșа Đ»ĐŸĐłĐŸĐČ Nginx с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Amazon Athena Đž Cube.js

I nĂ€sta flik vĂ€ljer vi „Record format conversion“ — „Enabled“ och vĂ€ljer „Apache ORC“ som format för skrivning. Enligt forskning frĂ„n vissa Owen O’Malley, Ă€r detta det optimala formatet för PrestoDB och Athena. Som schema anger vi tabellen som vi skapade ovan. Observera att S3-platsen i Kinesis kan anges till valfri, bara schemat frĂ„n tabellen anvĂ€nds. Men om du anger en annan S3-plats kommer dessa poster inte att kunna lĂ€sas frĂ„n den hĂ€r tabellen.

ĐĐœĐ°Đ»ĐžŃ‚ĐžĐșа Đ»ĐŸĐłĐŸĐČ Nginx с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Amazon Athena Đž Cube.js

VÀlj S3 för lagring och den bucket som vi skapade tidigare. AWS Glue Crawler, som jag kommer att berÀtta mer om senare, kan inte arbeta med prefix i S3-bucket, sÄ det Àr viktigt att lÀmna den tom.

ĐĐœĐ°Đ»ĐžŃ‚ĐžĐșа Đ»ĐŸĐłĐŸĐČ Nginx с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Amazon Athena Đž Cube.js

Övriga alternativ kan Ă€ndras beroende pĂ„ din belastning, jag anvĂ€nder vanligtvis standardinstĂ€llningarna. Observera att S3-komprimering inte Ă€r tillgĂ€nglig, men ORC anvĂ€nder egen standardkomprimering.

Fluentd

Nu nÀr vi har stÀllt in lagring och mottagning av loggar mÄste vi konfigurera sÀndningen. Vi kommer att anvÀnda Fluentd, eftersom jag Àlskar Ruby, men du kan anvÀnda Logstash eller skicka loggar till Kinesis direkt. Fluentd-servern kan startas pÄ flera sÀtt, jag kommer att prata om Docker, eftersom det Àr enkelt och bekvÀmt.

För att börja, behöver vi en konfigurationsfil fluent.conf. Skapa den och lÀgg till kÀllan:

typ framÄt
port 24224
bind 0.0.0.0

Nu kan du starta Fluentd-servern. Om du behöver en mer avancerad konfiguration finns det Docker Hub en detaljerad guide, inklusive hur man bygger sin egen bild.

$ 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

Denna konfiguration anvÀnder vÀgen /fluentd/log för att cacha loggar innan de skickas. Det gÄr att klara sig utan detta, men dÄ kan all cachelagrad data gÄ förlorad vid en omstart. Du kan Àven anvÀnda valfri port, 24224 Àr den standardport som Fluentd anvÀnder.

Nu nÀr vi har Fluentd igÄng kan vi skicka Nginx-loggar dit. Vi kör vanligtvis Nginx i en Docker-container, och i det hÀr fallet har Docker en inbyggd loggdrivare för Fluentd:

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

Om du kör Nginx pÄ ett annat sÀtt kan du anvÀnda loggfiler; Fluentd har en file tail plugin.

LÄt oss lÀgga till loggarparsing i Fluent-konfigurationen, som vi har stÀllt in ovan:

@type parser
  key_name log
  emit_invalid_record_to_error false
  
    @type json

Och skicka loggar till Kinesis genom att anvÀnda kinesis firehose plugin:

@type kinesis_firehose
    region region
    delivery_stream_name 
    aws_key_id 
    aws_sec_key

Athena

Om du har konfigurerat allt korrekt bör du efter en stund (Kinesis registrerar mottagna data som standard var 10:e minut) se loggfiler i S3. I menyn "monitoring" för Kinesis Firehose kan du se hur mycket data som har skrivits till S3 samt fel. Glöm inte att ge skrivbehörighet till S3-bucketen för Kinesis-rollen. Om Kinesis inte kan parsa nÄgot lÀgger den fel i samma bucket.

Nu kan vi titta pÄ data i Athena. LÄt oss hitta de senaste frÄgorna som vi fick fel pÄ:

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

Genomsökning av alla poster vid varje frÄga

Nu har vÄra loggar bearbetats och lagrats i S3 i ORC-format, komprimerade och redo för analys. Kinesis Firehose har till och med sorterat dem i kataloger per timme. Men sÄ lÀnge tabellen inte Àr partitionerad kommer Athena att ladda data frÄn hela tiden varje gÄng, med nÄgra fÄ undantag. Detta Àr ett stort problem av tvÄ skÀl:

  • DatamĂ€ngden vĂ€xer stĂ€ndigt, vilket saktar ner frĂ„gorna;
  • Kostnaden för Athena baseras pĂ„ mĂ€ngden scannade data, med ett minimum pĂ„ 10 MB per frĂ„ga.

För att korrigera detta anvÀnder vi AWS Glue Crawler, som skannar data i S3 och skriver ner information om partitioner i Glue Metastore. Detta gör att vi kan anvÀnda partitionerna som filter vid frÄgor i Athena, och den kommer endast att skanna de kataloger som anges i frÄgan.

Konfigurerar Amazon Glue Crawler

Amazon Glue Crawler skannar all data i S3-facket och skapar tabeller med partitioner. Skapa en Glue Crawler frÄn AWS Glue-konsolen och lÀgg till facket dÀr du lagrar data. Du kan anvÀnda en crawler för flera fack, i sÄ fall kommer den att skapa tabeller i den angivna databasen med namn som stÀmmer överens med fackens namn. Om du planerar att anvÀnda dessa data kontinuerligt, kom ihÄg att stÀlla in ett schema för att köra Crawler enligt dina behov. Vi anvÀnder en crawler för alla tabeller som körs varje timme.

Partitionerade tabeller

Efter den första körningen av crawlern bör tabeller för varje skannat fack visas i databasen som anges i instĂ€llningarna. Öppna Athena-konsolen och leta efter tabellen med Nginx-loggar. LĂ„t oss försöka lĂ€sa nĂ„got:

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

Denna frÄga kommer att vÀlja alla poster som mottogs mellan 6 och 7 pÄ morgonen den 8 april 2019. Men hur mycket effektivare Àr detta Àn att bara lÀsa frÄn en icke-partitionerad tabell? LÄt oss ta reda pÄ det och vÀlja samma poster, filtrera dem efter tidsstÀmpel:

ĐĐœĐ°Đ»ĐžŃ‚ĐžĐșа Đ»ĐŸĐłĐŸĐČ Nginx с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Amazon Athena Đž Cube.js

3.59 sekunder och 244.34 megabyte data pÄ ett dataset som har en veckas loggar. LÄt oss prova partitioneringsfilter:

ĐĐœĐ°Đ»ĐžŃ‚ĐžĐșа Đ»ĐŸĐłĐŸĐČ Nginx с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Amazon Athena Đž Cube.js

Lite snabbare, men det viktigaste — endast 1.23 megabyte data! Det skulle vara mycket billigare om det inte vore för de minimala 10 megabyte per frĂ„ga i prissĂ€ttningen. Men det Ă€r Ă€ndĂ„ mycket bĂ€ttre, och pĂ„ stora dataset kommer skillnaden att vara mycket mer imponerande.

ĐĄĐŸĐ±ĐžŃ€Đ°Đ”ĐŒ ĐŽŃŃˆĐ±ĐŸŃ€ĐŽ с ĐżĐŸĐŒĐŸŃ‰ŃŒŃŽ Cube.js

För att skapa en instrumentpanel anvÀnder vi den analytiska ramverket Cube.js. Det har ganska mÄnga funktioner, men vi Àr intresserade av tvÄ: möjligheten att automatiskt anvÀnda filter baserat pÄ partitioner och pre-aggregationen av data. Det anvÀnder dataskema data schema, skriven i Javascript, för att generera SQL och utföra frÄgor mot databasen. Det som krÀvs av oss Àr bara att ange hur vi ska anvÀnda partitioneringsfilter i dataskema.

Vi kommer att skapa en ny Cube.js-applikation. Eftersom vi redan anvÀnder en AWS-stack Àr det logiskt att anvÀnda Lambda för distribution. Du kan anvÀnda express-mallen för att generera om du planerar att hyra ut Cube.js backend pÄ Heroku eller Docker. I dokumentationen beskrivs andra vÀrdar.

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

För att konfigurera Ätkomst till databasen i cube.js anvÀnds miljövariabler. Generatorn skapar en fil .env dÀr du kan ange dina nycklar för Athena.

Nu behöver vi en dataschema, dÀr vi anger hur vÄra loggar lagras. DÀr kan vi ocksÄ ange hur man berÀknar metrik för dashboards.

I katalogen schema, skapa en fil Logs.js. HÀr Àr ett exempel pÄ datamodell för nginx:

Kod för modellen

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

HÀr anvÀnder vi variabeln FILTER_PARAMS, för att generera en SQL-frÄga med filter för partitioner.

Vi specificerar ocksÄ metrik och parametrar som vi vill visa pÄ dashboarden och anger pre-aggregations. Cube.js kommer att skapa ytterligare tabeller med pre-aggregated data och automatiskt uppdatera data allteftersom de kommer in. Detta gör att vi kan snabba upp förfrÄgningar och minska kostnaden för att anvÀnda Athena.

Vi lÀgger till denna information i dataschemat:

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

I denna modell anger vi att data mÄste pre-aggregaras för alla anvÀnda metrik, och att vi ska anvÀnda partitionering per mÄnad. Partitionering av pre-aggregations kan betydligt pÄskynda insamlingen och uppdateringen av data.

Nu kan vi skapa en dashboard!

Backend Cube.js tillhandahĂ„ller REST API och ett set med klientbibliotek för populĂ€ra frontend-ramverk. Vi kommer att anvĂ€nda React-versionen av klienten för att bygga dashboarden. Cube.js tillhandahĂ„ller endast data, sĂ„ vi behöver ett bibliotek för visualiseringar — jag föredrar recharts, men du kan anvĂ€nda vilken som helst.

Servern Cube.js tar emot förfrÄgningar i JSON-formatet, dÀr de nödvÀndiga metrikarna anges. Till exempel, för att rÀkna hur mÄnga fel Nginx har returnerat per dag, mÄste du skicka en sÄdan förfrÄgan:

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

Vi installerar Cube.js-klienten och React-komponentbiblioteket via NPM:

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

Vi importerar komponenterna cubejs och QueryRenderer, för att hÀmta data, och vi bygger dashboarden:

Dashboard-koden

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 'Loading...';
        }

        return (
          
            
            
            
          
        );
      }}
    />
  )
}

KÀllkoden för dashboarden finns tillgÀnglig pÄ CodeSandbox.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster