Nginx Log Analytics bi Amazon Athena û Cube.js re

Bi gelemperî, hilberên bazirganî an alternatîfên çavkaniya vekirî ya amade, wekî Prometheus + Grafana, ji bo şopandin û analîzkirina xebata Nginx têne bikar anîn. Ev vebijarkek baş e ji bo şopandin an analîzên rast-dem, lê ji bo analîzên dîrokî ne pir hêsan e. Li ser her çavkaniyek populer, qebareya daneyên ji têketinên nginx bi lez mezin dibe, û ji bo analîzkirina hejmareke mezin a daneyan, mentiqî ye ku meriv tiştek pisportir bikar bîne.

Di vê gotarê de ez ê ji we re vebêjim ka hûn çawa dikarin bikar bînin Atena ji bo analîzkirina têketinê, Nginx-ê wekî mînak bigire, û ez ê nîşan bidim ka meriv çawa bi karanîna çarçoweya cube.js-çavkaniya vekirî ji van daneyan tabloyek analîtîk berhev dike. Li vir mîmariya çareseriyê ya bêkêmasî ye:

Nginx Log Analytics bi Amazon Athena û Cube.js re

TL:DR;
Girêdana dashboarda qediyayî.

Ji bo berhevkirina agahdariyê em bikar tînin herikandinji bo pêvajoyê - AWS Kinesis Data Firehose и AWS Glue, ji bo hilanînê - AWS S3. Bi karanîna vê pakêtê, hûn dikarin ne tenê têketinên nginx, lê di heman demê de bûyerên din, û hem jî têketinên karûbarên din hilînin. Hûn dikarin hin beşan ji bo stûyê xwe bi yên mîna hev biguhezînin, mînakî, hûn dikarin têketinên kinesisê rasterast ji nginx binivîsin, fluentd derbas bikin, an ji bo vê yekê logstash bikar bînin.

Komkirina têketinên Nginx

Bi xwerû, têketinên Nginx bi vî rengî xuya dikin:

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

Ew dikarin bêne pars kirin, lê pir hêsantir e ku meriv veavakirina Nginx rast bike da ku ew di JSON de têketin çêbike:

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 ji bo hilanînê

Ji bo tomarkirina têketin, em ê S3 bikar bînin. Ev dihêle hûn têketin li yek cîhek hilînin û analîz bikin, ji ber ku Athena dikare rasterast bi daneyên S3 re bixebite. Dûv re di gotarê de ez ê ji we re vebêjim ka meriv çawa têketinên rast lê zêde bike û pêvajoyê bike, lê pêşî ji me re kelek paqij di S3 de hewce ye, ku tê de tiştek din neyê hilanîn. Hêja ye ku meriv berê xwe bide ber çavan ku hûn ê li kîjan herêmê kepçeya xwe biafirînin, ji ber ku Athena li hemî deveran peyda nabe.

Di konsolê Athena de çerxek çêbikin

Ka em li Athena ji bo têketin tabloyek çêbikin. Heke hûn plan dikin ku Kinesis Firehose bikar bînin hem ji bo nivîsandinê hem jî ji bo xwendinê hewce ye. Konsolê Athena vekin û tabloyek çêbikin:

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

Afirandina Kinesis Firehose Stream

Kinesis Firehose dê daneyên ku ji Nginx-ê ji S3-ê hatî wergirtin di forma hilbijartî de binivîsîne, wê li pelrêçan di forma YYYY/MM/DD/HH de dabeş bike. Ev dê di dema xwendina daneyan de bi kêr were. Bê guman, hûn dikarin rasterast li S3-ê ji fluentd-ê binivîsin, lê di vê rewşê de hûn neçar in ku JSON binivîsin, û ev ji ber mezinahiya pelan bêbandor e. Wekî din, dema ku PrestoDB an Athena bikar tînin, JSON formata daneya herî hêdî ye. Ji ber vê yekê konsolê Kinesis Firehose vekin, bikirtînin "Çaxa radestkirinê biafirînin", di qada "radestkirinê" de "PUT rasterast" hilbijêrin:

