Analisis log Nginx nganggo Amazon Athena sareng Cube.js

Biasana, produk komersil atanapi alternatif open-source anu siap, sapertos Prometheus + Grafana, dianggo pikeun ngawas sareng nganalisa operasi Nginx. Ieu mangrupikeun pilihan anu saé pikeun ngawaskeun atanapi analitik sacara real-time, tapi henteu cocog pisan pikeun analisa sajarah. Dina naon waé sumber populér, volume data tina log nginx ngembang pesat, sareng pikeun nganalisis jumlah data anu ageung, logis ngagunakeun anu langkung khusus.

Dina tulisan ieu kuring bakal nyarioskeun ka anjeun kumaha anjeun tiasa nganggo pundah pikeun nganalisis log, nyandak Nginx sabagé conto, sareng kuring bakal nunjukkeun kumaha ngumpul dasbor analitik tina data ieu nganggo kerangka open-source cube.js. Ieu arsitektur solusi lengkep:

Analisis log Nginx nganggo Amazon Athena sareng Cube.js

TL: DR;
Tumbu ka dasbor rengse.

Pikeun ngumpulkeun informasi kami nganggo Fluentd, pikeun ngolah- AWS Kinesis Data Firehose и Gelas Kolot, pikeun neundeun - AWS S3. Nganggo bungkusan ieu, anjeun tiasa nyimpen henteu ngan ukur log nginx, tapi ogé acara anu sanés, ogé log jasa anu sanés. Anjeun tiasa ngagentos sababaraha bagian sareng anu sami pikeun tumpukan anjeun, contona, anjeun tiasa nyerat log kana kinesis langsung tina nginx, ngalangkungan fluentd, atanapi nganggo logstash pikeun ieu.

Ngumpulkeun log Nginx

Sacara standar, log Nginx katingali sapertos kieu:

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

Éta tiasa diusir, tapi langkung gampang pikeun ngabenerkeun konfigurasi Nginx supados ngahasilkeun log di 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 pikeun neundeun

Pikeun nyimpen log, urang bakal nganggo S3. Ieu ngamungkinkeun anjeun pikeun nyimpen sareng nganalisis log dina hiji tempat, sabab Athena tiasa damel sareng data dina S3 langsung. Engké dina tulisan kuring bakal nyarioskeun ka anjeun kumaha cara nambihkeun sareng ngolah log anu leres, tapi mimitina urang peryogi ember bersih dina S3, dimana teu aya anu bakal disimpen. Éta patut mertimbangkeun sateuacanna di daérah mana anjeun badé nyiptakeun ember, sabab Athena henteu sayogi di sadaya daérah.

Nyiptakeun sirkuit dina konsol Athena

Hayu urang nyieun tabel di Athena pikeun log. Diperyogikeun pikeun nyerat sareng maca upami anjeun badé nganggo Kinesis Firehose. Buka konsol Athena sareng jieun tabel:

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

Nyiptakeun Kinesis Firehose Stream

Kinesis Firehose bakal nyerat data anu ditampi tina Nginx ka S3 dina format anu dipilih, ngabagi kana diréktori dina format YYYY/MM/DD/HH. Ieu bakal mangpaat nalika maca data. Anjeun tiasa, tangtosna, nyerat langsung ka S3 ti fluentd, tapi dina hal ieu anjeun kedah nyerat JSON, sareng ieu henteu cekap kusabab ukuran file anu ageung. Salaku tambahan, nalika nganggo PrestoDB atanapi Athena, JSON mangrupikeun format data anu paling laun. Janten buka konsol Kinesis Firehose, klik "Jieun aliran pangiriman", pilih "langsung PUT" dina widang "pangiriman":

Analisis log Nginx nganggo Amazon Athena sareng Cube.js

Dina tab salajengna, pilih "Rekam format konversi" - "Diaktipkeun" tur pilih "Apache ORC" salaku format rekaman. Numutkeun sababaraha panalungtikan Owen O'Malley, ieu mangrupikeun format optimal pikeun PrestoDB sareng Athena. Kami nganggo tabel anu kami ciptakeun di luhur salaku skéma. Punten dicatet yén anjeun tiasa netepkeun lokasi S3 dina kinesis; ngan ukur skéma anu dianggo tina tabél. Tapi lamun nangtukeun lokasi S3 béda, mangka anjeun moal bisa maca rékaman ieu tina tabel ieu.

Analisis log Nginx nganggo Amazon Athena sareng Cube.js

Urang milih S3 pikeun neundeun jeung ember nu urang dijieun saméméhna. Aws Glue Crawler, anu kuring bakal ngobrol engké, teu tiasa dianggo sareng awalan dina ember S3, janten penting pikeun ngantepkeun kosong.

