• No results found

Implementering av testplattform för end-to-end streaming telemetry i nätverk

N/A
N/A
Protected

Academic year: 2022

Share "Implementering av testplattform för end-to-end streaming telemetry i nätverk"

Copied!
44
0
0

Loading.... (view fulltext now)

Full text

(1)

Niklas Erlandsson

Självständigt arbete — Projektrapport Studieinriktning: Datateknik

Kursopäng: 15 hp Termin, år: VT, 2020

Handledare: Magnus Eriksson Examinator: Lennart Franked

Högskoleprogram: Nätverksdrift, 120 poäng

(2)

Abstract

The goals of this study are to implement a test environment for streaming telemetry and compare two alternatives for analysing the collected data in real-time. The two alternatives are the Python libraries PyKafka and Confluent-Kafka-Python. The comparison focused mainly on three are- as, these being documentation, amount of code and memory usage. The test environment for streaming telemetry was set up with a router run- ning IOS XR software that is sending data to a Cisco Pipeline collector, which in turn sends data to a Kafka-cluster. The comparison of the two libraries for interfacing with the cluster was made with the language Pyt- hon. The results of the comparison showed that both libraries had well- written documentation and showed a negligible difference in amount of code. The memory usage was considerably lower with the Confluent- Kafka-Python library. The study shows that streaming telemetry together with real-time analysis makes a good complement to or a replacement of SNMP. The study further recommends the use of Confluent-Kafka-Python in real-world implementations of streaming telemetry, particularly in lar- ge networks with a large amount of devices.

Keywords: Streaming Telemetry, Apache Kafka, Python, Real-time analy-

sis

(3)

Sammanfattning

Målen med denna studie är att implementera en testmiljö för streaming telemetry samt jämföra två alternativ för att möjliggöra realtidsanalys av det insamlade datat. Dessa två alternativ är Python-biblioteken PyKafka och Confluent-Kafka-Python. Bedömningskritierna för jämförselsen var dokumentation, kodmängd och minnesanvändning. Testmiljön för strea- ming telemetry använder en router med Cisco IOS XR programvara som skickar data till en Cisco Pipeline collector, som vidare sänder datat till ett Kafka-kluster. Jämförelsen av Python-biblioteken utfördes med språ- ket Python. Resultaten av jämförelsen visade att båda biblioteken hade välskriven dokumentation och liten skillnad i kodmängd, dock använde Confluent-Kafka-Python mindre minne. Studien visar att streaming tele- metry med realtidsanalys kan fungera bra som ett komplement till eller en ersättning av SNMP. Studien rekommenderar användning av Confluent- Kafka-Python för implementering i produktionsmiljöer med ett stort an- tal nätverksenheter med tanke på den lägre minnesanvändningen.

Nyckelord: Streaming Telemetry, Apache Kafka, Python, Realtidsanalys

(4)

Författarens tack

Ett stort tack till min handledare Magnus Eriksson för all hjälp under pro-

jektets gång. Jag vill även tacka mina företagshandledare Lukas Garberg

och Fredrik Lindgren för all hjälp med utvecklingen av skriptet och Sam

Pesonen för hjälp med routerkonfigurationen.

(5)

Författarens tack iii

Figurer vi

Tabeller vii

Kodexempel viii

Terminologi ix

1 Introduktion 1

1.1 Bakgrund och problemmotivering . . . . 1

1.2 Syfte . . . . 1

1.3 Avgränsningar . . . . 1

1.4 Konkreta och verifierbara mål . . . . 2

1.5 Översikt . . . . 2

2 Teori 3 2.1 Pull-baserade insamlingsmetoder . . . . 3

2.2 Push-baserade insamlingsmetoder . . . . 3

2.3 Pull kontra Push-metod? . . . . 4

2.4 Streaming telemetry - en översikt . . . . 4

2.4.1 Apache Kafka . . . . 5

2.4.2 Konfiguration av Streaming Telemetry . . . . 6

3 Metod 8 3.1 Verktyg . . . . 8

3.2 Bedömningskriterier . . . . 8

3.3 Mätning av minnesanvändning . . . . 8

3.4 Installation och konfigurering av Pipeline . . . . 9

3.5 Modell av tilltänkt teknisk lösning . . . . 9

4 Konstruktion 10 4.1 Anslutning till Apache Kafka och konsumtion av medde- landen . . . . 10

4.1.1 Skillnaden emellan PyKafka och Confluent-Kafka- Python . . . . 11

4.2 Filtrering och lagring av data i buffer . . . . 11

4.3 Uträkning av genomsnittlig belastning . . . . 14

(6)

4.4 Analys av data . . . . 14

5 Resultat 17 5.1 Jämförelse emellan Python-bibliotek . . . . 17

5.1.1 Dokumentation . . . . 17

5.1.2 Kodmängd och skriptkomplexitet . . . . 17

5.1.3 Minnesanvändning . . . . 17

6 Diskussion 19 6.1 Reflektion över arbetets syfte och mål . . . . 19

6.2 Reflektion över analysen . . . . 19

6.3 Etiska och samhälleliga aspekter . . . . 20

7 Slutsatser 21 7.1 Arbetets resultat . . . . 21

7.2 Förslag på fortsatt arbete . . . . 21

Källförteckning 22 A Fullständig kod för analys-skript 1 A.1 Confluent-Kafka-Python . . . . 1

A.2 PyKafka . . . . 5

B Skärmklipp över minnesanvändning 9

(7)
(8)

mory . . . . 18

(9)

Kodexempel

1 Exempel på YANG-RPC för on-change subscription . . . . 7 2 Upprätta anslutning till Kafka-brokers med SSL . . . . 10 3 Konsumera meddelanden ifrån Kafka-topic . . . . 10 4 Exempel på anslutning och konsumering med Pykafka . . 11 5 Filtering av data från meddelanden . . . . 12 6 Skapa post i buffer för interface och lagra värden . . . . 13 7 Beräkna genomsnittlig länkbelastning . . . . 14 8 Jämförelse av data mot länkkapacitet och genomsnittlig be-

lastning . . . . 15

(10)

Terminologi

SNMP Simple Network Management Protocol

MIB Management Information Base, används av SNMP OID Object ID, används av SNMP

NMS Network Monitoring System SLA Service Level Agreement

Apache Kafka System för att hantera meddelanden TSDB Time-Series Database

InfluxDB En variant av en TSDB

Prometheus Ett system bestående av en Event monitor och en TSDB

ASN.1 Abstract Syntax Notation One, en språkstandard för datastrukturer

BER Basic Encoding Rules, en del av X.601 standarden för ASN.1 notation

RPC Remote Procedure Call

(11)

1 Introduktion

1.1 Bakgrund och problemmotivering

Dagens pull-baserade metoder för att samla telemetridata från nätverk skalar allt sämre i stora nätverk. Uppdatering av MIBar i ett stort SNMP- baserat nätverk blir snabbt en krävande syssla, och NMS kan ha svårt att hantera belastningen av de tusentals enheter som data ska hämtas från.

Datat som tas in med dessa system är inte i realtid, och problem som uppstår i tiden emellan polling-intervaller blir ej upptäckta när de upp- kommer, vilket leder till stora problem i nätverk med höga krav på till- gänglighet och hårda SLA mot kund.

