Hur vi samlade in data om reklamkampanjer från webbsajter (den svåra vägen till produkten)

Det verkar som att området för onlineannonsering borde vara så tekniskt avancerat och automatiserat som möjligt. Naturligtvis eftersom sådana jättar och experter inom sitt område som Yandex, Mail.Ru, Google och Facebook arbetar där. Men, som det visade sig, finns det ingen gräns för perfektion och det finns alltid något att automatisera.

Hur vi samlade in data om reklamkampanjer från webbsajter (den svåra vägen till produkten)
Källa

Kommunikationsgrupp Dentsu Aegis Network Ryssland är den största aktören på den digitala annonsmarknaden och investerar aktivt i teknik och försöker optimera och automatisera sina affärsprocesser. Ett av de olösta problemen med onlineannonseringsmarknaden är uppgiften att samla in statistik om reklamkampanjer från olika internetplattformar. Lösningen på detta problem resulterade i slutändan i skapandet av en produkt D1.Digital (läs som DiVan), vars utveckling vi vill prata om.

Varför?

1. Vid tidpunkten för projektets start fanns det inte en enda färdig produkt på marknaden som löste problemet med att automatisera insamlingen av statistik om annonskampanjer. Det betyder att ingen utom vi själva kommer att tillfredsställa våra behov.

Tjänster som Improvado, Roistat, Supermetrics, SegmentStream erbjuder integration med plattformar, sociala nätverk och Google Analitycs, och gör det även möjligt att bygga analytiska dashboards för bekväm analys och kontroll av annonskampanjer. Innan vi började utveckla vår produkt försökte vi använda några av dessa system för att samla in data från webbplatser, men de kunde tyvärr inte lösa våra problem.

Det största problemet var att de testade produkterna var baserade på datakällor, visade placeringsstatistik per webbplats och inte gav möjlighet att samla statistik om reklamkampanjer. Detta tillvägagångssätt tillät oss inte att se statistik från olika webbplatser på ett ställe och analysera kampanjens tillstånd som helhet.

En annan faktor var att produkterna i de inledande stadierna var riktade mot den västerländska marknaden och inte stödde integration med ryska sajter. Och för de webbplatser med vilka integrationen implementerades, laddades inte alltid alla nödvändiga mätvärden ner med tillräcklig detalj, och integrationen var inte alltid bekväm och transparent, särskilt när det var nödvändigt att få något som inte finns i systemgränssnittet.
I allmänhet bestämde vi oss för att inte anpassa oss till tredjepartsprodukter, utan började utveckla våra egna...

2. Marknaden för onlineannonsering växer från år till år och 2018 gick den om den traditionellt sett största TV-reklammarknaden sett till reklambudgetar. Så det finns en skala.

3. Till skillnad från TV-reklammarknaden, där försäljningen av kommersiell reklam är monopoliserad, finns det många enskilda ägare av reklamlager av olika storlekar som verkar på Internet med sina egna reklamkonton. Eftersom en reklamkampanj som regel körs på flera sajter samtidigt, för att förstå annonskampanjens tillstånd, är det nödvändigt att samla rapporter från alla sajter och kombinera dem till en stor rapport som visar hela bilden. Det betyder att det finns potential för optimering.

4. Det verkade för oss att ägarna av annonsinventering på Internet redan har infrastrukturen för att samla in statistik och visa dem i reklamkonton, och de kommer att kunna tillhandahålla ett API för dessa data. Det betyder att det är tekniskt möjligt att implementera det. Låt oss säga direkt att det visade sig inte vara så enkelt.

Generellt sett var alla förutsättningar för genomförandet av projektet självklara för oss, och vi sprang för att väcka projektet till liv...

Storslagen plan

Till att börja med bildade vi en vision om ett idealiskt system:

  • Annonskampanjer från företagssystemet 1C bör automatiskt laddas in i det med deras namn, perioder, budgetar och placeringar på olika plattformar.
  • För varje placering inom en annonskampanj bör all tänkbar statistik laddas ned automatiskt från de sajter där placeringen sker, såsom antal visningar, klick, visningar osv.
  • Vissa annonskampanjer spåras med hjälp av tredjepartsövervakning av så kallade adserving-system som Adriver, Weborama, DCM, etc. Det finns också en industriell internetmätare i Ryssland - Mediascope-företaget. Enligt vår plan ska även data från oberoende och industriell övervakning automatiskt laddas in i motsvarande reklamkampanjer.
  • De flesta reklamkampanjer på Internet är inriktade på vissa målåtgärder (köp, ring, anmäl dig till en provkörning etc.), som spåras med hjälp av Google Analytics, och statistik för vilka också är viktiga för att förstå kampanjens status och bör laddas in i vårt verktyg.

