Әдетте, Nginx жұмысын бақылау және талдау үшін Prometheus + Grafana сияқты коммерциялық өнімдер немесе дайын ашық бастапқы баламалар пайдаланылады. Бұл мониторинг немесе нақты уақыттағы талдау үшін жақсы нұсқа, бірақ тарихи талдау үшін өте ыңғайлы емес. Кез келген танымал ресурста 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 пайдаланамыз. Бұл журналдарды бір жерде сақтауға және талдауға мүмкіндік береді, өйткені Athena S3 жүйесіндегі деректермен тікелей жұмыс істей алады. Кейінірек мақалада журналдарды қалай дұрыс қосу және өңдеу керектігін айтамын, бірақ алдымен бізге S3 ішінде таза шелек қажет, онда басқа ештеңе сақталмайды. Шелекті қай аймақта жасайтыныңызды алдын ала қарастырған жөн, өйткені Athena барлық аймақтарда қолжетімді емес.
Athena консолінде схема құру
Афинада журналдар үшін кесте құрайық. Kinesis Firehose қолданбасын пайдалануды жоспарласаңыз, ол жазу үшін де, оқу үшін де қажет. Athena консолін ашып, кестені жасаңыз:
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');
Kinesis Firehose Stream жасау
Kinesis Firehose Nginx-тен S3-ке алынған деректерді таңдалған пішімде жазады, оны ЖЖЖЖ/АА/КК/СС пішіміндегі каталогтарға бөледі. Бұл деректерді оқу кезінде пайдалы болады. Сіз, әрине, Fluentd-тен S3-ге тікелей жаза аласыз, бірақ бұл жағдайда JSON жазуға тура келеді және бұл файлдардың үлкен көлеміне байланысты тиімсіз. Сонымен қатар, PrestoDB немесе Athena пайдалану кезінде JSON ең баяу деректер пішімі болып табылады. Сондықтан Kinesis Firehose консолін ашыңыз, «Жеткізу ағынын жасау» түймесін басыңыз, «жеткізу» өрісінде «тікелей PUT» таңдаңыз:
Келесі қойындыда «Жазба пішімін түрлендіру» - «Қосулы» таңдаңыз және жазу пішімі ретінде «Apache ORC» таңдаңыз. Кейбір зерттеулерге сәйкес
Сақтау және бұрын жасаған шелек үшін S3 таңдаймыз. Мен сәл кейінірек айтатын Aws Glue Crawler 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 контейнерінде іске қосамыз, бұл жағдайда Docker-те 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
Егер Nginx-ті басқаша іске қоссаңыз, журнал файлдарын пайдалана аласыз, Fluentd бар
Жоғарыда конфигурацияланған журналды талдауды Fluent конфигурациясына қосамыз:
<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>
Афина
Егер сіз бәрін дұрыс конфигурациялаған болсаңыз, біраз уақыттан кейін (әдепкі бойынша Kinesis алынған деректерді 10 минут сайын бір рет жазады) S3 жүйесінде журнал файлдарын көруіңіз керек. Kinesis Firehose «бақылау» мәзірінде сіз S3 жүйесінде қанша деректер жазылғанын, сондай-ақ қателерді көре аласыз. Kinesis рөліне S3 шелекіне жазу рұқсатын беруді ұмытпаңыз. Егер Kinesis бір нәрсені талдай алмаса, ол қателерді бірдей шелекке қосады.
Енді сіз Athena-да деректерді көре аласыз. Қателерді қайтарған соңғы сұрауларды табайық:
SELECT * FROM "db_name"."table_name" WHERE status > 499 ORDER BY created_at DESC limit 10;
Әрбір сұрау үшін барлық жазбаларды сканерлеу
Енді біздің журналдар өңделді және ORC жүйесінде S3 форматында сақталды, қысылды және талдауға дайын. Kinesis Firehose тіпті оларды әр сағат үшін каталогтарға ұйымдастырды. Дегенмен, кесте бөлінбегенше, Athena сирек жағдайларды қоспағанда, әрбір сұрау бойынша барлық уақыттағы деректерді жүктейді. Бұл екі себеп бойынша үлкен мәселе:
- Деректер көлемі үнемі өсуде, сұрауларды баяулатады;
- Athena үшін шот сканерленген деректер көлеміне негізделген, әрбір сұрау үшін кемінде 10 МБ.
Мұны түзету үшін біз S3 ішіндегі деректерді тексеріп шығып, Glue Metastore бөліміне ақпарат жазатын AWS Glue Crawler қолданамыз. Бұл бізге Athena сұрауы кезінде бөлімдерді сүзгі ретінде пайдалануға мүмкіндік береді және ол тек сұрауда көрсетілген каталогтарды сканерлейді.
Amazon Glue Crawler орнату
Amazon Glue Crawler S3 шелекіндегі барлық деректерді сканерлейді және бөлімдері бар кестелерді жасайды. AWS Glue консолінен Glue Crawler жасаңыз және деректерді сақтайтын шелек қосыңыз. Бірнеше шелек үшін бір тексеріп шығу құралын пайдалануға болады, бұл жағдайда ол көрсетілген дерекқорда шелектердің атауларына сәйкес атаулары бар кестелерді жасайды. Бұл деректерді үнемі пайдалануды жоспарласаңыз, Crawler іске қосу кестесін қажеттіліктеріңізге сәйкес конфигурациялауды ұмытпаңыз. Біз сағат сайын жұмыс істейтін барлық кестелер үшін бір Crawler пайдаланамыз.
Бөлінген кестелер
Тексеру құралын бірінші іске қосқаннан кейін әрбір сканерленген шелекке арналған кестелер параметрлерде көрсетілген дерекқорда пайда болуы керек. Athena консолін ашыңыз және 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 пайдалану қисынды. Cube.js серверін Heroku немесе Docker ішінде орналастыруды жоспарласаңыз, генерация үшін экспресс үлгісін пайдалана аласыз. Құжаттама басқаларды сипаттайды
$ 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 алдын ала жинақталған деректері бар қосымша кестелерді жасайды және олар келгенде деректерді автоматты түрде жаңартады. Бұл сұрауларды жылдамдатып қана қоймай, сонымен қатар Athena-ны пайдалану құнын төмендетеді.
Бұл ақпаратты деректер схемасы файлына қосамыз:
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"
}
]
}
Cube.js клиентін және React құрамдас кітапханасын NPM арқылы орнатайық:
$ 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