Streaming telemetry är en push-baserad metod för insamling av telemetri- data som ämnar att lösa problematiken med den åldrande polling-baserade tekniken som främst nyttjas idag. Streaming telemetry skickar prenume- rerad data kontinuerligt utan behov av en managers förfrågan som krävs med SNMP, vilket möjliggör åtkomst till fullständig realtidsdata som kan nyttjas för ändamål såsom nätverksautomatisering och preventivt under- håll. Streaming telemetry är optimalt för stora nätverk med höga krav på tillgänglighet och smala SLA-tider.

1.2 Syfte

Syftet med detta arbete är att ge mer kunskap om strömmande telemetri- lösningar för stora nätverk. Vidare ämnar arbetet att utforska insamlings- metodens möjligheter för felsökning av nätverket genom analys av in- samlad data.

1.3 Avgränsningar

Arbetet kommer främst att fokusera på implementering av en testmiljö för strömmande telemetri. Den data som samlas in kan användas för många ändamål som felsökning och automatiserad beslutsfattning, detta arbete kommer endast att fokusera på analys i felsökningssyfte.

Delar av infrastrukturen som krävs för implementering av streaming te-

lemetry är redan i drift på företaget, bl.a Apache Kafka och en TSDB. Det-

ta arbete kommer därför inte att beröra installation och konfiguration av

dessa moduler.

(12)

1.4 Konkreta och verifierbara mål

Detta arbete ämnar att uppnå dessa mål:

• Implementera en testplattform för strömmande telemetridata i nät- verk.

• Jämföra alternativ för konstruktion av program för analys av ström- mande data.

• Konstruera ett program för analys av strömmande data i syfte att upptäcka överbelastade länkar samt länkar som upplever snabba förändringar i belastning.

1.5 Översikt

Kapitel 1 ger en introduktion till arbetet samt beskriver arbetets syfte och mål.

Kapitel 2 beskriver teorin om ämnet datainsamling med fokus på nät- verksdrift.

Kapitel 3 beskriver arbetets metoder som används för att utveckla kod och metodiken för arbetets analys.

Kapitel 4 går igenom konstruktionen av skriptet som används för analy- sen.

Kapitel 5 redovisar och visualiserar analysens resultat.

Kapitel 6 reflekterar över arbetet och metoderna som användes för att skaffa resultaten samt en konsekvensanalys om nätverksautomatisering.

Kapitel 7 utformar slutsatser och ger rekommendationer för fortsatt arbe-

te inom detta område.

(13)

2 Teori

2.1 Pull-baserade insamlingsmetoder

Nästan alla nätverk idag använder någon form av datainsamling för att övervaka nätverkets hälsa och felsöka problem. Ett av de äldsta och mest vanligt förekommande protokollen är SNMP(Simple Network Manage- ment Protocol), vars första version har använts sedan 80-talet[1].

Martin-Flatin beskriver pull-baserade metoder såsom SNMP är baserade på request/response-modellen, där klienten skickar en request till servern och servern svarar antingen synkront eller asynkront. Detta kan liknas med att klienten drardata från servern, där klienten är en manager/NMS och servern är en nätverksenhet[2, sec 3.1].

I en artikel publicerad av Cisco argumenterar Shelly Cadora att pull-baserade datainsamlingsmetoder är väldigt resursintensiva, och har hög overhead, vilket gör att protokoll som SNMP blir allt mindre lämpliga i takt med att nätverken växer och mängden enheter som en manager hämtar data från ökar[3].

I artikeln beskriver Shelly Cadora vidare om SNMPs GetBulk-kommando för att hämta stora mängder data, genom att fylla ett paket med så många kolumner som möjligt. Om hela tabellen inte får plats så skickas en ny GetBulk-request från managern, till dess att svarspaketen innehåller OID från en annan tabell. För stora tabeller kan detta innebära många requests och väldigt stor belastning på nätverksenheten. I stora nätverk så är det inte ovanligt med NMS-redundans, vilket betyder två iterationer av den- na väldigt resurskrävande syssla. Eftersom nätverksenheten måste pro- cessa dessa GetBulk-requests oberoende av varandra leder detta till dub- belt arbete, även om primary och backup manager frågade efter samma MIB samtidigt[3].

2.2 Push-baserade insamlingsmetoder

Ett alternativ till de traditionella pull-baserade metoderna för datainsamn- ling är de push-baserade metoderna. Dessa metoder använder

publish/subscribe/distribute-modellen istället för request/response-modellen.

Martin-Flatin beskriver de push-baserade metodernas operation: Agen-

ten publicerar först vilken typ av information som kan skickas. Därefter

prenumererar en manager på den informationen som den vill ha, som

kan skickas via schemaläggning eller asynkront. Efter detta behöver ma-

nagern inte kommunicera direkt med agenten, agenten pushar"istället in-

formationen till managern[2, sec 3.1].

(14)

Martin-Flatin förklarar vidare fördelarna med att använda push-metoder, som minskad belastning på nätverket och förflyttning av en del av CPU- belastningen från managern till agenten. Martin-Flatin menar att en stor del av pull-metodernas overhead orsakas av den repetitiva naturen av nätverksdrift och datainsamling. Som exempel tar han upp ett vanligt sätt att kolla om en agent är online genom att förfråga samma OID-varibel t.ex sysObjectID, vilket snabbt blir resurskrävande och ineffektivt om en manager ska fråga alla agenter varje polling-cykel[2, sec 4].

Ett problem som push-metoder behöver lösa är synkronisering. Om au- tomatiserad nätverksövervakning och/eller datainsamling används kan osynkroniserade klockor leda till falsklarm och att data går förlorad. Martin- Flatin rekommenderar därför användning av t.ex NTP för att säkerstäl- la att schemalagda händelser och insamlingar fungerar korrekt. Martin- Flatin menar att denna synkroniserings-overhead är försumbar jämfört med den minskade CPU- och nätverksbelastningen som en övergång från pull till push-metoden innebär[2, sec 4].

2.3 Pull kontra Push-metod?

Martin-Flatin beskriver en väldigt enkel och relaterbar metafor som jäm- för de olika modellerna:

”The newspaper metaphor is a simple illustration of these models: if you want to read your favourite newspaper everyday, you can either go and buy it every morning, or subscribe to it once and then receive it automatically at home. The former is an example of pull, the latter of push.”[2, sec 3.1]

De två metoderna uppfyller i slutändan samma krav: insamling av data.

Skillnaden emellan metoderna ligger som tidigare nämnt i resursanvänd- ningen och belastning på nätverket.

Som exempel medför SNMPs nyttjande av SMIv1 för SNMPv1[4] och SMIv2 för SNMPv2 och SNMPv3[5] en högre overhead på grund av dess användning av ASN.1 med BER. BER har fått kritik för att vara onödigt stor i förhållande till mängden data, vilket resulterar i högre belastning på nätverket[2, sec 2.2].

2.4 Streaming telemetry - en översikt

En plattform för strömmande telemetri är uppbyggd av många system

som tillsammans formar en nyttig informationskedja. Många alternativ

för implementation av denna insamlingsmetod är öppna och använder

formateringsstandarder som stöds av en uppsjö olika system.

(15)

Cisco beskriver streaming telemetry som en push-baserad metod för da- tainsamling som möjliggör kontinuerligt strömmande av data i nära real- tid[6].

Telemetridata skickas oftast till en s.k collector, vars uppgift är att sam- la in data från flera enheter och formatera datat till den notation som förväntas av resten av övervakningsinfrastrukturen. T.ex kan collectorn Pipeline formatera data i JSON för användning i en Apache Kafka-buss eller till öppna format som används av t.ex Prometheus eller InfluxDB[7], två populära öppna alternativ för Tidsserie-databaser och systemöverva- kare[8][9].