Analisis log Nginx nganggo Amazon Athena sareng Cube.js

Pilihan sésana tiasa dirobih gumantung kana beban anjeun; Kuring biasana nganggo anu standar. Catet yén komprési S3 henteu sayogi, tapi ORC nganggo komprési asli sacara standar.

Fluentd

Ayeuna urang geus ngonpigurasi nyimpen jeung narima log, urang kudu ngonpigurasikeun ngirim. Urang bakal ngagunakeun Fluentd, sabab Abdi bogoh Ruby, tapi anjeun bisa make Logstash atawa ngirim log ka kinesis langsung. Server Fluentd tiasa diluncurkeun ku sababaraha cara, kuring bakal nyarioskeun ka anjeun ngeunaan docker sabab éta saderhana sareng gampang.

Kahiji, urang peryogi file konfigurasi fluent.conf. Jieun eta sarta tambahkeun sumber:

ngetik di payun
port 24224
meungkeut 0.0.0.0

Ayeuna anjeun tiasa ngamimitian server Fluentd. Upami anjeun peryogi konfigurasi anu langkung maju, angkat ka Hub Docker Aya pituduh lengkep, kaasup kumaha carana ngumpul gambar anjeun.

$ 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

Konfigurasi ieu ngagunakeun jalur /fluentd/log ka cache log saméméh ngirim. Anjeun tiasa ngalakukeun tanpa ieu, tapi lajeng mun anjeun balikan deui, anjeun bisa leungit sagalana sindangan jeung kuli deui-megatkeun. Anjeun ogé tiasa nganggo port mana waé; 24224 mangrupikeun port Fluentd standar.

Ayeuna urang parantos ngajalankeun Fluentd, urang tiasa ngirim log Nginx ka dinya. Kami biasana ngajalankeun Nginx dina wadah Docker, dina hal ieu Docker ngagaduhan supir logging asli pikeun 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

Upami anjeun ngajalankeun Nginx béda, anjeun tiasa nganggo file log, Fluentd gaduh file buntut plugin.

Hayu urang tambahkeun parsing log anu dikonpigurasi di luhur kana konfigurasi Fluent:

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

Jeung ngirim log ka Kinesis maké kinesis firehose plugin:

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

pundah

Upami anjeun parantos ngonpigurasi sadayana leres, teras saatos sababaraha waktos (sacara standar, rékaman Kinesis nampi data sakali unggal 10 menit) anjeun kedah ningali file log dina S3. Dina menu "monitoring" Kinesis Firehose anjeun tiasa ningali sabaraha data anu kacatet dina S3, kitu ogé kasalahan. Tong hilap masihan aksés nyerat kana ember S3 kana peran Kinesis. Lamun Kinesis teu bisa parse hal, éta bakal nambahan kasalahan ka LIPI sarua.

Ayeuna anjeun tiasa ningali data dina Athena. Hayu urang milarian pamenta anu pangahirna anu kami balikkeun kasalahan:

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

Nyeken sadaya rékaman pikeun tiap pamundut

Ayeuna log kami parantos diolah sareng disimpen dina S3 di ORC, dikomprés sareng siap pikeun dianalisis. Kinesis Firehose malah ngatur kana diréktori pikeun unggal jam. Tapi, salami tabel henteu dipisahkeun, Athena bakal ngamuat data sadaya waktos dina unggal pamundut, sareng pengecualian anu jarang. Ieu masalah badag pikeun dua alesan:

  • Volume data anu terus tumuwuh, slowing turun queries;
  • Athena ditagih dumasar kana volume data anu diseken, kalayan minimum 10 MB per pamundut.

Pikeun ngalereskeun ieu, kami nganggo AWS Glue Crawler, anu bakal ngorondang data dina S3 sareng nyerat inpormasi partisi kana Metastore Glue. Ieu bakal ngamungkinkeun urang ngagunakeun partisi salaku saringan nalika naroskeun Athena, sareng éta ngan ukur nyeken diréktori anu ditunjuk dina pamundut.

Nyetél Amazon Glue Crawler

Amazon Glue Crawler nyeken sadaya data dina ember S3 sareng nyiptakeun tabel sareng partisi. Jieun Crawler lem tina konsol AWS Glue tur tambahkeun ember dimana anjeun nyimpen data. Anjeun tiasa make hiji Mapay pikeun sababaraha ember, nu hal eta bakal nyieun tabel dina database dieusian kalawan ngaran nu cocog jeung ngaran ember. Upami anjeun ngarencanakeun ngagunakeun data ieu sacara rutin, pastikeun pikeun ngonpigurasikeun jadwal peluncuran Crawler pikeun nyocogkeun ka kabutuhan anjeun. Urang make hiji Crawler pikeun sakabéh tabel, nu ngalir unggal jam.