Den första pannkaka är klumpig

Med tanke på vårt engagemang för flexibla principer för mjukvaruutveckling (agil, allt), beslutade vi att först utveckla en MVP och sedan gå mot det avsedda målet iterativt.
Vi bestämde oss för att bygga MVP baserat på vår produkt DANBo (Dentsu Aegis Network Board), som är en webbapplikation med allmän information om våra kunders reklamkampanjer.

För MVP förenklades projektet så mycket som möjligt vad gäller genomförandet. Vi har valt ut en begränsad lista med plattformar för integration. Dessa var huvudplattformarna, såsom Yandex.Direct, Yandex.Display, RB.Mail, MyTarget, Adwords, DBM, VK, FB och de viktigaste annonssystemen Adriver och Weborama.

För att få tillgång till statistik på webbplatser via API:et använde vi ett enda konto. En kundgruppschef som ville använda automatisk insamling av statistik på en reklamkampanj var tvungen att först delegera åtkomst till nödvändiga reklamkampanjer på sajter till plattformskontot.

Nästa är systemanvändaren DANBo var tvungen att ladda upp en fil av ett visst format till Excel-systemet, som innehöll all information om placeringen (reklamkampanj, plattform, format, placeringsperiod, planerade indikatorer, budget etc.) och identifierare för motsvarande reklamkampanjer på webbplatser och räknare i annonssystem.

Det såg ärligt talat skrämmande ut:

Hur vi samlade in data om reklamkampanjer från webbsajter (den svåra vägen till produkten)

Den nedladdade informationen sparades i en databas, och sedan samlade separata tjänster in kampanjidentifierare på webbplatser från dem och hämtade statistik om dem.

För varje sajt skrevs en separat Windows-tjänst, som en gång om dagen gick under ett tjänstkonto i sajtens API och laddade ner statistik för specificerade kampanj-ID:n. Samma sak hände med adserving-system.

Den nedladdade informationen visades på gränssnittet i form av en liten anpassad instrumentpanel:

Hur vi samlade in data om reklamkampanjer från webbsajter (den svåra vägen till produkten)

Oväntat för oss började MVP arbeta och började ladda ner aktuell statistik om reklamkampanjer på Internet. Vi implementerade systemet på flera klienter, men när vi försökte skala stötte vi på allvarliga problem:

  • Det största problemet var komplexiteten i att förbereda data för att laddas in i systemet. Dessutom måste placeringsdata konverteras till ett strikt fast format innan de laddas. Det var nödvändigt att inkludera enhetsidentifierare från olika platser i nedladdningsfilen. Vi ställs inför det faktum att det är mycket svårt för tekniskt outbildade användare att förklara var man kan hitta dessa identifierare på sajten och var i filen de behöver anges. Med tanke på antalet anställda på avdelningarna som driver kampanjer på sajter och omsättningen resulterade detta i ett enormt stöd från vår sida, vilket vi absolut inte var nöjda med.
  • Ett annat problem var att inte alla reklamplattformar hade mekanismer för att delegera åtkomst till reklamkampanjer till andra konton. Men även om en delegeringsmekanism fanns tillgänglig var inte alla annonsörer villiga att ge åtkomst till sina kampanjer till tredjepartskonton.
  • En viktig faktor var den indignation som väcktes bland användarna över att alla planerade indikatorer och placeringsdetaljer som de redan anger i vårt 1C redovisningssystem, måste de återinföra DANBo.

Detta gav oss idén att den primära informationskällan om placering skulle vara vårt 1C-system, i vilket all data matas in korrekt och i tid (poängen här är att fakturor genereras baserat på 1C-data, så korrekt inmatning av data i 1C är en prioritet för alla KPI). Så här uppstod ett nytt koncept av systemet...

Koncept

Det första vi bestämde oss för att göra var att dela upp systemet för insamling av statistik om reklamkampanjer på Internet i en separat produkt - D1.Digital.