Nginx Log Analytics bi Amazon Athena û Cube.js re

Di tabloya paşîn de, "Veguheztina formata tomarkirinê" - "Enabled" hilbijêrin û "Apache ORC" wekî forma tomarkirinê hilbijêrin. Li gorî hin lêkolînan Owen O'Malley, ev ji bo PrestoDB û Athena formata çêtirîn e. Em tabloya ku me li jor çêkiriye wekî şema bikar tînin. Ji kerema xwe not bikin ku hûn dikarin her cîhek S3 di kinesisê de diyar bikin; tenê şema ji tabloyê tê bikar anîn. Lê heke hûn cîhek cûda ya S3 diyar bikin, wê hingê hûn ê nikaribin van tomaran ji vê tabloyê bixwînin.

Nginx Log Analytics bi Amazon Athena û Cube.js re

Em ji bo hilanînê S3 û kepçeya ku me berê afirandiye hilbijêrin. Aws Glue Crawler, ya ku ez ê piçekî paşê qala wê bikim, nikare bi pêşgiran di kelek S3 de bixebite, ji ber vê yekê girîng e ku ew vala bihêlin.

Nginx Log Analytics bi Amazon Athena û Cube.js re

Vebijarkên mayî dikarin li gorî barkirina we werin guheztin; Ez bi gelemperî yên xwerû bikar tînim. Bala xwe bidinê ku kompresyona S3 ne berdest e, lê ORC ji hêla xwerû ve berhevkirina xwemalî bikar tîne.

herikandin

Naha ku me tomarkirin û wergirtina têketin mîheng kiriye, pêdivî ye ku em şandinê mîheng bikin. Em ê bikar bînin herikandin, ji ber ku ez ji Ruby hez dikim, lê hûn dikarin Logstash bikar bînin an rasterast têketin bişînin kinesis. Servera Fluentd dikare bi çend awayan were destpêkirin, ez ê ji we re li ser docker bibêjim ji ber ku ew sade û hêsan e.

Pêşî, pêdiviya me bi pelê veavakirina fluent.conf heye. Wê biafirînin û çavkaniyê lê zêde bikin:

awa pêşve
Port 24224
girêdan 0.0.0.0

Naha hûn dikarin servera Fluentd dest pê bikin. Ger hewceyê vesazkirinek pêşkeftî be, biçin Navenda docker Rêbernameyek berfireh heye, di nav de meriv çawa wêneyê xwe berhev dike.

$ 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

Ev veavakirin rê bi kar tîne /fluentd/log berî şandina têketinên cache. Hûn dikarin bêyî vê yekê bikin, lê dûv re gava ku hûn ji nû ve dest pê bikin, hûn dikarin her tiştê ku bi keda paşverû hatî girtin winda bikin. Her weha hûn dikarin her portê bikar bînin; 24224 porta Fluentd ya xwerû ye.

Naha ku me Fluentd dimeşîne, em dikarin têketinên Nginx li wir bişînin. Em bi gelemperî Nginx-ê di konteynirek Docker de dimeşînin, di vê rewşê de Docker ji bo Fluentd ajokarek têketinê ya xwecihî heye:

$ 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

Ger hûn Nginx-ê cûda dimeşînin, hûn dikarin pelên têketinê bikar bînin, Fluentd heye pêveka dûvika pelê.

Ka em parsinga têketinê ya ku li jor hatî mîheng kirin li veavakirina Fluent zêde bikin:

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

Û şandina têketinên Kinesis bi kar tînin pêveka 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>

Atena