Mera information om collectors och Cisco Pipeline finns på XRDocs[10]

och denna artikel[7] från Shelly Cadora.

2.4.1 Apache Kafka

Apache Kafka är ett populärt val för implementering i allehanda applika- tioner där hantering av meddelanden i realtid är ett krav. Apache Kafka är ett meddelandesystem vars funktion är att passera meddelanden från ett system till ett annat, utan att övriga system behöver tänka på medde- landehanteringen. Kafka arbetar enligt publish-subscribe-modellen, och lämpar sig därför särskilt väl till distribution av meddelanden till många konsumenter i realtid.[11]

Kafka organiserar meddelanden i topics som separerar olika meddelan- deköer ifrån varandra. Detta är särskilt bra för miljöer där många system kan köras på samma Kafka-server utan att blandas ihop. Kafka lagrar meddelanden i en indexerbar lista där de senaste meddelandena läggs till i ena änden. Det gör att man med en offset kan exempelvis hämta de senaste 50 meddelandena ur kön.[12]

PyKafka och Confluent-Kafka-Python

Det finns många alternativ för att kommunicera med en Kafka-server. Fle- ra bibliotek för språk såsom Python och C finns tillgängliga gratis, två ex- empel på Python-bibliotek är PyKafka och Confluent-Kafka-Python. Båda dessa bibliotek uppfyller samma funktion, dock skiljer sig implementatio- nerna åt.

PyKafka

Biblioteket PyKafka är helt och hållet Python-baserat, med stöd för att

använda C-biblioteket librdkafka istället för den python-baserade imple-

mentationen. Enligt PyKafkas dokumentation är bibliotekets primära mål

(16)

att ge användaren en hög grad av abstraktion och ett API som är så pyt- honiskt som möjligt[13]. PyKafka är utvecklat av Parse.ly, ett företag som utvecklar mjukvara för webb-analys och innehållsoptimering för online- publishing[14].

Confluent-Kafka-Python

Ett alternativ till PyKafka är Confluent-Kafka-Python, som utvecklas och underhålls av Confluent, Inc. Confluent är skaparna av Apache Kafka och Confluent Platform[15] som Confluent-Kafka-Python också stödjer.

Confluent-Kafka-Python är en wrapper som är byggd kring C-biblioteket librdkafka och kräver därför installation av librdkafka[16][17], till skill- nad från PyKafka som har inbyggda Python-baserade funktioner(se sek.

2.4.1).

2.4.2 Konfiguration av Streaming Telemetry

Konfiguration av streaming telemetry sker vanligtvis med YANG via NETCONF och data som skickas till en manager är även detta baserat på datamodel-

len YANG.[6] YANG är skapat av IETF och är datamodellen som används för all data som sänds över management-protokoll såsom NETCONF. YANG inkluderar modeller för all data som används för NETCONF-operationer, såsom konfigurationsdata, statistik, RPC och notifieringar.[18]

Streaming telemetry är som tidigare nämnt en push-modell, och konfi- gureras enligt publish/subscribe/distribute-modellen. För att etablera en subscription till en enhet så skickas en YANG ”establish-subscription”

RPC(Remote Procedure Call), som bl.a innehåller information om vilken data som ska skickas.[19]

Mera information om streaming telemetry och dess konfiguration kan hit- tas på Cisco DevNet[20].

Ett exempel på en establish-subscription RPC visas i kodexemplet nedan.

Denna RPC skapar en on-change subscription på alla ändringar i enhetens

CDP-tabell.

(17)

Kodexempel 1 : Exempel på YANG-RPC för on-change subscription 1 < rpc message - id = ''101 '' xmlns = ''

urn:ietf:params:xml:ns:netconf:base:1.0 ''>

2 <establish - subscription xmlns = ''

urn:ietf:params:xml:ns:yang:ietf -event - notifications '' xmlns:yp = ''

urn:ietf:params:xml:ns:yang:ietf -yang - push ''>

3 < stream > yp:yang -push </ stream >

4 <yp:xpath - filter > /cdp -ios -xe - oper:cdp - neighbour - details /cdp - neighbour -detail </ yp:xpath - filter >

5 <yp:dampening -period >0 </ yp:dampening -period >

6 </ establish - subscription >

7 </ rpc >

Det finns två typer av subscription som kan konfigureras i YANG: pe-

riodic och on-change. En periodic subscription skickar ut uppdatering-

ar enligt ett konfigurerat tidsintervall. En on-change-subscription skickar

endast ut uppdateringar när en ändring sker i den prenumererade infor-

mationen. Kodexempel 1 visar en on-change subscription som skickar ut

en uppdatering varje gång en ändring sker i enhetens CDP-tabell.[6]

(18)

3 Metod

Detta arbete kommer att implementera en testplattform för streaming te- lemetry och utföra analys på det insamlade datat. Insamlingen av datat kommer att göras i Apache Kafka och konsumeras av analys-skripten.

Detta arbetes undersökning kommer att utvärdera två Python-bibliotek som kan användas för att hämta och analysera data från Kafka. Dessa bibliotek är:

• PyKafka - Ett alternativ till Kafka-Python som underhålls av Parsly.

• confluent-kafka-python - Detta bibliotek underhålls av Confluent som skapade Kafka.

3.1 Verktyg

De verktyg som används för att utföra undersökningen är Ciscos Pipeline- collector som är kopplad till Apache Kafka. Språket Python kommer att användas tillsammans med de bibliotek som skall undersökas. Analysda- tat tillhandahålls av en Cisco router med IOS XR programvara. Mätning av minnesanvändning sker med programmet htop(1).

3.2 Bedömningskriterier

Biblioteken kommer att utvärderas efter följande kriterier:

• Dokumentation - Har biblioteket en välskriven dokumentation som förenklar implementationsarbetet?

• Kodmängd - Hur många rader kod krävs för att uppnå ett givet re- sultat?

• Minnesanvändning - Hur stor skillnad är det emellan biblioteken i minnesanvändning?

3.3 Mätning av minnesanvändning

Att jämföra minneanvändning är viktigt för skalbarhet. Eftersom detta ar- bete utvecklar en prototyp används endast en nätverksenhet för datain- samling. Minnesanvändningen mellan de två biblioteken kan ge en trolig bild över vilket bibliotek som bäst hanterar flera enheter i en produktions- miljö.

Minnesanvändningen kommer att mätas med programmet htop(1) efter

att skriptet har körts i 10 minuter. Därefter kommer resultaten att jämföras

(19)

mot varandra och skillnaden i minnesanvändning mätt i procent kommer att redovisas i del 5.

3.4 Installation och konfigurering av Pipeline

Att installera Pipeline är en simpel process. Allt som krävs för att komma igång är att ladda ned repositoriet från GitHub och starta programmet med startskriptet. Nätverksenheter som skickar data till Pipeline konfi- gurerades som dial-out, vilket betyder att de skickar data till collectorns IP-adress där collectorn redan lyssnar.

För att skicka data till Kafka så konfigurerades Pipeline med adresserna för de tre redan tillgängliga Kafka-servrarna, som finns i företagets pro- duktionsmiljö.

3.5 Modell av tilltänkt teknisk lösning

