Biasanya, produk komersial atau alternatif sumber terbuka siap pakai, seperti Prometheus + Grafana, digunakan untuk memantau dan menganalisis pengoperasian Nginx. Ini adalah pilihan yang baik untuk pemantauan atau analisis real-time, namun tidak terlalu nyaman untuk analisis historis. Pada sumber daya populer mana pun, volume data dari log nginx berkembang pesat, dan untuk menganalisis data dalam jumlah besar, masuk akal untuk menggunakan sesuatu yang lebih khusus.
Pada artikel ini saya akan memberi tahu Anda cara menggunakannya
PENJELASAN: DR;
Untuk mengumpulkan informasi yang kami gunakan
Mengumpulkan log Nginx
Secara default, log Nginx terlihat seperti ini:
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" "-"
Mereka dapat diuraikan, tetapi lebih mudah untuk memperbaiki konfigurasi Nginx sehingga menghasilkan log dalam 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 untuk penyimpanan
Untuk menyimpan log, kita akan menggunakan S3. Hal ini memungkinkan Anda menyimpan dan menganalisis log di satu tempat, karena Athena dapat bekerja dengan data di S3 secara langsung. Nanti di artikel saya akan memberi tahu Anda cara menambahkan dan memproses log dengan benar, tetapi pertama-tama kita memerlukan keranjang bersih di S3, di mana tidak ada lagi yang akan disimpan. Sebaiknya pertimbangkan terlebih dahulu di wilayah mana Anda akan membuat keranjang, karena Athena tidak tersedia di semua wilayah.
Membuat sirkuit di konsol Athena
Mari buat tabel di Athena untuk log. Ini diperlukan untuk menulis dan membaca jika Anda berencana menggunakan Kinesis Firehose. Buka konsol Athena dan buat tabel:
Pembuatan 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');
Membuat Aliran Kinesis Firehose
Kinesis Firehose akan menulis data yang diterima dari Nginx ke S3 dalam format yang dipilih, membaginya ke dalam direktori dalam format YYYY/MM/DD/HH. Ini akan berguna saat membaca data. Anda tentu saja dapat menulis langsung ke S3 dari fluentd, tetapi dalam kasus ini Anda harus menulis JSON, dan ini tidak efisien karena ukuran file yang besar. Selain itu, saat menggunakan PrestoDB atau Athena, JSON adalah format data paling lambat. Jadi buka konsol Kinesis Firehose, klik βBuat aliran pengirimanβ, pilih βPUT langsungβ di bidang βpengirimanβ:
Di tab berikutnya, pilih "Konversi format rekaman" - "Diaktifkan" dan pilih "Apache ORC" sebagai format rekaman. Menurut beberapa penelitian
Kami memilih S3 untuk penyimpanan dan bucket yang kami buat sebelumnya. Aws Glue Crawler, yang akan saya bicarakan nanti, tidak dapat bekerja dengan awalan di bucket S3, jadi penting untuk membiarkannya kosong.
Opsi lainnya dapat diubah tergantung pada beban Anda; Saya biasanya menggunakan opsi default. Perhatikan bahwa kompresi S3 tidak tersedia, tetapi ORC menggunakan kompresi asli secara default.
Lancar
Sekarang kita telah mengonfigurasi penyimpanan dan penerimaan log, kita perlu mengonfigurasi pengiriman. Kami akan menggunakan
Pertama, kita memerlukan file konfigurasi fluent.conf. Buat dan tambahkan sumber:
pelabuhan 24224
mengikat 0.0.0.0
Sekarang Anda dapat memulai server Fluentd. Jika Anda memerlukan konfigurasi lebih lanjut, kunjungi
$ 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 ini menggunakan jalur /fluentd/log
untuk menyimpan log dalam cache sebelum mengirim. Anda dapat melakukannya tanpa ini, tetapi ketika Anda memulai ulang, Anda dapat kehilangan semua yang di-cache karena kerja keras yang melelahkan. Anda juga dapat menggunakan port apa pun; 24224 adalah port Fluentd default.
Sekarang Fluentd sudah berjalan, kita dapat mengirim log Nginx ke sana. Kami biasanya menjalankan Nginx dalam container Docker, dalam hal ini Docker memiliki driver logging asli untuk 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
Jika Anda menjalankan Nginx secara berbeda, Anda dapat menggunakan file log, yang dimiliki Fluentd
Mari tambahkan penguraian log yang dikonfigurasi di atas ke konfigurasi Fluent:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
Dan mengirimkan log ke Kinesis menggunakan
<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
Jika Anda telah mengonfigurasi semuanya dengan benar, maka setelah beberapa saat (secara default, Kinesis Records menerima data setiap 10 menit sekali) Anda akan melihat file log di S3. Di menu βpemantauanβ Kinesis Firehose Anda dapat melihat berapa banyak data yang dicatat di S3, serta kesalahannya. Jangan lupa untuk memberikan akses tulis ke bucket S3 kepada peran Kinesis. Jika Kinesis tidak dapat menguraikan sesuatu, kesalahan tersebut akan ditambahkan ke keranjang yang sama.
Sekarang Anda dapat melihat data di Athena. Mari temukan permintaan terbaru yang kesalahannya kami kembalikan:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Memindai semua catatan untuk setiap permintaan
Sekarang log kami telah diproses dan disimpan di S3 di ORC, dikompresi dan siap untuk dianalisis. Kinesis Firehose bahkan mengaturnya ke dalam direktori untuk setiap jam. Namun, selama tabel tidak dipartisi, Athena akan memuat data sepanjang masa pada setiap permintaan, dengan pengecualian yang jarang terjadi. Ini adalah masalah besar karena dua alasan:
- Volume data terus bertambah, memperlambat permintaan;
- Athena ditagih berdasarkan volume data yang dipindai, dengan minimal 10 MB per permintaan.
Untuk memperbaikinya, kami menggunakan AWS Glue Crawler, yang akan merayapi data di S3 dan menulis informasi partisi ke Glue Metastore. Ini akan memungkinkan kita menggunakan partisi sebagai filter saat menanyakan Athena, dan itu hanya akan memindai direktori yang ditentukan dalam kueri.
Menyiapkan Perayap Amazon Glue
Amazon Glue Crawler memindai semua data di bucket S3 dan membuat tabel dengan partisi. Buat Glue Crawler dari konsol AWS Glue dan tambahkan bucket tempat Anda menyimpan data. Anda dapat menggunakan satu crawler untuk beberapa bucket, dalam hal ini crawler akan membuat tabel dalam database yang ditentukan dengan nama yang cocok dengan nama bucket. Jika Anda berencana untuk menggunakan data ini secara rutin, pastikan untuk mengonfigurasi jadwal peluncuran Crawler agar sesuai dengan kebutuhan Anda. Kami menggunakan satu Crawler untuk semua tabel, yang berjalan setiap jam.
Tabel yang dipartisi
Setelah peluncuran pertama crawler, tabel untuk setiap bucket yang dipindai akan muncul di database yang ditentukan dalam pengaturan. Buka konsol Athena dan temukan tabel dengan log Nginx. Mari kita coba membaca sesuatu:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
Kueri ini akan memilih semua catatan yang diterima antara jam 6 pagi dan 7 pagi pada tanggal 8 April 2019. Namun seberapa efisienkah hal ini dibandingkan hanya membaca dari tabel yang tidak dipartisi? Mari cari tahu dan pilih catatan yang sama, memfilternya berdasarkan stempel waktu:
3.59 detik dan 244.34 megabyte data pada kumpulan data dengan log hanya satu minggu. Mari kita coba filter berdasarkan partisi:
Sedikit lebih cepat, namun yang terpenting - hanya 1.23 megabita data! Akan jauh lebih murah jika bukan karena harga minimum 10 megabyte per permintaan. Namun hal ini masih jauh lebih baik, dan pada kumpulan data yang besar, perbedaannya akan jauh lebih mengesankan.
Membangun dasbor menggunakan Cube.js
Untuk merakit dasbor, kami menggunakan kerangka analitis Cube.js. Fungsinya cukup banyak, tetapi kami tertarik pada dua hal: kemampuan untuk menggunakan filter partisi secara otomatis dan pra-agregasi data. Ini menggunakan skema data
Mari buat aplikasi Cube.js baru. Karena kita sudah menggunakan tumpukan AWS, logis untuk menggunakan Lambda untuk penerapan. Anda dapat menggunakan templat ekspres untuk pembuatan jika Anda berencana menghosting backend Cube.js di Heroku atau Docker. Dokumentasi menjelaskan yang lain
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
Variabel lingkungan digunakan untuk mengonfigurasi akses database di cube.js. Generator akan membuat file .env di mana Anda dapat menentukan kuncinya
Sekarang kita membutuhkannya
Di direktori schema
, buat file Logs.js
. Berikut adalah contoh model data untuk nginx:
Kode 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`
}
}
});
Di sini kita menggunakan variabel
Kami juga mengatur metrik dan parameter yang ingin kami tampilkan di dasbor dan menentukan pra-agregasi. Cube.js akan membuat tabel tambahan dengan data yang telah dikumpulkan sebelumnya dan secara otomatis akan memperbarui data saat data tersebut tiba. Ini tidak hanya mempercepat kueri, tetapi juga mengurangi biaya penggunaan Athena.
Mari tambahkan informasi ini ke file skema 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`
)
}
}
}
Kami menetapkan dalam model ini bahwa perlu melakukan pra-agregat data untuk semua metrik yang digunakan, dan menggunakan partisi berdasarkan bulan.
Sekarang kita bisa merakit dasbornya!
Backend Cube.js menyediakan
Server Cube.js menerima permintaan masuk
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
Mari instal klien Cube.js dan pustaka komponen React melalui NPM:
$ npm i --save @cubejs-client/core @cubejs-client/react
Kami mengimpor komponen cubejs
ΠΈ QueryRenderer
untuk mengunduh data, dan mengumpulkan 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 dasbor tersedia di
Sumber: www.habr.com