Ger we her tişt rast mîheng kiriye, wê hingê piştî demekê (bi xwerû, Kinesis her 10 hûrdem carekê daneyan distîne) divê hûn pelên têketinê li S3 bibînin. Di menuya "şopandinê" ya Kinesis Firehose de hûn dikarin bibînin ka çiqas daneya di S3 de têne tomar kirin, û hem jî xeletiyan. Ji bîr nekin ku hûn gihandina nivîsandinê bidin berika S3 rola Kinesis. Ger Kinesis nekari tiştek parsek bike, ew ê xeletiyan li heman kelê zêde bike.

Niha hûn dikarin daneyên li Athena bibînin. Ka em daxwazên herî paşîn ên ku me xeletî vedigerin bibînin:

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

Ji bo her daxwazê ​​​​hemû tomar dişoxilînin

Naha têketinên me di S3-ê de di ORC de hatine pêvajo kirin û hilanîn, hatine berhev kirin û ji bo analîzê amade ne. Kinesis Firehose tewra ji bo her demjimêrê wan di pelrêçan de organîze kir. Lêbelê, heya ku tablo neyê dabeş kirin, Athena dê li ser her daxwazê, bi îstîsnayên hindik, daneyên hemî-demê bar bike. Ji ber du sedeman ev pirsgirêkek mezin e:

  • Hêjmara daneyan her ku diçe mezin dibe, pirsan hêdî dike;
  • Athena li ser bingeha qebareya daneya ku hatî şopandin, bi her daxwazek herî kêm 10 MB tê hesab kirin.

Ji bo rastkirina vê yekê, em AWS Glue Crawler bikar tînin, ku dê daneya di S3 de bişopîne û agahdariya dabeşkirinê li Glue Metastore binivîse. Ev ê bihêle ku em dema ku pirsa Athena-yê dipirsin, dabeşan wekî parzûnek bikar bînin, û ew ê tenê pelrêçiyên ku di pirsnameyê de hatine destnîşan kirin bigerin.

Sazkirina Amazon Glue Crawler

Amazon Glue Crawler hemî daneyên di kepçeya S3 de dişoxilîne û bi dabeşan tabloyan diafirîne. Ji konsolê AWS Glue Crawlerek Glue biafirînin û kelekek lê zêde bikin ku hûn daneyan hilînin. Hûn dikarin ji bo çend kepçeyan yek crawler bikar bînin, di vê rewşê de ew ê di databasa diyarkirî de tabloyan bi navên ku navên kepçeyan li hev dikin biafirîne. Ger hûn plan dikin ku van daneyan bi rêkûpêk bikar bînin, bê guman nexşeya destpêkirina Crawler-ê li gorî hewcedariyên we mîheng bikin. Em ji bo hemî tabloyan yek Crawler bikar tînin, ku her demjimêr dimeşe.

Maseyên dabeşkirî

Piştî destpêkirina yekem a crawler, divê tabloyên ji bo her kelek skankirî di databasa ku di mîhengan de hatî destnîşan kirin xuya bibin. Konsolê Athena vekin û tabloya bi têketinên Nginx re bibînin. Ka em hewl bidin ku tiştek bixwînin:

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

Ev pirs dê hemî tomarên ku di navbera 6-ê sibehê û 7-ê sibehê de 8ê Avrêl, 2019-an de hatine wergirtin hilbijêrin. Lê ev ji xwendina ji tabloyek ne-parvekirî çiqas bikêrtir e? Ka em heman tomaran bibînin û hilbijêrin, wan li gorî demjimêrê fîlter bikin:

Nginx Log Analytics bi Amazon Athena û Cube.js re

3.59 saniye û 244.34 megabytes daneya li ser daneyek bi tenê hefteyek têketin. Ka em parzûnek bi dabeşkirinê biceribînin:

Nginx Log Analytics bi Amazon Athena û Cube.js re

Piçek zûtir, lê ya herî girîng - tenê 1.23 megabytes daneyê! Ger di nirxê de her daxwazek herî kêm 10 megabayt nebe dê pir erzantir be. Lê ew hîn jî pir çêtir e, û li ser daneyên mezin cûdahî dê pir bi heybettir be.