Mina tekniska lösningar för att uppnå arbetets mål kommer att följa funk- tionsmodellen i flödesdiagrammet nedan:

Start

Läs meddelan- de från Kafka

Lagra interface-värden, timestamp i buffer

Skapa delta på interface- värden och timestamp

Länken överbelastad? Larm till tekniker/NMS

Länkbelastning >

60% av medelvärde?

Länk OK, inget larm

Stop

Ja

Nej

Ja

Nej Interrupt

Figur 1: Flödesdiagram över lösningsmodell.

(20)

4 Konstruktion

Skriptet som konstruerades i detta arbete kan grovt delas upp i fyra di- stinkta delar som uppfyller en del av funktionaliteten och anropar sedan de andra delarna för att utföra arbetet. Den fullständiga koden återfinns i Bilaga A.

4.1 Anslutning till Apache Kafka och konsum- tion av meddelanden

För att upprätta en anslutning till Apache Kafka där nätverksenheternas meddelanden lagras finns det ett antal alternativ. De som användes i det- ta arbete var Python-biblioteken PyKafka och Confluent-Kafka-Python.

Funktionaliteten är densamma, exempelvis stödjer båda biblitotek anslut- ning med SSL(Confluent-Kafka-Python har även stöd för SASL), dock är det skillnader i implementationen av dessa bibliotek. Confluent-Kafka- Python är en Python-wrapper runt C-biblioteket librdkafka. PyKafka är ett fullständig Kafka-klient för Python, med stöd för användning av li- brdkafka, till skillnad från Confluent-kafkas krav.

Koden för att upprätta en anslutning med SSL med hjälp av biblioteket Confluent-Kafka-Python ser ut såhär:

Kodexempel 2 : Upprätta anslutning till Kafka-brokers med SSL 1 c = Consumer ({

2 ' bootstrap.servers ': 'kafka - servers -goes - here.net:9094 ' ,

3 'group.id ': 'TestGroup ',

4 ' auto.offset.reset ': 'latest ' , 5 ' security.protocol ': 'ssl ' ,

6 ' ssl.ca.location ': '/usr/ local / share /ca - certificates /ca - certificate -goes - here.crt ' 7 })

När en anslutning har upprättats kan man sedan konsumera meddelan- den från en specificerad Kafka-topic:

Kodexempel 3 : Konsumera meddelanden ifrån Kafka-topic 1 c.subscribe ([ ' kafkatopic.NetworkMetrics ' ]) 2

3 while True:

4 msg = c.poll (1.0)

(21)

Som tidigare nämnt i 2.4 fungerar en topic i Kafka-miljön som en separa- tor för att enkelt dela upp meddelanden från olika system till egna med- delandeköer.

4.1.1 Skillnaden emellan PyKafka och Confluent-Kafka- Python

I exempel 2 och 3 visade exempelkoden biblioteket Confluent-Kafka-Python.

Alternativet PyKafka utför samma uppgift, dock ser koden lite annorlun- da ut för anslutning till Kafka och konsumering av meddelanden:

