This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
giganet:sflow [2021/07/21 14:30] rb |
giganet:sflow [2021/08/03 13:28] (current) rb |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Схема мониторинга | + | ===== Общая схема мониторинга ===== |
- | ==== Задействованные сервера ==== | + | < |
+ | switch sflow -> goflow2 -> kafka -> clickhouse | ||
- | * **goflow **- сервер на котором крутится kafka и goflow2 приложение по сбору статистики | + | </ |
- | * **clickhouse **- сервер с базой данных clickhouse, хранение и обработка статистики | + | |
- | ==== Задействованные приложения ==== | + | |
- | | + | |
- | | + | - goflow2 |
- | | + | |
- | ==== Общая схема мониторинга ==== | + | |
+ | - kafka - таблица подключена на чтение в kafka, данные читаются только 1 раз | ||
+ | - kafka_to_raw - представление которое выбирает данные с kafka и добавляя нужные поля вставляет в raw | ||
+ | - raw - таблица с остаточными сырыми данными | ||
+ | |||
+ | ==== switch ==== | ||
+ | |||
+ | примеры конфигов для свитчей | ||
+ | |||
+ | < | ||
+ | sampling.1G = 8192 | ||
+ | sampling.10G = 8192 | ||
+ | sampling.40G = 16384 | ||
+ | sampling.100G = 32768 | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== goflow2 ==== | ||
+ | |||
+ | file / | ||
+ | |||
+ | < | ||
+ | GOFLOW2_ARGS=-format pb -format.protobuf.fixedlen=true -listen=sflow:// | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== kafka ==== | ||
+ | |||
+ | == Установка == | ||
+ | |||
+ | < | ||
+ | useradd kafka -m | ||
+ | passwd kafka | ||
+ | su -l kafka | ||
+ | cd | ||
+ | curl https:// | ||
+ | tar -xvzf kafka_2.13-2.8.0.tgz | ||
+ | ln -s / | ||
+ | |||
+ | </ | ||
+ | |||
+ | / | ||
+ | |||
+ | < | ||
+ | delete.topic.enable=true | ||
+ | |||
+ | </ | ||
+ | |||
+ | / | ||
+ | |||
+ | < | ||
+ | [Unit] | ||
+ | Requires=network.target remote-fs.target | ||
+ | After=network.target remote-fs.target | ||
+ | |||
+ | [Service] | ||
+ | Type=simple | ||
+ | User=kafka | ||
+ | ExecStart=/ | ||
+ | ExecStop=/ | ||
+ | Restart=on-abnormal | ||
+ | |||
+ | [Install] | ||
+ | WantedBy=multi-user.target | ||
+ | |||
+ | </ | ||
+ | |||
+ | / | ||
+ | |||
+ | < | ||
+ | [Unit] | ||
+ | Requires=zookeeper.service | ||
+ | After=zookeeper.service | ||
+ | |||
+ | [Service] | ||
+ | Type=simple | ||
+ | User=kafka | ||
+ | ExecStart=/ | ||
+ | ExecStop=/ | ||
+ | Restart=on-abnormal | ||
+ | |||
+ | [Install] | ||
+ | WantedBy=multi-user.target | ||
+ | |||
+ | </ | ||
+ | |||
+ | Запускаем сервисы | ||
+ | |||
+ | < | ||
+ | systemctl daemon-reload | ||
+ | systemctl start kafka | ||
+ | systemctl enable kafka | ||
+ | |||
+ | </ | ||
+ | |||
+ | Работаем с kafka | ||
+ | |||
+ | < | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | / | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== clickhouse ==== | ||
+ | |||
+ | === дополнительная информация === | ||
+ | |||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | [[https:// | ||
+ | |||
+ | === таблица kafka === | ||
+ | < | ||
+ | |||
+ | CREATE TABLE traffic.kafka | ||
+ | ( | ||
+ | `TimeReceived` UInt64, | ||
+ | `SequenceNum` UInt64, | ||
+ | `SamplingRate` UInt64, | ||
+ | `FlowDirection` UInt32, | ||
+ | |||
+ | `SamplerAddress` FixedString(16), | ||
+ | |||
+ | `TimeFlowStart` UInt64, | ||
+ | `TimeFlowEnd` UInt64, | ||
+ | |||
+ | `Bytes` UInt64, | ||
+ | `Packets` UInt64, | ||
+ | |||
+ | `SrcAddr` FixedString(16), | ||
+ | `DstAddr` FixedString(16), | ||
+ | |||
+ | `EType` UInt32, | ||
+ | `Proto` UInt32, | ||
+ | |||
+ | `SrcPort` UInt32, | ||
+ | `DstPort` UInt32, | ||
+ | |||
+ | `InIf` UInt32, | ||
+ | `OutIf` UInt32, | ||
+ | |||
+ | `SrcMac` String, | ||
+ | `DstMac` String, | ||
+ | |||
+ | `SrcVlan` UInt32, | ||
+ | `DstVlan` UInt32, | ||
+ | `VlanId` UInt32, | ||
+ | |||
+ | `IngressVrfID` UInt32, | ||
+ | `EgressVrfID` UInt32, | ||
+ | |||
+ | `IPTos` UInt32, | ||
+ | `ForwardingStatus` UInt32, | ||
+ | `IPTTL` UInt32, | ||
+ | `TCPFlags` UInt32, | ||
+ | `IcmpType` UInt32, | ||
+ | `IcmpCode` UInt32, | ||
+ | `IPv6FlowLabel` UInt32, | ||
+ | |||
+ | `FragmentId` UInt32, | ||
+ | `FragmentOffset` UInt32, | ||
+ | `BiFlowDirection` UInt32, | ||
+ | |||
+ | `SrcAs` UInt32, | ||
+ | `DstAs` UInt32, | ||
+ | |||
+ | `NextHop` FixedString(16), | ||
+ | `NextHopAS` UInt32, | ||
+ | |||
+ | `SrcNet` UInt32, | ||
+ | `DstNet` UInt32, | ||
+ | |||
+ | `HasMPLS` UInt8, | ||
+ | `MPLSCount` UInt32, | ||
+ | `MPLS1TTL` UInt32, | ||
+ | `MPLS1Label` UInt32, | ||
+ | `MPLS2TTL` UInt32, | ||
+ | `MPLS2Label` UInt32, | ||
+ | `MPLS3TTL` UInt32, | ||
+ | `MPLS3Label` UInt32, | ||
+ | `MPLSLastTTL` UInt32, | ||
+ | `MPLSLastLabel` UInt32 | ||
+ | ) | ||
+ | ENGINE | ||
+ | SETTINGS | ||
+ | kafka_broker_list = ' | ||
+ | kafka_topic_list = ' | ||
+ | kafka_group_name = ' | ||
+ | kafka_format = ' | ||
+ | kafka_schema = ' | ||
+ | kafka_num_consumers = 6 | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== таблица raw ==== | ||
+ | |||
+ | < | ||
+ | CREATE TABLE traffic.raw | ||
+ | ( | ||
+ | `Date` Date, | ||
+ | `Datetime` DateTime, | ||
+ | |||
+ | `SequenceNum` UInt64, | ||
+ | `SamplingRate` UInt64, | ||
+ | `FlowDirection` UInt32, | ||
+ | |||
+ | `SamplerAddress` String, | ||
+ | |||
+ | `TimeFlowStart` DateTime, | ||
+ | `TimeFlowEnd` DateTime, | ||
+ | |||
+ | `Bytes` UInt64, | ||
+ | `Packets` UInt64, | ||
+ | |||
+ | `SrcIp` String, | ||
+ | `DstIp` String, | ||
+ | |||
+ | `EType` UInt32, | ||
+ | `Proto` String, | ||
+ | |||
+ | `SrcPort` UInt32, | ||
+ | `DstPort` UInt32, | ||
+ | |||
+ | `InIf` UInt32, | ||
+ | `OutIf` UInt32, | ||
+ | |||
+ | `SrcMac` String, | ||
+ | `DstMac` String, | ||
+ | |||
+ | `SrcVlan` UInt32, | ||
+ | `DstVlan` UInt32, | ||
+ | `VlanId` UInt32, | ||
+ | |||
+ | `IngressVrfID` UInt32, | ||
+ | `EgressVrfID` UInt32, | ||
+ | |||
+ | `IPTos` UInt32, | ||
+ | `ForwardingStatus` UInt32, | ||
+ | `IPTTL` UInt32, | ||
+ | `TCPFlags` UInt32, | ||
+ | `IcmpType` UInt32, | ||
+ | `IcmpCode` UInt32, | ||
+ | `IPv6FlowLabel` UInt32, | ||
+ | |||
+ | `FragmentId` UInt32, | ||
+ | `FragmentOffset` UInt32, | ||
+ | `BiFlowDirection` UInt32, | ||
+ | |||
+ | `SrcGeo` UInt32, | ||
+ | `DstGeo` UInt32, | ||
+ | `SrcAs` UInt32, | ||
+ | `DstAs` UInt32, | ||
+ | |||
+ | `SrcCountry` String, | ||
+ | `DstCountry` String, | ||
+ | |||
+ | `NextHop` String, | ||
+ | `NextHopAS` UInt32, | ||
+ | |||
+ | `SrcNet` String, | ||
+ | `DstNet` String, | ||
+ | |||
+ | `HasMPLS` UInt8, | ||
+ | `MPLSCount` UInt32, | ||
+ | `MPLS1TTL` UInt32, | ||
+ | `MPLS1Label` UInt32, | ||
+ | `MPLS2TTL` UInt32, | ||
+ | `MPLS2Label` UInt32, | ||
+ | `MPLS3TTL` UInt32, | ||
+ | `MPLS3Label` UInt32, | ||
+ | `MPLSLastTTL` UInt32, | ||
+ | `MPLSLastLabel` UInt32) | ||
+ | ENGINE = MergeTree | ||
+ | PARTITION BY toYYYYMMDD(Date) | ||
+ | ORDER BY Datetime | ||
+ | TTL Date | ||
+ | SETTINGS index_granularity = 8192 | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== таблица kafka_to_raw ==== | ||
+ | |||
+ | < | ||
+ | CREATE MATERIALIZED VIEW traffic.kafka_to_raw TO traffic.raw | ||
+ | ( | ||
+ | `Date` Date, | ||
+ | `Datetime` DateTime, | ||
+ | |||
+ | `SequenceNum` UInt64, | ||
+ | `SamplingRate` UInt64, | ||
+ | `FlowDirection` UInt32, | ||
+ | |||
+ | `SamplerAddress` String, | ||
+ | |||
+ | `TimeFlowStart` DateTime, | ||
+ | `TimeFlowEnd` DateTime, | ||
+ | |||
+ | `Bytes` UInt64, | ||
+ | `Packets` UInt64, | ||
+ | |||
+ | `SrcIp` String, | ||
+ | `DstIp` String, | ||
+ | |||
+ | `EType` UInt32, | ||
+ | `Proto` String, | ||
+ | |||
+ | `SrcPort` UInt32, | ||
+ | `DstPort` UInt32, | ||
+ | |||
+ | `InIf` UInt32, | ||
+ | `OutIf` UInt32, | ||
+ | |||
+ | `SrcMac` String, | ||
+ | `DstMac` String, | ||
+ | |||
+ | `SrcVlan` UInt32, | ||
+ | `DstVlan` UInt32, | ||
+ | `VlanId` UInt32, | ||
+ | |||
+ | `IngressVrfID` UInt32, | ||
+ | `EgressVrfID` UInt32, | ||
+ | |||
+ | `IPTos` UInt32, | ||
+ | `ForwardingStatus` UInt32, | ||
+ | `IPTTL` UInt32, | ||
+ | `TCPFlags` UInt32, | ||
+ | `IcmpType` UInt32, | ||
+ | `IcmpCode` UInt32, | ||
+ | `IPv6FlowLabel` UInt32, | ||
+ | |||
+ | `FragmentId` UInt32, | ||
+ | `FragmentOffset` UInt32, | ||
+ | `BiFlowDirection` UInt32, | ||
+ | |||
+ | `SrcAs` UInt32, | ||
+ | `DstAs` UInt32, | ||
+ | |||
+ | `SrcCountry` String, | ||
+ | `DstCountry` String, | ||
+ | |||
+ | `NextHop` String, | ||
+ | `NextHopAS` UInt32, | ||
+ | |||
+ | `SrcNet` String, | ||
+ | `DstNet` String, | ||
+ | |||
+ | `HasMPLS` UInt8, | ||
+ | `MPLSCount` UInt32, | ||
+ | `MPLS1TTL` UInt32, | ||
+ | `MPLS1Label` UInt32, | ||
+ | `MPLS2TTL` UInt32, | ||
+ | `MPLS2Label` UInt32, | ||
+ | `MPLS3TTL` UInt32, | ||
+ | `MPLS3Label` UInt32, | ||
+ | `MPLSLastTTL` UInt32, | ||
+ | `MPLSLastLabel` UInt32 | ||
+ | ) AS | ||
+ | SELECT | ||
+ | toDate(TimeReceived) AS Date, | ||
+ | TimeReceived as Datetime, | ||
+ | IPv4NumToString(reinterpretAsUInt32(substring(reverse(SamplerAddress), | ||
+ | Bytes * SamplingRate as Bytes, | ||
+ | Packets * SamplingRate as Packets, | ||
+ | multiIf(EType = 0x0800, dictGetUInt32(' | ||
+ | EType = 0x86DD, dictGetUInt32(' | ||
+ | multiIf(EType = 0x0800, dictGetUInt32(' | ||
+ | EType = 0x86DD, dictGetUInt32(' | ||
+ | multiIf(EType = 0x0800, dictGetUInt32(' | ||
+ | EType = 0x86DD, dictGetUInt32(' | ||
+ | multiIf(EType = 0x0800, dictGetUInt32(' | ||
+ | EType = 0x86DD, dictGetUInt32(' | ||
+ | multiIf(EType = 0x0800, IPv4NumToString(reinterpretAsUInt32(substring(reverse(SrcAddr), | ||
+ | EType = 0x86DD, IPv6NumToString(SrcAddr), | ||
+ | multiIf(EType = 0x0800, IPv4NumToString(reinterpretAsUInt32(substring(reverse(DstAddr), | ||
+ | EType = 0x86DD, IPv6NumToString(DstAddr), | ||
+ | dictGet(' | ||
+ | MACNumToString(toUInt64(SrcMac)) AS SrcMac, | ||
+ | MACNumToString(toUInt64(DstMac)) AS DstMac, | ||
+ | dictGetString(' | ||
+ | dictGetString(' | ||
+ | |||
+ | SequenceNum, | ||
+ | SamplingRate, | ||
+ | FlowDirection, | ||
+ | TimeFlowStart, | ||
+ | TimeFlowEnd, | ||
+ | EType, | ||
+ | SrcPort, | ||
+ | DstPort, | ||
+ | InIf, | ||
+ | OutIf, | ||
+ | SrcVlan, | ||
+ | DstVlan, | ||
+ | VlanId, | ||
+ | IngressVrfID, | ||
+ | EgressVrfID, | ||
+ | IPTos, | ||
+ | ForwardingStatus, | ||
+ | IPTTL, | ||
+ | TCPFlags, | ||
+ | IcmpType, | ||
+ | IcmpCode, | ||
+ | IPv6FlowLabel, | ||
+ | FragmentId, | ||
+ | FragmentOffset, | ||
+ | BiFlowDirection, | ||
+ | NextHop, | ||
+ | NextHopAS, | ||
+ | SrcNet, | ||
+ | DstNet, | ||
+ | HasMPLS, | ||
+ | MPLSCount, | ||
+ | MPLS1TTL, | ||
+ | MPLS1Label, | ||
+ | MPLS2TTL, | ||
+ | MPLS2Label, | ||
+ | MPLS3TTL, | ||
+ | MPLS3Label, | ||
+ | MPLSLastTTL, | ||
+ | MPLSLastLabel | ||
+ | FROM traffic.kafka | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== Словари ==== | ||
+ | |||
+ | protocols - словарь для текстового представления протоколов | ||
+ | |||
+ | < | ||
+ | CREATE DICTIONARY dictionaries.protocols ( | ||
+ | `proto` UInt8, | ||
+ | `name` String, | ||
+ | `description` String | ||
+ | ) | ||
+ | PRIMARY KEY proto | ||
+ | SOURCE(FILE(PATH '/ | ||
+ | LIFETIME(MIN 0 MAX 3600) | ||
+ | LAYOUT(FLAT()) | ||
+ | |||
+ | </ | ||
+ | |||
+ | asnv4 - конвертация ipv4 к ASN | ||
+ | |||
+ | < | ||
+ | CREATE DICTIONARY dictionaries.asnv4 | ||
+ | ( | ||
+ | `network` String, | ||
+ | `asn` UInt32, | ||
+ | `aso` String DEFAULT '??' | ||
+ | ) | ||
+ | PRIMARY KEY network | ||
+ | SOURCE(FILE(PATH '/ | ||
+ | LIFETIME(MIN 0 MAX 3600) | ||
+ | LAYOUT(IP_TRIE()) | ||
+ | |||
+ | </ | ||
+ | |||
+ | asnv6 - конвертация ipv6 к ASN | ||
+ | |||
+ | < | ||
+ | CREATE DICTIONARY dictionaries.asnv6 | ||
+ | ( | ||
+ | `network` String, | ||
+ | `asn` UInt32, | ||
+ | `aso` String DEFAULT '??' | ||
+ | ) | ||
+ | PRIMARY KEY network | ||
+ | SOURCE(FILE(PATH '/ | ||
+ | LIFETIME(MIN 0 MAX 3600) | ||
+ | LAYOUT(IP_TRIE()) | ||
+ | |||
+ | </ | ||
+ | |||
+ | contryen | ||
+ | |||
+ | < | ||
+ | CREATE DICTIONARY dictionaries.contryen | ||
+ | ( | ||
+ | `geoname_id` id, | ||
+ | `locale_code` String, | ||
+ | `continent_code` String, | ||
+ | `continent_name` String, | ||
+ | `country_iso_code` String, | ||
+ | `country_name` String, | ||
+ | `is_in_european_union` UInt8 | ||
+ | ) | ||
+ | PRIMARY KEY geoname_id | ||
+ | SOURCE(FILE(PATH '/ | ||
+ | LIFETIME(MIN 0 MAX 3600) | ||
+ | LAYOUT(HASHED()) | ||
+ | |||
+ | </ | ||
+ | |||
+ | contryv4 | ||
+ | |||
+ | < | ||
+ | CREATE DICTIONARY dictionaries.contryv4 | ||
+ | ( | ||
+ | `network` String, | ||
+ | `geoname_id` UInt32 DEFAULT 0, | ||
+ | `registered_country_geoname_id` UInt32 DEFAULT 0, | ||
+ | `represented_country_geoname_id` UInt32 DEFAULT 0, | ||
+ | `is_anonymous_proxy` UInt8 DEFAULT 0, | ||
+ | `is_satellite_provider` UInt8 DEFAULT 0 | ||
+ | ) | ||
+ | PRIMARY KEY network | ||
+ | SOURCE(FILE(PATH '/ | ||
+ | LIFETIME(MIN 0 MAX 3600) | ||
+ | LAYOUT(IP_TRIE()) | ||
+ | |||
+ | </ | ||
+ | |||
+ | contryv6 | ||
+ | |||
+ | < | ||
+ | CREATE DICTIONARY dictionaries.contryv6 | ||
+ | ( | ||
+ | `network` String, | ||
+ | `geoname_id` UInt32 DEFAULT 0, | ||
+ | `registered_country_geoname_id` UInt32 DEFAULT 0, | ||
+ | `represented_country_geoname_id` UInt32 DEFAULT 0, | ||
+ | `is_anonymous_proxy` UInt8 DEFAULT 0, | ||
+ | `is_satellite_provider` UInt8 DEFAULT 0 | ||
+ | ) | ||
+ | PRIMARY KEY network | ||
+ | SOURCE(FILE(PATH '/ | ||
+ | LIFETIME(MIN 0 MAX 3600) | ||
+ | LAYOUT(IP_TRIE()) | ||
+ | |||
+ | </ | ||
+ | |||
+ | switches | ||
+ | |||
+ | < | ||
+ | CREATE DICTIONARY dictionaries.switches | ||
+ | ( | ||
+ | `ip` String, | ||
+ | `name` String | ||
+ | ) | ||
+ | PRIMARY KEY ip | ||
+ | SOURCE(FILE(PATH '/ | ||
+ | LIFETIME(MIN 0 MAX 3600) | ||
+ | LAYOUT(COMPLEX_KEY_HASHED()) | ||
+ | |||
+ | </ | ||