I det nya konceptet bestämde vi oss för att ladda in D1.Digital information om reklamkampanjer och placeringar inom dem från 1C, och sedan hämta statistik från webbplatser och AdServing-system till dessa placeringar. Detta var tänkt att avsevärt förenkla livet för användarna (och, som vanligt, lägga till mer arbete för utvecklarna) och minska mängden support.

Det första problemet vi stötte på var av organisatorisk karaktär och var relaterat till det faktum att vi inte kunde hitta en nyckel eller tecken med vilken vi kunde jämföra enheter från olika system med kampanjer och placeringar från 1C. Faktum är att processen i vårt företag är utformad på ett sådant sätt att reklamkampanjer läggs in i olika system av olika personer (mediaplanerare, inköp etc.).

För att lösa detta problem var vi tvungna att uppfinna en unik hashad nyckel, DANBoID, som skulle länka samman entiteter i olika system, och som ganska enkelt och unikt kunde identifieras i nedladdade datamängder. Denna identifierare genereras i det interna 1C-systemet för varje enskild placering och överförs till kampanjer, placeringar och räknare på alla sajter och i alla AdServing-system. Det tog lite tid att implementera rutinen att sätta DANBoID i alla placeringar, men vi lyckades göra det :)

Sedan fick vi reda på att inte alla sajter har ett API för automatisk insamling av statistik, och även de som har ett API returnerar inte all nödvändig data.

I detta skede beslutade vi att avsevärt minska listan över plattformar för integration och fokusera på de huvudsakliga plattformarna som är involverade i de allra flesta reklamkampanjer. Den här listan inkluderar alla de största aktörerna på annonsmarknaden (Google, Yandex, Mail.ru), sociala nätverk (VK, Facebook, Twitter), stora AdServing och analyssystem (DCM, Adriver, Weborama, Google Analytics) och andra plattformar.

Majoriteten av webbplatserna vi valde hade ett API som gav de mätvärden vi behövde. I de fall där det inte fanns något API eller det inte innehöll nödvändig data använde vi rapporter som skickades dagligen till vårt kontors e-post för att ladda data (i vissa system är det möjligt att konfigurera sådana rapporter, i andra kom vi överens om utvecklingen av sådana rapporter för oss).

När vi analyserade data från olika webbplatser fick vi reda på att hierarkin av enheter inte är densamma i olika system. Dessutom måste information laddas ner i olika detaljer från olika system.

För att lösa detta problem utvecklades SubDANBoID-konceptet. Idén med SubDANBoID är ganska enkel, vi markerar kampanjens huvudenhet på webbplatsen med det genererade DANBoID, och vi laddar upp alla kapslade enheter med unika webbplatsidentifierare och bildar SubDANBoID enligt DANBoID-principen + identifierare på den första nivån kapslad enhet + identifierare för den andra nivån kapslade enheten +... Detta tillvägagångssätt gjorde det möjligt för oss att koppla ihop reklamkampanjer i olika system och ladda ner detaljerad statistik om dem.

Vi var också tvungna att lösa problemet med tillgång till kampanjer på olika plattformar. Som vi skrev ovan är mekanismen för att delegera åtkomst till en kampanj till ett separat tekniskt konto inte alltid tillämplig. Därför var vi tvungna att utveckla en infrastruktur för automatisk auktorisering via OAuth med hjälp av tokens och mekanismer för att uppdatera dessa tokens.

Senare i artikeln kommer vi att försöka beskriva lösningens arkitektur och de tekniska detaljerna för implementeringen mer i detalj.

Lösningsarkitektur 1.0

När vi startade implementeringen av en ny produkt förstod vi att vi omedelbart behövde tillhandahålla möjligheten att ansluta nya webbplatser, så vi bestämde oss för att följa mikrotjänstarkitekturens väg.

När vi utformade arkitekturen separerade vi kopplingar till alla externa system - 1C, reklamplattformar och annonssystem - i separata tjänster.
Huvudtanken är att alla kopplingar till webbplatser har samma API och är adaptrar som för webbplatsens API till ett gränssnitt som är bekvämt för oss.

I centrum för vår produkt står en webbapplikation, som är en monolit som är designad på ett sådant sätt att den enkelt kan demonteras till tjänster. Denna applikation ansvarar för att bearbeta nedladdade data, sammanställa statistik från olika system och presentera dem för systemanvändare.