Kodexempel 4 : Exempel på anslutning och konsumering med Pykafka 1 config = SslConfig ( cafile ='/usr/ local / share /ca -

certificates /ca - certificate -goes - here.crt ') 2

3 client = KafkaClient ( hosts ="kafka - servers -goes - here.net:9094 ",

4 ssl_config = config )

5

6 topic = client.topics [ ' kafkatopic.NetworkMetrics ']

7

8 consumer = topic.get_simple_consumer ( consumer_group = "

TestGroup " , auto_commit_enable =True , consumer_timeout_ms =32000)

9

10 for msg in consumer:

11 # Konsumera meddelanden

I Confluent-Kafka-Python lagras samtliga konfigurationsinställningar för anslutningen i en dict som sedan passerar direkt ner till underliggande librdkafka. PyKafka använder två separata funktioner för konfiguration av SSL och anslutning till Kafka-server.

4.2 Filtrering och lagring av data i buffer

För att få ut den data som krävs för analysen så behöver meddelande- na filteras och det relevanta datat lagras tillfälligt för att senare jämföras.

Exempelkoden nedan visar filtreringsfunktionen:

(22)

Kodexempel 5 : Filtering av data från meddelanden 1 #Get new messages

2 while True:

3 msg = c.poll (1.0) 4 # Basic error - checking 5 if msg is None:

6 continue

7 if msg.error ():

8 print ( " Consumer error: {}" . format ( msg.error () ))

9 continue

10 # Format message , encoded in JSON

11 data = json.loads ( format ( msg.value (). decode ( 'utf -8 ')))

12 # Check if data is about inteerfaces

13 if data ['Telemetry ' ][ 'encoding_path '] == 'Cisco - IOS -XR -infra -statsd - oper:infra - statistics / interfaces / interface / latest / generic - counters ':

14 # Match wanted data by key in the resulting dicts

15 for row in data ['Rows ' ]:

16 # Create variables , to be used later 17 device = data [ 'Telemetry '][ '

node_id_str ']

18 interface = row[ 'Keys ' ][ 'interface - name ']

19 key = device + "-" + interface

20 load = row[ 'Content ' ][ 'bytes - received ']

21 time = datetime.utcfromtimestamp ( int ( row[ 'Timestamp ' ]) / 1000)

22 # Send data to buffer - function

23 addToList (key , load , time ) 24 continue

När datat har filtrerats och placerats i variabler, så anropar skriptet funk-

tionen addToList, som ansvarar för att lagra datat i buffrar. Buffrarna är en

hierarisk dictionary, som lagrar datat med en nyckel för varje identifierat

interface.

(23)

Kodexempel 6 : Skapa post i buffer för interface och lagra värden

1 # Function to add messages to buffer , and send buffer off for comparison

2 def addToList (key , load , time ):

3 # Iterate through link - load records 4 for k in list ( Bytes.keys ()):

5 # Check if Key is in buffer already , and add it if not

6 if key not in Bytes.keys ():

7 print ( " Interface " + key + " detected. " )

8 Bytes [key] = []

9 avgBytes [key] = []

10 avg[key] = []

11 # Iterate over all keys in buffer , and check if two values are present

12 for k, v in Bytes.items ():

13 if k == key:

14 if len (v) == 2:

15 for k, v in avgBytes.items ():

16 if k == key and len (v) == 20:

17 calcAvg (key)

18 # Send off values to compare with

identifier

19 Compare (key)

20 # Append value to buffer as a list 21 Bytes [key ]. append ( load )

22 avgBytes [key ]. append ( load )

Denna funktion itererar igenom korttidsbuffern och kollar om interface- nyckeln redan finns. Om nyckeln inte finns så skapas nyckeln tillsammans med en tom lista. Samma nyckel skapas även i en annan långtidsbuffer, vars uppgift är att skapa ett genomsnittligt belastningsvärde under en längre tid.

Om nyckeln finns eller skapades så sker en ny iteration, som letar efter matchande nyckeln. När nyckeln hittas så utförs en kontroll om det redan finns två värden i korttidsbuffern. Om det finns två värden, så kontrolle- ras det om det finns 20 värden i långtidsbuffern. Om det finns 20 värden så anropas funktionen calcAvg, som skapar ett nytt genomsnittligt belast- ningsvärde för interfacet. Sedan anropas funktionen Compare som jämför de två värdena i korttidsbuffern.

Om det inte finns två värden i kortidsbuffern eller funktionen Compare har exekverat så lagras värdet i buffern.

Denna funktion repeterar ytterligare en gång över en annan buffer, som

(24)

lagrar Timestamp-värden. Exemplet ovan visar buffern som lagrar länk- belastningsvärden.

4.3 Uträkning av genomsnittlig belastning

Om långtidsbuffern innehåller 20 värden så anropas funktionen calcAvg.

Funktionen beräknar deltat i tid samt belastning mellan det senaste och det tidigaste värdet och lagrar resulterande länkbelastningen i en lista som används vid jämförelse av datat i korttidsbuffern.

Kodexempel 7 : Beräkna genomsnittlig länkbelastning 1 def calcAvg (key):

2 Iterate through buffer for the key 3 for k, v in avgBytes.items ():

4 if k == key:

5 print ( " Calculating average for " + key) 6 # Calculate delta between latest and

earliest data

7 avgLinkload = v [19] - v[0]

8 #Do the same in Timestamp buffer

9 for k, v in avgTS.items ():

10 if k == key:

11 avgTdelta = v [19] - v[0]

12 delta = avgTdelta.seconds

13 avgBps = avgLinkload / delta

14 #If there is no existing value ,

append one

15 if not avg [key ]:

16 avg[key ]. append ( avgBps )

17 # Otherwise overwrite older value

18 else:

19 avg[key ][0] = avgBps

20 # Clear buffers for new data 21 avgBytes [key ]. clear () 22 avgTS [key ]. clear () 23 return

4.4 Analys av data

Funktionen Compare anropas när det finns två värden tillhörande ett in- terface i buffern. För att beräkna belastning på länken tas ett delta emellan de två beräknade värdena:

• skillnaden i mottagna Bytes, och

(25)

• skillnaden i tid mätt i sekunder.

Dessa divideras med varandra för att få fram ett värde i Byte/sekund, Bps.

Om ett genomsnittligt värde finns från modulen som beskrivs i del 4.3 så kontrolleras det nya Bps-värdet. Överstiger värdet det genomsnittliga värdet med 60% så larmar skriptet genom en varning i terminalen. Sedan jämförs Bps-värdet med ett fördefinerat gränsvärde som baseras på vilket interface som kontrolleras, exempelvis 10 Gbit eller 1 Gbit. Om värdet är större än gränsvärdet så skriver skriptet ut en varning i terminalen. Om värdet är mindre än gränsvärdet så är allting OK och skriptet hämtar ny data och börjar om från början tills det stoppas manuellt.

Kodexempel 8 : Jämförelse av data mot länkkapacitet och genomsnittlig belast- ning

1 def Compare (key):

2 for k, v in Bytes.items ():

3 if k == key:

4 # Calculate delta between later and earlier data

5 linkload = v[1] - v[0]

6 for k, v in Timestamp.items ():

7 #Get delta for timestamp buffer too

8 tdelta = v[1] - v[0]

9 delta = tdelta.seconds

10 # Convert to Bps

11 bps = linkload / delta

12 # Check the keystring for interface type , and set load limit accordingly

13 if re.search ( 'HundredGigE ' , key):

14 limit = 12500000000

15 elif re.search ( 'TenGigE ', key):

16 limit = 1250000000

17 elif re.search ( 'GigE ' , key):

18 limit = 125000000

19 else:

20 limit = 125000000

21

22 # Check if current link load is 60% higher than average for interface

23 if avg[key] and bps > float (avg [key ][0]) * 1.6:

24 print ( " Average load is currently

" + " {:.2 f}" . format (bps) + "

Bytes / second on " + key)

25 print ( " Average load on link

(26)

unexpectedly high !" )

26 # Clear buffers

27 Bytes [key ]. clear ()

28 Timestamp [key ]. clear ()

29 return

30 # Check if interface load is above

interface capacity

31 elif bps > limit:

32 print ( " Average load is currently

" + " {:.2 f}" . format (bps) + "

Bytes / second on " + key)

33 print ( "The link is overloaded !" )

34 Bytes [key ]. clear ()

35 Timestamp [key ]. clear ()

36 return

37 #If everything is OK:

38 else:

39 print ( " Average load is currently

" + " {:.2 f}" . format (bps) + "

Bytes / second on " + key) 40 print ( " Link OK , resetting

buffer... ")

41 Bytes [key ]. clear ()

42 Timestamp [key ]. clear ()

43 return

(27)

5 Resultat

5.1 Jämförelse emellan Python-bibliotek

5.1.1 Dokumentation PyKafka

Dokumentationen för PyKafka listar möjliga funktionsanrop, tillgängliga parametrar och om applicerbart vilken typ av data som returneras[13].

PyKafka skapades och underhålls av Parse.ly och har en relativt aktiv användarbas som ger tips och råd på sidor som StackExchange.

Confluent-Kafka-Python

Dokumentationen för Confluent-Kafka-Python listar möjliga funktions- anrop, vilka parametrar som är applicerbara för en given funktion, samt vilken typ av data som funktionen returnerar.[16] Biblioteket underhålls av företaget Confluent Inc, som skapade Apache Kafka. Även här finns gott om hjälp från användarbasen, på sidor som StackExchange.

5.1.2 Kodmängd och skriptkomplexitet

Mängden biblioteksspecifik kod i de två skripten som användes för jäm- förelsen är väldigt liten. Skriptet som använde PyKafka är totalt 158 rader långt. Skriptet som använder Confluent-Kafka-Python är totalt 163 rader långt.

Om man endast jämför koden som tillhör de två biblioteken så skiljer det tre rader kod, där PyKafka hade totalt 7 gentemot Confluent-Kafka- Pythons 10.

Kodmängd - Total Kodmängd - specifik

PyKafka 158 7

Confluent-Kafka 163 10

Differens 5 3

Tabell 1: Skillnaden i kodstorlek emellan PyKafka och Confluent-Kafka

5.1.3 Minnesanvändning

Som tidigare nämnt i sektion 3.1 så användes verktyget htop(1) för att mä-

ta minnesanvändningen. Både den virtuella minnesallokeringen(VIRT)

(28)

och den faktiska minnesallokeringen(RES) användes för jämförelse. Den virtuella allokeringen inkluderar saker som mappning av bibliotek etc. Se även bilaga B för skärmdumpar av värdena i htop(1).

Memory - Virtual Memory - Resident

PyKafka 658 MB 33,6 MB

Confluent-Kafka 480 MB 25,6 MB Difference ( %) 37,1 31,25

Tabell 2: Bibliotekens minnesanvändning i virtual och resident memory

(29)

6 Diskussion

6.1 Reflektion över arbetets syfte och mål

Detta arbetets syfte gick ut på att bidra med mera kunskap om ämnet streaming telemetry samt att implementera en testmiljö för att kunna testa olika lösningar som tidigare nämnt i del 1.2 och 1.4.

Verktygen som har använts för att lösa dessa uppgifter har varit enkla att jobba med, det finns väldigt gott om dokumentation och aktiva com- munities som finns tillgängliga om det skulle uppstå problem. Streaming telemetry är fortfarande ett relativt nytt område inom nätverksdrift och det har varit väldigt intressant att söka kunskap och nyttja den för detta ändamål.

Det andra målet om att jämföra alternativ för konstruktionen av skriptet resulterade i jämförelsen mellan PyKafka och Confluent-Kafka-Python.

Denna jämförelse utfördes genom konstruktion av testskript som visade en stor skillnad i minnesanvändningen, en viktig aspekt när det gäller val av bibliotek för ett skript i en produktionsmiljö med ett stort antal enheter.

Det tredje målet om att konstruera ett program som kan analysera det insamlade datat var en intressant utmaning som resulterade i ett väldigt skalbart skript, som kan växa i takt med att mängden enheter som ansluts till systemet ökar. Skriptet kan användas som en bra grund att bygga vida- re på alternativt ses som ett POC som bidrar med kunskap i utvecklingen av ett annat program eller skript.

Ett möjligt problem med skriptet i sin nuvarande form är minnesanvänd- ningen, vilket kan påverka skalbarheten i en stor produktionsmiljö, ex- empelvis en ISP med tusentals enheter vars telemetridata ska filtreras och hanteras. Den relativt höga minnesanvändningen som ofta förekommer i Python-program kan bli ett hinder för en implementering i en större ska- la. En lösning på detta kan vara att använda ett annat språk som ger mera granulär kontroll över minneshanteringen, såsom C och biblioteket librd- kafka.

6.2 Reflektion över analysen

Granskningen och jämförelsen av de två biblioteken PyKafka och Confluent- Kafka-Python är i min mening lyckad om än något grundläggande. För att förbättra denna granskning så hade det behövts en djupare analys av den underliggande koden för att bättre kunna jämföra de två biblioteken.

Resultatet av granskningen visade att Confluent-Kafka-Python använde

(30)

mindre minne, både virtuellt och resident. Detta anser jag gör ytterligare analys av Confluent-Kafka mera intressant sett till skalbarheten.

Ett problem med min analys som beskrivs i del 3.3 är användandet av endast en mätpunkt. För att uppnå ett mera pålitligt resultat så hade flera värden vid olika tidpunkter kunnat nyttjas och ett medelvärde dragits av dessa.

6.3 Etiska och samhälleliga aspekter

Detta arbete är endast ett första steg på vägen mot ett nätverk som kan i realtid upptäcka och automatiskt reagera på problem. Detta arbete och skriptet som resulterade kan inte självständigt åtgärda några problem ut- an en tekniker, dock är teknologin fullt kapabel till att utveckla och drifta både enklare och mera avancerad automatisk felsökning och åtgärd.

Det är ingen hemlighet att i takt med att implementering och använd-

ning av teknologier som streaming telemetry och avancerad nätverksau-

tomation ökar finns det på längre sikt en chans att behovet för yrken som

nätverkstekniker minskar. Detta kan leda till nedskärningar i driftavdel-

ningar med uppsägning av personal som följd.

(31)

7 Slutsatser

7.1 Arbetets resultat

Arbetet redovisade att streaming telemetry kan användas som ett kom- plement till eller ersättning för SNMP för nätverksövervakning. Telemetri- data från nätverk kan hämtas i nära realtid och analyseras i takt med att informationen kommer in, vilket i en produktionsmiljö kan översättas till bättre upptid och snabbare respons på problem. De tre utsatta målen i del 1.4 har uppnåtts, med en lyckad implementering av en testplattform för streaming telemetry, en jämförelse emellan två bibliotek som kan använ- das för att tillhandahålla realtidsanalys samt ett konstruerat POC-skript som kan analysera det strömmande datat.

Som redovisats i del 5.1.2 så var det ingen större skillnad i mängden kod som krävdes för att uppfylla målet som beskrivs i del 1.4. Baserat på dessa resultat anser jag att valet av bibliotek inte har någon påverkan på det slutliga skriptets storlek eller komplexitet.

I del 5.1.3 så redovisades minnesanvändningen för de två skripten, där skillnaden var biblioteket för anslutning till Apache Kafka. Skillnaden i minnesanvändning var större än vad jag först trodde, en tänkbar anled- ning till varför detta är fallet är att Confluent-Kafka-Pythons nyttjande av det underliggande C-biblioteket librdkafka orsakade det bättre resultatet.

Python är inte känt för att vara ett språk som är särskilt väl optimerat för låg minnesanvändning, och C-biblioteket minskar mängden python- specifik kod som krävs för att utföra samma funktioner.

7.2 Förslag på fortsatt arbete

För att bygga vidare på detta arbete så ges följande förslag:

• En djupare granskning och jämförelse av PyKafka och Conlfuent- Kafka-Python och dess lämplighet för hämtning av telemetridata.

• En mera grundlig analys av bibliotekens minnesanvändning, med förbättrad metodik som t.ex hämtar flera mätvärden vid olika tid- punkter.

• Vidareutveckling av skriptet med funktioner för lagring i databas,

larmhantering och mera anpassningsbarhet med användning av ex-

empelvis argument.

(32)

Källförteckning

[1] J Case, M Fedor, M Schoffstall m. fl. RFC 1067, A Simple Network Management Protocol. Aug. 1988. URL : https://tools.ietf.org/

html/rfc1067 (se s. 3).

[2] Jean-Philippe Martin-Flatin. Push vs. Pull in Web-Based Network Ma- nagement. Nov. 1998. URL : http://lcawww.epfl.ch/Publications/

Martin-Flatin/Martin-Flatin99a.pdf (se s. 3, 4).

[3] Shelly Cadora. The limits of SNMP. Accessed 2020-04-15. 2016. URL : https://blogs.cisco.com/sp/the-limits-of-snmp (se s. 3).

[4] M Rose och K McCloghrie. RFC 1155, Structure and Identification of Management Information for TCP/IP-based Internets. Maj 1990. URL : https://tools.ietf.org/html/rfc1155 (se s. 4).

[5] M Rose, K McCloghrie, J Case m. fl. RFC 1902, Structure of Manage- ment Information for Version 2 of the Simple Network Management Pro- tocol (SNMPv2). Jan. 1996. URL : https://tools.ietf.org/html/

rfc1902 (se s. 4).

[6] Cisco Systems, Inc. Streaming Telemetry. URL : https://developer.

cisco.com/docs/ios-xe/#!streaming-telemetry-quick-start- guide/streaming-telemetry (se s. 5–7).

[7] Shelly Cadora. Introducing Pipeline: A Model-Driven Telemetry Col- lection Service. Juli 2017. URL : https : / / blogs . cisco . com / sp / introducing-pipeline-a-model-driven-telemetry-collection- service (se s. 5).

[8] The Linux Foundation. What is Prometheus? URL : https://prometheus.

io/docs/introduction/overview/ (se s. 5).

[9] InfluxData Inc. Why use InfluxDB 1.x? URL : https://www.influxdata.

com/time-series-platform/ (se s. 5).

[10] Viktor Osipchuk. Everything you need to know about Pipeline. 2018.

URL : https://xrdocs.io/telemetry/tutorials/2018- 03- 01- everything-you-need-to-know-about-pipeline/ (se s. 5).

[11] Tutorials Point. Apache Kafka - Introduction. 2020. URL : https://www.

tutorialspoint.com/apache_kafka/apache_kafka_introduction.

htm (se s. 5).

[12] Apache Software Foundation. Apache Kafka® is a distributed strea- ming platform. What exactly does that mean? 2017. URL : https : / / kafka.apache.org/intro (se s. 5).

[13] Parse.ly. PyKafka. URL : https : / / pykafka . readthedocs . io / en /

latest/index.html (se s. 6, 17).

(33)

[14] Parse.ly. Parse.ly. 2020. URL : https://www.parse.ly/ (se s. 6).

[15] Confluent, Inc. Confluent Platform. URL : https://www.confluent.

io/product/confluent-platform/ (se s. 6).

[16] Confluent, Inc. The Confluent Kafka API. URL : https://docs.confluent.

io/current/clients/confluent-kafka-python/ (se s. 6, 17).

[17] Confluent, Inc. Confluent’s Python Client for Apache Kafka. URL : https:

//github.com/confluentinc/confluent- kafka- python/blob/

master/README.md (se s. 6).

[18] M Björklund. RFC 6020, YANG - A Data Modeling Language for the Network Configuration Protocol (NETCONF). Okt. 2010. URL : https:

//tools.ietf.org/html/rfc6020 (se s. 6).

[19] A Clemm och E Voit. RFC 8641, Subscription to YANG Notifications for Datastore Updates. Sept. 2019. URL : https://tools.ietf.org/

html/rfc8641 (se s. 6).

[20] Cisco DevNet. Streaming Telemetry. URL : https://developer.cisco.

com/docs/ios-xe/#!streaming-telemetry-quick-start-guide/

what-is-subscription (se s. 6).

(34)
(35)

A Fullständig kod för analys-skript

A.1 Confluent-Kafka-Python

1 #!/ usr/bin/env python3

2 from __future__ import division 3 from collections import defaultdict 4 import json

5 import math

6 from pprint import pprint 7 from itertools import islice 8 from datetime import datetime

9 from confluent_kafka import Consumer 10 import re

11

12 def calcAvg (key):

13 for k, v in avgBytes.items ():

14 if k == key:

15 print ( " Calculating average for " + key)

16 avgLinkload = v[3] - v[0]

17 for k, v in avgTS.items ():

18 if k == key:

19 avgTdelta = v[3] - v[0]

20 delta = avgTdelta.seconds

21 avgBps = avgLinkload / delta

22 if not avg [key ]:

23 avg[key ]. append ( avgBps )

24 print (avg[ key ])

25 else:

26 avg[key ][0] = avgBps

27 print (avg[ key ])

28

29 avgBytes [key ]. clear () 30 avgTS [key ]. clear () 31 return

32

33 # Function to add messages to buffer , and send buffer off for comparison

34 def addToList (key , load , time ):

35 # Iterate through link - load records 36 for k in list ( Bytes.keys ()):

37 if key not in Bytes.keys (): # Check if Key is in buffer already , and add it if not

38 print ( " Interface " + key + " detected. " )

39 Bytes [key] = []

(36)

40 avgBytes [key] = []

41 avg[key] = []

42 pprint (avg)

43 for k, v in Bytes.items (): # Iterate

over all keys in buffer , and check if two values are present

44 if k == key:

45 if len (v) == 2:

46 print ( "Two values in Buffer. ")

47 for k, v in avgBytes.items ():

48 if k == key and len (v) == 4:

49 calcAvg (key)

50 Compare (key) # Send off

values to compare along with key to identify

51 return

52 Bytes [key ]. append ( load ) # Append value to buffer as a list

53 avgBytes [key ]. append ( load ) 54 # print ( Bytes [key ])

55

56 # Iterate through Timestamp records 57 for k in list ( Timestamp.keys ()):

58 if key not in Timestamp.keys ():

59 # print (" New interface " + key + "

detected , adding to TSbuffer... ")

60 Timestamp [key] = []

61 avgTS [key] = []

62 for k, v in Timestamp.items ():

63 if k == key:

64 if len (v) == 2:

65 # print (" Two values in TSbuffer , comparing... ")

66 for k, v in avgTS.items ():

67 if k == key and len (v) == 4:

68 calcAvg (key)

69 Compare (key)

70 return

71 Timestamp [key ]. append ( time ) 72 avgTS [key ]. append ( time ) 73 # print ( Timestamp [key ]) 74 return

75

76 # Function to compare values in buffer , and then clear it

77 def Compare (key):

(37)

78 for k, v in Bytes.items ():

79 if k == key:

80 # print (k, v)

81 linkload = v[1] - v[0]

82 for k, v in Timestamp.items ():

83 if k == key:

84 tdelta = v[1] - v[0]

85 delta = tdelta.seconds

86 bps = linkload / delta

87

88 if re.search ( 'HundredGigE ' , key):

89 # print (" Hundred Gigbit link

detected. ")

90 limit = 12500000000

91 elif re.search ( 'TenGigE ' , key):

92 # print (" Ten Gigabit link

detected. ")

93 limit = 1250000000

94 elif re.search ( 'GigE ' , key):

95 # print (" Gigabit link

detected. ")

96 limit = 125000000

97 else:

98 # print (" Cannot identify

interface speed ,

defaulting to Gigabit. ")

99 limit = 125000000

100 101

102 if avg[ key] and bps > float (avg[

key ][0]) * 1.6:

103 print ( " Average load is

currently " + " {:.2 f}" . format (bps) + " Bytes / second on " + key)

104 print ( " Average load on link unexpectedly high !" )

105 print ( Bytes [key ])

106 print (avg[ key ])

107 Bytes [key ]. clear ()

108 Timestamp [key ]. clear ()

109 return

110 elif bps > limit:

111 print ( " Average load is

currently " + " {:.2 f}" .

format (bps) + " Bytes /

(38)

second on " + key)

112 print ( " The link is overloaded

!" )

113 Bytes [key ]. clear ()

114 Timestamp [key ]. clear ()

115 return

116 else:

117 print ( " Average load is

currently " + " {:.2 f}" . format (bps) + " Bytes / second on " + key) 118 print ( " Link OK , resetting

buffer... " )

119 print ( Bytes [key ])

120 # print ( Timestamp )

121 Bytes [key ]. clear ()

122 Timestamp [key ]. clear ()

123 return

124

125 # Buffers:

126 Timestamp = defaultdict ( list ) 127 Bytes = defaultdict ( list ) 128 avgBytes = defaultdict ( list ) 129 avgTS = defaultdict ( list ) 130 avg = defaultdict ( list ) 131

132 c = Consumer ({

133 ' bootstrap.servers ': 'kafka - servers -goes - here.net:9094 ' ,

134 'group.id ': 'TestGroup ',

135 ' auto.offset.reset ': 'latest ' , 136 ' security.protocol ': 'ssl ' ,

137 ' ssl.ca.location ': ' certificate.crt ' 138 })

139

140 c.subscribe ([ ' kafkatopic.NetworkMetrics ' ]) 141

142 while True:

143 msg = c.poll (1.0) 144

145 if msg is None:

146 continue

147 if msg.error ():

148 print ( " Consumer error: {}" . format ( msg.error () ))

149 continue

(39)

150

151 data = json.loads ( format ( msg.value (). decode ( 'utf -8 ')))

152 # Check if data is about interfaces

153 if data ['Telemetry ' ][ 'encoding_path '] == 'Cisco - IOS -XR -infra -statsd - oper:infra - statistics / interfaces / interface / latest / generic - counters ':

154 for row in data ['Rows ' ]:

155 device = data [ 'Telemetry '][ ' node_id_str ']

156 interface = row[ 'Keys ' ][ 'interface - name ']

157 key = device + "-" + interface

158 load = row[ 'Content ' ][ 'bytes - received ']

159 time = datetime.utcfromtimestamp ( int ( row[ 'Timestamp ' ]) / 1000)

160 addToList (key , load , time ) 161 continue

162

163 c.close ()

A.2 PyKafka

1 #!/ usr/bin/env python3

2 from __future__ import division 3 from collections import defaultdict 4 import json

5 import math

6 from pprint import pprint 7 from itertools import islice 8 from datetime import datetime

9 from pykafka import KafkaClient , SslConfig 10 from pykafka.common import OffsetType

11 import re 12

13 def calcAvg (key):

14 for k, v in avgBytes.items ():

15 if k == key:

16 print ( " Calculating average for " + key )

17 avgLinkload = v[3] - v[0]

18 for k, v in avgTS.items ():

19 if k == key:

20 avgTdelta = v[3] - v[0]

21 delta = avgTdelta.seconds

22 avgBps = avgLinkload / delta

(40)

23 if not avg [key ]:

24 avg[key ]. append ( avgBps )

25 print (avg[ key ])

26 else:

27 avg[key ][0] = avgBps

28 print (avg[ key ])

29

30 avgBytes [key ]. clear () 31 avgTS [key ]. clear () 32 return

33

34 # Function to add messages to buffer , and send buffer off for comparison

35 def addToList (key , load , time ):

36 # Iterate through link - load records 37 for k in list ( Bytes.keys ()):

38 if key not in Bytes.keys (): # Check if Key is in buffer already , and add it if not

39 print ( " Interface " + key + " detected. " )

40 Bytes [key] = []

41 avgBytes [key] = []

42 avg[key] = []

43 pprint (avg)

44 for k, v in Bytes.items (): # Iterate

over all keys in buffer , and check if two values are present

45 if k == key:

46 if len (v) == 2:

47 print ( "Two values in Buffer. ")

48 for k, v in avgBytes.items ():

49 if k == key and len (v) == 4:

50 calcAvg (key)

51 Compare (key) # Send off

values to compare along with key to identify

52 return

53 Bytes [key ]. append ( load ) # Append value to buffer as a list

54 avgBytes [key ]. append ( load ) 55 # print ( Bytes [key ])

56

57 # Iterate through Timestamp records 58 for k in list ( Timestamp.keys ()):

59 if key not in Timestamp.keys ():

60 # print (" New interface " + key + "

(41)

detected , adding to TSbuffer... ")

61 Timestamp [key] = []

62 avgTS [key] = []

63 for k, v in Timestamp.items ():

64 if k == key:

65 if len (v) == 2:

66 # print (" Two values in TSbuffer , comparing... ")

67 for k, v in avgTS.items ():

68 if k == key and len (v) == 4:

69 calcAvg (key)

70 Compare (key)

71 return

72 Timestamp [key ]. append ( time ) 73 avgTS [key ]. append ( time ) 74 # print ( Timestamp [key ]) 75 return

76

77 # Function to compare values in buffer , and then clear it

78 def Compare (key):

79 for k, v in Bytes.items ():

80 if k == key:

81 # print (k, v)

82 linkload = v[1] - v[0]

83 for k, v in Timestamp.items ():

84 if k == key:

85 tdelta = v[1] - v[0]

86 delta = tdelta.seconds

87 bps = linkload / delta

88

89 if re.search ( 'HundredGigE ' , key):

90 # print (" Hundred Gigbit link

detected. ")

91 limit = 12500000000

92 elif re.search ( 'TenGigE ' , key):

93 # print (" Ten Gigabit link

detected. ")

94 limit = 1250000000

95 elif re.search ( 'GigE ' , key):

96 # print (" Gigabit link

detected. ")

97 limit = 125000000

98 else:

99 # print (" Cannot identify

interface speed ,

(42)

defaulting to Gigabit. ")

100 limit = 125000000

101 102

103 if avg[ key] and bps > float (avg[

key ][0]) * 1.6:

104 print ( " Average load is

currently " + " {:.2 f}" . format (bps) + " Bytes / second on " + key)

105 print ( " Average load on link unexpectedly high !" )

106 print ( Bytes [key ])

107 print (avg[ key ])

108 Bytes [key ]. clear ()

109 Timestamp [key ]. clear ()

110 return

111 elif bps > limit:

112 print ( " Average load is

currently " + " {:.2 f}" . format (bps) + " Bytes / second on " + key)

113 print ( " The link is overloaded

!" )

114 Bytes [key ]. clear ()

115 Timestamp [key ]. clear ()

116 return

117 else:

118 print ( " Average load is

currently " + " {:.2 f}" . format (bps) + " Bytes / second on " + key) 119 print ( " Link OK , resetting

buffer... " )

120 print ( Bytes [key ])

121 # print ( Timestamp )

122 Bytes [key ]. clear ()

123 Timestamp [key ]. clear ()

124 return

125

126 # Buffers:

127 Timestamp = defaultdict ( list )

128 Bytes = defaultdict ( list )

129 avgBytes = defaultdict ( list )

130 avgTS = defaultdict ( list )

131 avg = defaultdict ( list )

(43)

132

133 #SSL config and connection establishment:

134 config = SslConfig ( cafile =' certificate.crt ') 135

136 client = KafkaClient ( hosts ="kafka - servers -goes - here.net:9094 ", ssl_config = config )

137

138 topic = client.topics [ ' kafkatopic.NetworkMetrics ']

139

140 consumer = topic.get_simple_consumer ( consumer_group = "

TestGroup " , auto_commit_enable =True , consumer_timeout_ms =32000)

141

142 # Iterate over all messages 143 for msg in consumer:

144 # Clean up messeasges

145 data = json.loads ( msg.value ) 146

147 # Check if data is about interfaces

148 if data ['Telemetry ' ][ 'encoding_path '] == 'Cisco - IOS -XR -infra -statsd - oper:infra - statistics / interfaces / interface / latest / generic - counters ':

149 for row in data ['Rows ' ]:

150 device = data [ 'Telemetry '][ ' node_id_str ']

151 interface = row[ 'Keys ' ][ 'interface - name ']

152 key = device + "-" + interface

153 load = row[ 'Content ' ][ 'bytes - received ']

154 time = datetime.utcfromtimestamp ( int ( row[ 'Timestamp ' ]) / 1000)

155 addToList (key , load , time )

B Skärmklipp över minnesanvändning

(44)

Figur 2: Skärmklipp av htop med Confluent-Kafka

Figur 3: Skärmklipp av htop med PyKafka

References

Related documents

Jessica F risk Acupuncture treatment for hot flushes in women with breast cancer and men with prostate cancer. FLUSHES HOT

KEY WORDS: N-Rheme, English, Swedish, contrastive, corpus-based, translation, parallel corpus, Systemic Functional Linguistics, information structure, information density, Rheme,

In the translations, the ing- clause Tail is usually translated into a separate T-unit, with repetition of the Subject, which is usually the Theme in the English original text and

The data used in task 6 is an adapta- tion of the restaurant reservation dataset from the second dialog state tracking challenge (DSTC2) [8].. The dataset was originally designed

Man skulle kunna beskriva det som att den information Johan Norman förmedlar till de andra är ofullständig (om detta sker medvetet eller omedvetet kan inte jag ta ställning

Detta stöds av Pishdad &amp; Haider (2013b) att stöd från ledning under hela implementeringsfasen bidrar till större acceptans hos slutanvändarna och anses vara

Second, we evaluate different secure messaging protocols and we consider the scientific work and relevant activities addressing transparency from the edge devices to the

The aim of this paper is to propose a specific measurement framework and relevant metrics for Company X to measure the performance of the end-to-end Product X supply chain.. Product