tabél partitioned

Saatos peluncuran munggaran Mapay, tabel pikeun tiap ember discan kedah muncul dina database dieusian dina setélan. Buka konsol Athena sareng panggihan tabel sareng log Nginx. Hayu urang coba maca hiji hal:

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

Paménta ieu bakal milih sadaya rékaman anu ditampi antara jam 6 énjing sareng 7 énjing dina 8 April 2019. Tapi sabaraha langkung éfisién ieu tibatan ngan ukur maca tina méja anu henteu dipisahkeun? Hayu urang manggihan tur pilih rékaman sarua, nyaring aranjeunna ku timestamp:

Analisis log Nginx nganggo Amazon Athena sareng Cube.js

3.59 detik sareng 244.34 megabytes data dina set data anu ngan ukur saminggu log. Hayu urang coba saringan ku partisi:

Analisis log Nginx nganggo Amazon Athena sareng Cube.js

Saeutik langkung gancang, tapi anu paling penting - ngan ukur 1.23 megabyte data! Eta bakal jadi laér leuwih murah lamun teu keur minimum 10 megabytes per pamundut di bedah. Tapi éta tetep langkung saé, sareng dina set data ageung bédana bakal langkung narik.

Ngawangun dasbor ngagunakeun Cube.js

Pikeun ngumpul dasbor, kami nganggo kerangka analitik Cube.js. Cai mibanda cukup loba fungsi, tapi urang museurkeun dua: kamampuhan pikeun otomatis ngagunakeun saringan partisi jeung data pre-aggregation. Éta ngagunakeun skéma data skéma data, ditulis dina Javascript pikeun ngahasilkeun SQL jeung ngaéksekusi query database. Urang ngan ukur kedah nunjukkeun kumaha ngagunakeun saringan partisi dina skéma data.

Hayu urang nyieun aplikasi Cube.js anyar. Kusabab urang parantos nganggo tumpukan AWS, éta logis ngagunakeun Lambda pikeun panyebaran. Anjeun tiasa make template express pikeun generasi lamun rencana pikeun host Cube.js backend di Heroku atanapi Docker. Dokuméntasi ngajelaskeun batur métode hosting.

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

variabel lingkungan dipaké pikeun ngonpigurasikeun aksés database di cube.js. generator bakal nyieun file .env nu bisa nangtukeun konci Anjeun pikeun pundah.

Ayeuna urang peryogi skéma data, dimana urang bakal nunjukkeun persis kumaha log urang disimpen. Aya anjeun ogé tiasa nangtukeun kumaha ngitung métrik pikeun dasbor.

Dina diréktori schema, jieun file Logs.js. Ieu conto modél data pikeun nginx:

Kodeu modél

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

Di dieu urang ngagunakeun variabel FILTER_PARAMSpikeun ngahasilkeun query SQL sareng saringan partisi.

Urang ogé nyetél métrik sareng parameter anu urang hoyong tunjukkeun dina dasbor sareng netepkeun pre-aggregations. Cube.js bakal nyieun tabel tambahan kalawan data pre-aggregated tur otomatis bakal ngamutahirkeun data sakumaha eta datang. Ieu teu ngan speeds up queries, tapi ogé ngurangan biaya pamakéan Athena.

Hayu urang tambahkeun inpormasi ieu kana file schema data:

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

Urang tangtukeun dina modél ieu yén éta téh perlu pre-agrégat data pikeun sakabéh metrics dipaké, sarta ngagunakeun partitioning dumasar bulan. Pra-aggregation partitioning nyata bisa nyepetkeun ngumpulkeun data jeung ngamutahirkeun.

Ayeuna urang tiasa ngumpul dasbor!

Cube.js backend nyadiakeun sesa API jeung susunan perpustakaan klien pikeun frameworks hareup-tungtung populér. Kami bakal nganggo versi React tina klien pikeun ngawangun dasbor. Cube.js ngan ukur nyayogikeun data, janten kami peryogi perpustakaan visualisasi - kuring resep recharts, tapi anjeun tiasa nganggo naon waé.

Server Cube.js nampi pamundut di format JSON, nu nangtukeun metrics diperlukeun. Contona, pikeun ngitung sabaraha kasalahan Nginx masihan sadinten, anjeun kedah ngirim pamundut ieu:

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

Hayu urang pasang klien Cube.js sareng perpustakaan komponén React via NPM:

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

Urang ngimpor komponén cubejs и QueryRendererpikeun ngundeur data, sarta ngumpulkeun dasbor:

Kode dasbor

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

sumber Dashboard sadia di sandbox kode.

sumber: www.habr.com

Tambahkeun komentar