Avakirina dashboardek bi karanîna Cube.js

Ji bo komkirina dashboardê, em çarçoveya analîtîk Cube.js bikar tînin. Gelek fonksiyonên wê hene, lê em bi du kesan re eleqedar dibin: şiyana ku bixweber bikar anîna fîlterên dabeşkirinê û berhevkirina daneyan. Ew şema daneyê bikar tîne şemaya daneyê, di Javascript de hatî nivîsandin da ku SQL çêbike û pirsek databasê pêk bîne. Em tenê hewce ne ku destnîşan bikin ka meriv çawa parzûna dabeşkirinê di şemaya daneyê de bikar tîne.

Werin em serîlêdanek nû ya Cube.js biafirînin. Ji ber ku em berê steka AWS bikar tînin, mentiqî ye ku meriv Lambda ji bo bicîhkirinê bikar bîne. Heke hûn plan dikin ku paşîna Cube.js-ê li Heroku an Docker-ê mêvandar bikin, hûn dikarin ji bo nifşê şablonê ekspres bikar bînin. Belgekirin yên din diyar dike rêbazên mêvandariyê.

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

Guherbarên jîngehê ji bo mîhengkirina gihîştina databasê di cube.js de têne bikar anîn. Dê jenerator pelek .env biafirîne ku tê de hûn dikarin mifteyên xwe ji bo diyar bikin Atena.

Niha em hewce ne şemaya daneyê, ku tê de em ê tam destnîşan bikin ka têketinên me çawa têne hilanîn. Li wir jî hûn dikarin diyar bikin ka meriv çawa metrîkên ji bo dashboardan hesab dike.

Di pelrêça schema, pelek çêbikin Logs.js. Li vir mînakek modela daneyê ji bo nginx heye:

Koda modelê

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

Li vir em guhêrbar bikar tînin FILTER_PARAMSji bo afirandina pirsek SQL bi parzûnek dabeşkirinê.

Me her weha metrîk û pîvanên ku em dixwazin li ser tabloyê nîşan bidin destnîşan dikin û berhevokên pêşîn diyar dikin. Cube.js dê bi daneyên pêş-hevkirî tabloyên zêde biafirîne û gava ku ew digihîje dê bixweber daneyan nûve bike. Ev ne tenê pirsan bilez dike, lê di heman demê de lêçûna karanîna Athena jî kêm dike.

Ka em vê agahiyê li pelê şema daneyê zêde bikin:

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

Em di vê modelê de diyar dikin ku pêdivî ye ku ji bo hemî metrîkên ku têne bikar anîn daneyan pêş-kom bikin, û dabeşkirina mehane bikar bînin. Dabeşkirina pêş-kombûnê dikare berhevkirin û nûvekirina daneyan bi girîngî bilez bike.

Naha em dikarin dashboardê bicivînin!

Cube.js paşperdeya peyda dike REST API û komek pirtûkxaneyên xerîdar ji bo çarçoveyên pêş-end-end ên populer. Em ê guhertoya React ya xerîdar bikar bînin da ku dashboardê ava bikin. Cube.js tenê daneyan peyda dike, ji ber vê yekê em ê hewceyê pirtûkxaneyek dîtbarî bikin - ez jê hez dikim recharts, lê hûn dikarin her yekê bikar bînin.

Pêşkêşkara Cube.js daxwazê ​​qebûl dike formata JSON, ku pîvanên pêdivî diyar dike. Mînakî, ji bo hesabkirina çend xeletiyên ku Nginx bi roj dane, hûn hewce ne ku daxwaziya jêrîn bişînin:

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

Werin em muwekîlê Cube.js û pirtûkxaneya pêkhateya React bi navgîniya NPM-ê saz bikin:

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

Em pêkhateyan îthal dikin cubejs и QueryRendererdaxistina daneyan, û berhevkirina dashboardê:

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

Çavkaniyên dashboardê li ser hene koda sandbox.

Source: www.habr.com

Add a comment