För att kommunicera mellan kontakterna och webbapplikationen var vi tvungna att skapa en ytterligare tjänst som vi kallade Connector Proxy. Den utför funktionerna Service Discovery och Task Scheduler. Den här tjänsten kör datainsamlingsuppgifter för varje anslutning varje natt. Att skriva ett servicelager var lättare än att koppla en meddelandeförmedlare och för oss var det viktigt att få resultatet så snabbt som möjligt.

För enkelhetens skull och snabbheten i utvecklingen beslutade vi också att alla tjänster ska vara webb-API:er. Detta gjorde det möjligt att snabbt sätta ihop ett proof-of-concept och verifiera att hela designen fungerar.

Hur vi samlade in data om reklamkampanjer från webbsajter (den svåra vägen till produkten)

En separat, ganska komplex uppgift var att sätta upp åtkomst för att samla in data från olika konton, vilket, som vi beslutat, skulle utföras av användare via webbgränssnittet. Den består av två separata steg: först lägger användaren till en token för att komma åt kontot via OAuth och konfigurerar sedan insamlingen av data för klienten från ett specifikt konto. Att skaffa en token via OAuth är nödvändigt eftersom det, som vi redan har skrivit, inte alltid är möjligt att delegera åtkomst till det önskade kontot på sajten.

För att skapa en universell mekanism för att välja ett konto från webbplatser, var vi tvungna att lägga till en metod till connectors API som returnerar JSON Schema, som återges till en form med en modifierad JSONEditor-komponent. På så sätt kunde användarna välja de konton som de skulle ladda ner data från.

För att följa de begärandegränser som finns på webbplatser kombinerar vi förfrågningar om inställningar inom en token, men vi kan behandla olika tokens parallellt.

Vi valde MongoDB som en lagring för laddad data för både webbapplikationen och kopplingarna, vilket gjorde att vi inte kunde oroa oss för mycket över datastrukturen i de inledande utvecklingsstadierna, då objektmodellen för applikationen ändras varannan dag.

Vi fick snart reda på att all data inte passar bra i MongoDB och till exempel är det bekvämare att lagra daglig statistik i en relationsdatabas. Därför, för kopplingar vars datastruktur är mer lämpad för en relationsdatabas, började vi använda PostgreSQL eller MS SQL Server som lagring.

Den valda arkitekturen och teknologierna gjorde det möjligt för oss att bygga och lansera D1.Digital-produkten relativt snabbt. Under två års produktutveckling utvecklade vi 23 kopplingar till webbplatser, fick ovärderlig erfarenhet av att arbeta med tredjeparts API:er, lärde oss att undvika fallgroparna på olika webbplatser, som var och en hade sina egna, bidrog till utvecklingen av API:n på minst 3 webbplatser, hämtade automatiskt information om nästan 15 000 kampanjer och för mer än 80 000 placeringar, samlade in mycket feedback från användare om produktens funktion och lyckades ändra produktens huvudprocess flera gånger, baserat på denna feedback.

Lösningsarkitektur 2.0

Två år har gått sedan utvecklingen startade D1.Digital. Den ständiga ökningen av belastningen på systemet och uppkomsten av fler och fler nya datakällor avslöjade gradvis problem i den befintliga lösningsarkitekturen.

Det första problemet är relaterat till mängden data som laddas ner från webbplatserna. Vi stod inför det faktum att insamling och uppdatering av all nödvändig data från de största sajterna började ta för mycket tid. Till exempel tar det cirka 12 timmar att samla in data från AdRivers annonssystem, med vilket vi spårar statistik för de flesta placeringar.

För att lösa detta problem började vi använda alla typer av rapporter för att ladda ner data från webbplatser, vi försöker utveckla deras API tillsammans med webbplatserna så att hastigheten på dess drift möter våra behov, och parallellisera nedladdningen av data så mycket som möjligt.

Ett annat problem hänför sig till behandlingen av nedladdade data. Nu, när ny placeringsstatistik kommer in, lanseras en process i flera steg för omräkning av mätvärden, som inkluderar att ladda rådata, beräkna sammanställd statistik för varje webbplats, jämföra data från olika källor med varandra och beräkna sammanfattande mätvärden för kampanjen. Detta orsakar mycket belastning på webbapplikationen som gör alla beräkningar. Flera gånger, under omräkningsprocessen, förbrukade applikationen allt minne på servern, cirka 10-15 GB, vilket hade den mest skadliga effekten på användarnas arbete med systemet.

De identifierade problemen och ambitiösa planerna för vidareutveckling av produkten ledde oss till behovet av att ompröva applikationsarkitekturen.

