सामान्यतः, व्यावसायिक उत्पादने किंवा तयार मुक्त-स्रोत पर्याय, जसे की Prometheus + Grafana, Nginx च्या ऑपरेशनचे परीक्षण आणि विश्लेषण करण्यासाठी वापरले जातात. देखरेखीसाठी किंवा रिअल-टाइम विश्लेषणासाठी हा एक चांगला पर्याय आहे, परंतु ऐतिहासिक विश्लेषणासाठी फारसा सोयीस्कर नाही. कोणत्याही लोकप्रिय स्त्रोतावर, nginx लॉगमधील डेटाची मात्रा वेगाने वाढत आहे आणि मोठ्या प्रमाणात डेटाचे विश्लेषण करण्यासाठी, काहीतरी अधिक विशिष्ट वापरणे तर्कसंगत आहे.
आपण कसे वापरू शकता या लेखात मी तुम्हाला सांगेन
TL:DR;
माहिती गोळा करण्यासाठी आम्ही वापरतो
Nginx लॉग गोळा करत आहे
डीफॉल्टनुसार, Nginx लॉग यासारखे काहीतरी दिसतात:
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" "-"
त्यांचे विश्लेषण केले जाऊ शकते, परंतु Nginx कॉन्फिगरेशन दुरुस्त करणे खूप सोपे आहे जेणेकरून ते 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
नोंदी संग्रहित करण्यासाठी, आम्ही S3 वापरू. हे तुम्हाला एकाच ठिकाणी लॉग संग्रहित आणि विश्लेषण करण्यास अनुमती देते, कारण एथेना थेट S3 मधील डेटासह कार्य करू शकते. लेखात नंतर मी तुम्हाला लॉग योग्यरित्या कसे जोडावे आणि प्रक्रिया कशी करावी हे सांगेन, परंतु प्रथम आम्हाला S3 मध्ये एक स्वच्छ बादली आवश्यक आहे, ज्यामध्ये दुसरे काहीही संग्रहित केले जाणार नाही. तुम्ही तुमची बादली कोणत्या प्रदेशात तयार कराल हे आधीच विचारात घेण्यासारखे आहे, कारण अथेना सर्व प्रदेशांमध्ये उपलब्ध नाही.
एथेना कन्सोलमध्ये एक सर्किट तयार करणे
लॉगसाठी एथेनामध्ये एक टेबल तयार करूया. जर तुम्ही Kinesis Firehose वापरण्याची योजना आखत असाल तर लेखन आणि वाचन दोन्हीसाठी ते आवश्यक आहे. एथेना कन्सोल उघडा आणि एक टेबल तयार करा:
एसक्यूएल टेबल तयार करणे
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');
Kinesis Firehose प्रवाह तयार करणे
Kinesis Firehose Nginx वरून S3 वर प्राप्त केलेला डेटा YYYY/MM/DD/HH फॉरमॅटमधील डिरेक्टरीमध्ये विभागून, निवडलेल्या फॉरमॅटमध्ये लिहितो. डेटा वाचताना हे उपयोगी पडेल. तुम्ही अर्थातच, fluentd वरून थेट S3 वर लिहू शकता, परंतु या प्रकरणात तुम्हाला JSON लिहावे लागेल आणि फायलींच्या मोठ्या आकारामुळे हे अकार्यक्षम आहे. याव्यतिरिक्त, PrestoDB किंवा Athena वापरताना, JSON हे सर्वात धीमे डेटा स्वरूप आहे. तर Kinesis Firehose कन्सोल उघडा, "डिलिव्हरी स्ट्रीम तयार करा" वर क्लिक करा, "डिलिव्हरी" फील्डमध्ये "डायरेक्ट पुट" निवडा:
पुढील टॅबमध्ये, "रेकॉर्ड फॉरमॅट रूपांतरण" - "सक्षम" निवडा आणि रेकॉर्डिंग फॉरमॅट म्हणून "Apache ORC" निवडा. काही संशोधनानुसार
आम्ही स्टोरेजसाठी S3 निवडतो आणि आम्ही आधी तयार केलेली बादली. Aws ग्लू क्रॉलर, ज्याबद्दल मी थोड्या वेळाने बोलेन, S3 बकेटमध्ये उपसर्गांसह कार्य करू शकत नाही, म्हणून ते रिक्त सोडणे महत्वाचे आहे.
तुमच्या लोडनुसार उर्वरित पर्याय बदलले जाऊ शकतात; मी सहसा डीफॉल्ट वापरतो. लक्षात ठेवा की S3 कॉम्प्रेशन उपलब्ध नाही, परंतु ORC डिफॉल्टनुसार मूळ कॉम्प्रेशन वापरते.
अस्खलित
आता आम्ही लॉग संग्रहित करणे आणि प्राप्त करणे कॉन्फिगर केले आहे, आम्हाला पाठवणे कॉन्फिगर करणे आवश्यक आहे. आम्ही वापरू
प्रथम, आम्हाला fluent.conf कॉन्फिगरेशन फाइलची आवश्यकता आहे. ते तयार करा आणि स्त्रोत जोडा:
पोर्ट 24224
0.0.0.0 बांधणे
आता तुम्ही Fluentd सर्व्हर सुरू करू शकता. तुम्हाला अधिक प्रगत कॉन्फिगरेशन हवे असल्यास, येथे जा
$ 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
हे कॉन्फिगरेशन पथ वापरते /fluentd/log
पाठवण्यापूर्वी लॉग कॅशे करण्यासाठी. आपण याशिवाय करू शकता, परंतु नंतर आपण रीस्टार्ट केल्यावर, आपण बॅक-ब्रेकिंग श्रमाने कॅश केलेले सर्वकाही गमावू शकता. तुम्ही कोणतेही पोर्ट देखील वापरू शकता; 24224 हे डीफॉल्ट Fluentd पोर्ट आहे.
आता आमच्याकडे Fluentd चालू आहे, आम्ही तेथे Nginx लॉग पाठवू शकतो. आम्ही सामान्यत: डॉकर कंटेनरमध्ये Nginx चालवतो, अशा परिस्थितीत डॉकरकडे फ्लुएंटसाठी मूळ लॉगिंग ड्राइव्हर आहे:
$ 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
तुम्ही Nginx वेगळ्या पद्धतीने चालवल्यास, तुम्ही लॉग फाइल्स वापरू शकता, Fluentd आहे
वर कॉन्फिगर केलेले लॉग पार्सिंग फ्लुएंट कॉन्फिगरेशनमध्ये जोडूया:
<filter YOUR-NGINX-TAG.*>
@type parser
key_name log
emit_invalid_record_to_error false
<parse>
@type json
</parse>
</filter>
आणि वापरून Kinesis ला लॉग पाठवत आहे
<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>
अथेना
जर तुम्ही सर्वकाही योग्यरित्या कॉन्फिगर केले असेल, तर काही काळानंतर (डीफॉल्टनुसार, किनेसिस रेकॉर्ड प्रत्येक 10 मिनिटांनी एकदा डेटा प्राप्त करतो) तुम्हाला S3 मध्ये लॉग फाइल्स दिसल्या पाहिजेत. Kinesis Firehose च्या “मॉनिटरिंग” मेनूमध्ये आपण S3 मध्ये किती डेटा रेकॉर्ड केला आहे तसेच त्रुटी देखील पाहू शकता. Kinesis भूमिकेसाठी S3 बकेटमध्ये लेखन प्रवेश देण्यास विसरू नका. Kinesis एखाद्या गोष्टीचे विश्लेषण करू शकत नसल्यास, ते त्याच बकेटमध्ये त्रुटी जोडेल.
आता तुम्ही अथेनामधील डेटा पाहू शकता. चला नवीनतम विनंत्या शोधू ज्यासाठी आम्ही त्रुटी परत केल्या:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
प्रत्येक विनंतीसाठी सर्व रेकॉर्ड स्कॅन करत आहे
आता आमचे लॉग प्रोसेस केले गेले आहेत आणि ORC मध्ये S3 मध्ये संग्रहित केले गेले आहेत, संकुचित आणि विश्लेषणासाठी तयार आहेत. Kinesis Firehose अगदी प्रत्येक तासासाठी त्यांना निर्देशिकांमध्ये व्यवस्थापित केले. तथापि, जोपर्यंत टेबलचे विभाजन होत नाही, तोपर्यंत अथेना दुर्मिळ अपवादांसह, प्रत्येक विनंतीवर सर्व-वेळ डेटा लोड करेल. ही दोन कारणांसाठी मोठी समस्या आहे:
- डेटाची मात्रा सतत वाढत आहे, क्वेरी कमी करत आहे;
- एथेनाला स्कॅन केलेल्या डेटाच्या व्हॉल्यूमवर आधारित बिल केले जाते, प्रति विनंती किमान 10 MB.
याचे निराकरण करण्यासाठी, आम्ही AWS Glue Crawler वापरतो, जो S3 मधील डेटा क्रॉल करेल आणि Glue Metastore वर विभाजन माहिती लिहेल. हे आम्हाला एथेनाला क्वेरी करताना फिल्टर म्हणून विभाजने वापरण्याची परवानगी देईल आणि ते केवळ क्वेरीमध्ये निर्दिष्ट केलेल्या निर्देशिका स्कॅन करेल.
Amazon Glue Crawler सेट करत आहे
Amazon Glue Crawler S3 बकेटमधील सर्व डेटा स्कॅन करतो आणि विभाजनांसह टेबल तयार करतो. AWS Glue कन्सोल मधून एक Glue Crawler तयार करा आणि जिथे तुम्ही डेटा साठवता तिथे एक बादली जोडा. तुम्ही अनेक बकेट्ससाठी एक क्रॉलर वापरू शकता, अशा परिस्थितीत ते निर्दिष्ट डेटाबेसमध्ये बकेटच्या नावांशी जुळणार्या नावांसह टेबल तयार करेल. तुम्ही हा डेटा नियमितपणे वापरण्याची योजना करत असल्यास, तुमच्या गरजांनुसार क्रॉलरचे लॉन्च शेड्यूल कॉन्फिगर केल्याची खात्री करा. आम्ही सर्व टेबलसाठी एक क्रॉलर वापरतो, जे दर तासाला चालते.
विभाजित सारण्या
क्रॉलरच्या पहिल्या लाँचनंतर, प्रत्येक स्कॅन केलेल्या बकेटसाठी सारण्या सेटिंग्जमध्ये निर्दिष्ट केलेल्या डेटाबेसमध्ये दिसल्या पाहिजेत. एथेना कन्सोल उघडा आणि Nginx लॉगसह टेबल शोधा. चला काहीतरी वाचण्याचा प्रयत्न करूया:
SELECT * FROM "default"."part_demo_kinesis_bucket"
WHERE(
partition_0 = '2019' AND
partition_1 = '04' AND
partition_2 = '08' AND
partition_3 = '06'
);
ही क्वेरी 6 एप्रिल 7 रोजी सकाळी 8 ते सकाळी 2019 दरम्यान प्राप्त झालेले सर्व रेकॉर्ड निवडेल. पण विभाजन न केलेल्या टेबलवरून वाचण्यापेक्षा हे किती कार्यक्षम आहे? चला तेच रेकॉर्ड शोधू आणि निवडू, त्यांना टाइमस्टॅम्पनुसार फिल्टर करा:
एका आठवड्याच्या लॉगसह डेटासेटवर 3.59 सेकंद आणि 244.34 मेगाबाइट डेटा. चला विभाजनानुसार फिल्टर करून पहा:
थोडे वेगवान, परंतु सर्वात महत्त्वाचे म्हणजे - फक्त 1.23 मेगाबाइट डेटा! किंमतीमध्ये प्रति विनंती किमान 10 मेगाबाइट्स नसल्यास ते खूपच स्वस्त असेल. परंतु तरीही ते बरेच चांगले आहे आणि मोठ्या डेटासेटवर फरक अधिक प्रभावी असेल.
Cube.js वापरून डॅशबोर्ड तयार करणे
डॅशबोर्ड एकत्र करण्यासाठी, आम्ही Cube.js विश्लेषणात्मक फ्रेमवर्क वापरतो. यात बरीच कार्ये आहेत, परंतु आम्हाला दोन गोष्टींमध्ये स्वारस्य आहे: स्वयंचलितपणे विभाजन फिल्टर आणि डेटा पूर्व-एकत्रीकरण वापरण्याची क्षमता. हे डेटा स्कीमा वापरते
चला एक नवीन Cube.js ऍप्लिकेशन तयार करू. आम्ही आधीच AWS स्टॅक वापरत असल्याने, तैनातीसाठी Lambda वापरणे तर्कसंगत आहे. तुम्ही Heroku किंवा Docker मध्ये Cube.js बॅकएंड होस्ट करण्याची योजना करत असल्यास तुम्ही जनरेशनसाठी एक्सप्रेस टेम्प्लेट वापरू शकता. दस्तऐवजीकरण इतरांचे वर्णन करते
$ npm install -g cubejs-cli
$ cubejs create nginx-log-analytics -t serverless -d athena
cube.js मध्ये डेटाबेस प्रवेश कॉन्फिगर करण्यासाठी पर्यावरण व्हेरिएबल्सचा वापर केला जातो. जनरेटर एक .env फाइल तयार करेल ज्यामध्ये तुम्ही तुमच्या कळा निर्दिष्ट करू शकता
आता गरज आहे
निर्देशिकेत schema
, एक फाइल तयार करा Logs.js
. येथे nginx साठी डेटा मॉडेलचे उदाहरण आहे:
मॉडेल कोड
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`
}
}
});
येथे आपण व्हेरिएबल वापरत आहोत
आम्ही मॅट्रिक्स आणि पॅरामीटर्स देखील सेट करतो जे आम्ही डॅशबोर्डवर प्रदर्शित करू इच्छितो आणि पूर्व-एकत्रीकरण निर्दिष्ट करतो. Cube.js पूर्व-एकत्रित डेटासह अतिरिक्त सारण्या तयार करेल आणि डेटा येताच आपोआप अपडेट करेल. हे केवळ प्रश्नांना गती देत नाही तर एथेना वापरण्याची किंमत देखील कमी करते.
ही माहिती डेटा स्कीमा फाईलमध्ये जोडूया:
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`
)
}
}
}
आम्ही या मॉडेलमध्ये निर्दिष्ट करतो की वापरलेल्या सर्व मेट्रिक्ससाठी डेटा पूर्व-एकत्रित करणे आणि महिन्यानुसार विभाजन वापरणे आवश्यक आहे.
आता आम्ही डॅशबोर्ड एकत्र करू शकतो!
Cube.js बॅकएंड प्रदान करते
Cube.js सर्व्हर विनंती स्वीकारतो
{
"measures": ["Logs.errorCount"],
"timeDimensions": [
{
"dimension": "Logs.createdAt",
"dateRange": ["2019-01-01", "2019-01-07"],
"granularity": "day"
}
]
}
NPM द्वारे Cube.js क्लायंट आणि प्रतिक्रिया घटक लायब्ररी स्थापित करू:
$ npm i --save @cubejs-client/core @cubejs-client/react
आम्ही घटक आयात करतो cubejs
и QueryRenderer
डेटा डाउनलोड करण्यासाठी आणि डॅशबोर्ड गोळा करण्यासाठी:
डॅशबोर्ड कोड
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>
);
}}
/>
)
}
डॅशबोर्ड स्रोत येथे उपलब्ध आहेत
स्त्रोत: www.habr.com