Vi började med kopplingar.
Vi märkte att alla kontakter fungerar enligt samma modell, så vi byggde ett pipeline-ramverk där man bara behövde programmera logiken i stegen för att skapa en koppling, resten var universellt. Om någon anslutning behöver förbättras överför vi den omedelbart till ett nytt ramverk samtidigt som anslutningen förbättras.

Samtidigt började vi distribuera kopplingar till Docker och Kubernetes.
Vi planerade flytten till Kubernetes ganska länge, experimenterade med CI/CD-inställningar, men började flytta först när en anslutning, på grund av ett fel, började äta upp mer än 20 GB minne på servern, vilket praktiskt taget dödade andra processer . Under utredningen flyttades kontakten till ett Kubernetes-kluster, där den till slut fanns kvar, även efter att felet åtgärdats.

Ganska snabbt insåg vi att Kubernetes var bekvämt och inom sex månader överförde vi 7 kontakter och Connectors Proxy, som förbrukar mest resurser, till produktionsklustret.

Efter anslutningarna bestämde vi oss för att ändra arkitekturen för resten av applikationen.
Huvudproblemet var att data kommer från kopplingar till proxyservrar i stora partier, och sedan träffar DANBoID och skickas till den centrala webbapplikationen för bearbetning. På grund av det stora antalet omberäkningar av mätvärden är det en stor belastning på applikationen.

Det visade sig också vara ganska svårt att övervaka statusen för enskilda datainsamlingsjobb och rapportera fel som inträffade i kopplingar till en central webbapplikation så att användarna kunde se vad som hände och varför data inte samlades in.

För att lösa dessa problem utvecklade vi arkitektur 2.0.

Den största skillnaden mellan den nya versionen av arkitekturen är att istället för webb-API:t använder vi RabbitMQ och MassTransit-biblioteket för att utbyta meddelanden mellan tjänster. För att göra detta var vi tvungna att nästan helt skriva om Connectors Proxy, vilket gjorde det Connectors Hub. Namnet ändrades eftersom tjänstens huvudroll inte längre är att vidarebefordra förfrågningar till anslutare och tillbaka, utan att hantera insamlingen av mätvärden från anslutare.

Från den centrala webbapplikationen separerade vi information om placeringar och statistik från sajter till separata tjänster, vilket gjorde det möjligt att bli av med onödiga omräkningar och endast lagra redan beräknad och aggregerad statistik på placeringsnivå. Vi skrev också om och optimerade logiken för att beräkna basstatistik baserad på rådata.

Samtidigt migrerar vi alla tjänster och applikationer till Docker och Kubernetes för att göra lösningen lättare att skala och mer bekväm att hantera.

Hur vi samlade in data om reklamkampanjer från webbsajter (den svåra vägen till produkten)

Vart är vi nu

Proof-of-concept arkitektur 2.0-produkt D1.Digital redo och arbetar i en testmiljö med en begränsad uppsättning kontakter. Allt som återstår att göra är att skriva om ytterligare 20 kontakter till en ny plattform, testa att data laddas korrekt och att alla mätvärden är korrekt beräknade och rulla ut hela designen i produktion.

Faktum är att denna process kommer att ske gradvis och vi måste lämna bakåtkompatibilitet med gamla API:er för att allt ska fungera.

Våra omedelbara planer inkluderar utveckling av nya kopplingar, integration med nya system och att lägga till ytterligare mätvärden till uppsättningen av data som laddas ner från anslutna webbplatser och annonssystem.

Vi planerar också att överföra alla applikationer, inklusive den centrala webbapplikationen, till Docker och Kubernetes. I kombination med den nya arkitekturen kommer detta att avsevärt förenkla driftsättning, övervakning och kontroll av förbrukade resurser.

En annan idé är att experimentera med valet av databas för lagring av statistik, som för närvarande lagras i MongoDB. Vi har redan överfört flera nya kopplingar till SQL-databaser, men där är skillnaden nästan omärkbar, och för aggregerad statistik per dag, som kan begäras under en godtycklig period, kan vinsten vara ganska allvarlig.

I allmänhet är planerna storslagna, låt oss gå vidare :)

Författare till artikeln R&D Dentsu Aegis Network Ryssland: Georgy Ostapenko (shmiigaa), Mikhail Kotsik (hitexx)

Källa: will.com

Lägg en kommentar