Upload
matjaz-pecan
View
528
Download
0
Embed Size (px)
Citation preview
UNIVERZA V LJUBLJANI
Fakulteta za elektrotehniko
Matjaž Pečan
SPLETNA STORITEV SINHRONIZACIJE
KONTAKTNIH PODATKOV V OBLAKU
DIPLOMSKO DELO UNIVERZITETNEGA ŠTUDIJA
Mentor: doc. dr. Boštjan Murovec
Ljubljana, maj 2011
Zahvala
Zahvaljujem se mentorju doc. dr. Boštjanu Murovcu za pomoč, podporo in potrpežljivost
med pisanjem diplomskega dela.
Prav tako se zahvaljujem tudi svojim staršem, ki sta me podpirala med dolgim študijem
in nikoli nista izgubila upanja.
Zahvala gre tudi vsem mojim prijateljem in prijateljicam, ki so mi v času študija dajali
nasvete in mi pomagali.
Povzetek
Diplomsko delo opisuje razvoj spletnega servisa za sinhronizacijo kontaktov med
spletno storitvijo Google Kontakti in socialnim omrežjem Facebook. Storitev samostojno
povezuje uporabnikove kontakte in prijatelje na Facebooku, zatem pa sinhronizira
dostopne kontaktne podatke.
V prvem delu je podan koncept rešitve, kjer so predstavljene osnovne ideje, arhitektura
in utemeljitev načina povezovanja kontaktov s prijatelji. V nadaljevanju je opisana
platforma Google App Engine, na kateri je bil razvit spletni servis, opisan je način
dostopa do uporabnikovih podatkov s protokolom OAuth in uporabljene knjižnice.
V drugem delu je prikazana struktura baze podatkov in njena izvedba, zatem pa je
opisana tudi izvedba servisa z strukturo in optimizacija le-‐tega. Na koncu je prikazana še
analiza stroškov povezanih z vzdrževanjem storitve.
Ključne besede: spletni servis, sinhronizacija, Google App Engine, avtorizacija, OAuth,
Google Kontakti, Facebook, Java
Abstract
The thesis describes the development of a web service for the syncronization of contact
data between the web service Google Contacts and the Facebook social network. The
service automatically matches the user's contacts with his friends on Facebook and
syncronizes the available data.
The first part describes the conceptual idea of the service, its architecture and details the
way contacts and friends are matched. It also describes the Google App Engine platform,
on which the service was created, the way that user data is accessed, the use of OAuth
and the libraries used in the service.
The second part details the structure of the database and its implementation, the
structure of the service itself and the optimization process. In the end a cost analysis is
made.
Keywords: web service, syncronization, Google App Engine, authorization, OAuth,
Google Contacts, Facebook, Java
I
Kazalo
1. UVOD ........................................................................................................................................... 1
2. IDEJNA ZASNOVA STORITVE ............................................................................................... 3 2.1. AVTENTIKACIJA IN AVTORIZACIJA ...................................................................................................... 5 2.2. PRIDOBIVANJE IN SHRANJEVANJE PODATKOV .................................................................................. 6 2.3. POVEZOVANJE KONTAKTOV IN PRIJATELJEV .................................................................................... 7 2.3.1. Ime, priimek in rojstni dan ....................................................................................................... 8 2.3.2. Ime, priimek, rojstni dan in prijateljstvo ........................................................................... 9 2.3.3. Enačenje uporabniških imen ................................................................................................. 10 2.3.4. Ročno povezovanje .................................................................................................................... 10
2.4. SINHRONIZACIJA ................................................................................................................................. 11
3. GOOGLE APP ENGINE .......................................................................................................... 13 3.1. VARNOST IN ZANESLJIVOST .............................................................................................................. 13 3.2. PROGRAMIRANJE ZA GAE V JEZIKU JAVA ....................................................................................... 14 3.3. HRAMBA PODATKOV .......................................................................................................................... 14 3.4. GOOGLE APP ENGINE APIJI .............................................................................................................. 15 3.4.1. Users API ........................................................................................................................................ 15 3.4.2. Memchache API .......................................................................................................................... 16 3.4.3. URL Fetch API .............................................................................................................................. 16
4. DOSTOP DO PODATKOV .................................................................................................... 17 4.1. PROTOKOL OAUTH ............................................................................................................................ 17 4.1.1. Vloge ................................................................................................................................................ 18 4.1.2. Potek avtorizacije ...................................................................................................................... 18 4.1.3. Različice ......................................................................................................................................... 20 4.1.4. Primer izvedbe: Facebook ...................................................................................................... 20
4.2. GOOGLE CONTACTS DATA API ........................................................................................................ 22 4.2.1. Predložitev podatkov za dostop .......................................................................................... 22 4.2.2. Oblikovanje zahtev za pridobitev podatkov ................................................................... 23 4.2.3. Izvedba zahteve in vrnjeni podatki .................................................................................... 23 4.2.4. Zapisovanje podatkov .............................................................................................................. 24
4.3. KOMUNIKACIJA S SOCIALNIM OMREŽJEM FACEBOOK .................................................................. 24 4.3.1. Predložitev OAuth podatkov ................................................................................................. 24
II
4.3.2. Zahteve in branje podatkov ................................................................................................... 25 4.3.3. FQL zahteve .................................................................................................................................. 25 4.3.4. Iskanje ............................................................................................................................................. 26
5. BAZA PODATKOV ................................................................................................................. 27 5.1. STRUKTURA ......................................................................................................................................... 27 5.2. IZVEDBA BAZE PODATKOV ................................................................................................................. 28 5.3. TWIG-‐PERSIST ..................................................................................................................................... 29 5.3.1. Uporaba knjižnice ...................................................................................................................... 29
5.3.1.1. Primer uporabe označb: ContactList.java ............................................................................................. 29 5.3.1.2. Shranjevanje podatkov .................................................................................................................................. 30 5.3.1.3. Nalaganje in iskanje objetkov ..................................................................................................................... 31 5.3.1.4. Učinkovitost ....................................................................................................................................................... 32
6. IZVEDBA SERVISA ................................................................................................................ 33 6.1. STRUKTURA SERVISA .......................................................................................................................... 33 6.1.1. Paketa uporabniškega vmesnika ........................................................................................ 33 6.1.2. Paket ponavljajočih se opravil ............................................................................................. 34 6.1.3. Paket opravil v ozadju ............................................................................................................. 36
6.2. UPORABNIŠKI VMESNIK ..................................................................................................................... 38 6.2.1. Omejitve uporabniškega vmesnika .................................................................................... 38 6.2.2. Komunikacija med uporabniškim vmesnikom in strežnikom ................................ 38 6.2.3. Oblika uporabniškega vmesnika ......................................................................................... 39
6.3. OPTIMIZACIJA SERVISA ...................................................................................................................... 40 6.4. ANALIZA STROŠKOV ............................................................................................................................ 42 6.4.1. Shranjevanje podatkov ............................................................................................................ 43 6.4.2. Prenos podatkov ......................................................................................................................... 43 6.4.3. Procesorski čas ............................................................................................................................ 43 6.4.4. Skupni mesečni strošek ............................................................................................................ 44
7. ZAKLJUČEK ............................................................................................................................. 45
III
Kazalo slik
Slika 2.1 -‐ Prikaz medsebojnih povezav procesov v spletnem storitvi ....................................... 3
Slika 2.2 – Potek avtentikacije in avtorizacije ........................................................................................ 5
Slika 2.3 -‐ Shema procesa pridobivanja kontaktnih podatkov ....................................................... 6
Slika 2.4 – Shema procesa povezovanja kontaktov in uporabnikovih prijateljev .................. 7
Slika 2.5 -‐ Shema procesa sinhronizacije ............................................................................................... 11
Slika 4.1 -‐ prikaz poteka OAuth avtorizacije ........................................................................................ 19
Slika 5.1 -‐ Struktura baze podatkov ......................................................................................................... 27
Slika 6.1 -‐ Struktura paketov client in server ...................................................................................... 34
Slika 6.2 -‐ Proces dodajanja opravil za sinhronizacijo ..................................................................... 35
Slika 6.3 -‐ Časovni in zmogljivostni potek procesa povezovanja kontakta ............................. 40
Slika 6.4 -‐ Časovni in zmogljivostni potek procesa povezovanja kontaktov (100
kontaktov) ................................................................................................................................................. 41
IV
Kazalo tabel
Tabela 6.1 -‐ Cenik storitev Google App Engine ................................................................................... 42
Tabela 6.2 -‐ Podatki testnih uporabnikov storitve ........................................................................... 42
Tabela 6.3 -‐ Projekcija stroškov vzdrževanja storitve ..................................................................... 44
V
Seznam uporabljenih kratic in simbolov
API – Aplikacijski programski vmesnik.
GAE – Google App Engine, aplikacijski strežnik, ki ga oskrbuje podjetje Google.
HTML – HyperText Markup Language, jezik za določitev strukture dokumentov, ki se
prenašajo po spletu in pregledujejo s spletnimi brskalniki.
JSON – JavaScript Object Notation, format izmenjave podatkov.
Memcache – Mehanizem za pospešitev izvajanja programa z uporabo dinamičnega
pomnilnika.
RPC – Remote procedure call, klic oddaljene procedure.
URL – Uniform Resource Locator, internetni naslov, na katerem se nahaja vsebina.
VI
1
1. Uvod Živimo v času mobilnih naprav in komunikacij. Na razpolago imamo veliko število
naprav, ki nam omogočajo hiter dostop do interneta na poti in doma. Istočasno ima
čedalje več uporabnikov večje število takih naprav. Vsaka od njih se povezuje na
svetovni splet in izvaja sinhronizacijo z strežniki za razne namene, naj bo to e-‐pošta,
kontakti ali pa koledar.
Po mnenju uporabnikov mobilnih naprav, je med najpomembnejšimi lastnostmi naprave
čas mobilnega delovanja [1], torej čas, ko je naprava v delovanju brez zunanjega
napajanja. Sinhronizacija z različnimi servisi pomeni izgubo energije, kar morda lahko
upravičimo pri enem servisu, v primeru, da jih uporabljamo več, je potrebna
sinhronizacija za vsak servis posebej. Pri tem ne gre le za podvajanje podatkov, težava je
v dodatnih podatkih (ang. overhead), ki so potrebni za sinhronizacijo zaradi protokolov
in usklajevanja aplikacij. Ti podatki pomenijo dodatno obremenitev procesorja in
komunikacijske poti z zunanjim svetom, kar vodi v izgubo časa delovanja zaradi
nepotrebne porabe energije.
Sinhronizacijo je mogoče izvrševati v oblaku (ang. cloud), saj so storitve v oblaku danes
poceni. Omogočajo uporabo strežniških sistemov, ki so sestavljeni iz tisočev posameznih
strežnikov in so zaradi tega zmožni obdelati velike količine podatkov. Sinhronizacija, ki
se na mobilni napravi izvaja več minut, je v oblaku opravljena v sekundah, hkrati
mobilna naprava prihrani skoraj toliko minut delovanja, saj je ta čas v mirovanju.
Računalništvo v oblaku je internetna tehnologija, za katero je značilno deljenje sredstev,
programske opreme in informacij med več spletnimi storitvami [2]. Uporaba naprav in
programske opreme se v oblaku izvaja na zahtevo, torej ni potrebno imeti zakupljenih
zmogljivosti, obračunajo se le opravljene storitve. Ko razvijamo aplikacije za oblak, se
nam ni potrebno ukvarjati s tehničnimi podrobnostmi storitev, saj so le-‐te skrite za
oblaki.
2
V diplomskem delu prikazujemo razvoj sinhronizacijskega sistema, ki povezuje servis
Google Kontakti [3] in socialno omrežje Facebook [4]. Sistem je sestavljen modularno in
vsebuje dva poglavitna modula. Prvi modul ugotavlja povezave med razpoložljivimi
kontakti in Facebook prijatelji, drugi modul pa izvaja sinhronizacijo.
Zaradi omejitev, ki jih Facebook uveljavlja nad uporabniškimi podatki, je žal mogoče
sinhronizirati le rojstni datum, ime, priimek in fotografijo, a sistem bo z manjšimi
spremembami omogočal sinhronizacijo vseh razpoložljivih podatkov v trenutku, ko bo
Facebook omogočil dostop do njih.
Pri izvedbi smo se zaradi cenovne ugodnosti in visoke zmogljivosti odločili za uporabo
servisa Google App Engine [5] (v nadaljevanju GAE).
3
2. Idejna zasnova storitve V sistemu želimo sinhronizirati podatke med dvema spletnima servisoma, spletnim
omrežjem Facebook in Google Kontakti. Na sliki 2.1 so prikazane povezave med procesi,
ki se izvajajo v spletni storitvi. Vrstni red izvajanja procesov je ponazorjen z številkami
od 1 do 4. Proces 3 se ne more izvesti v primeru, da se še nista izvedla procesa 1 in 2. Na
sliki so s črtkano črto obkroženi procesi, ki se izvajajo na oddaljenih strežnikih in nad
njimi nimamo nadzora. Polne puščice predstavljajo prenos oz. zapisovanje podatkov,
medtem ko prazne puščice predstavljajo izključno prenos podatkov, potrebnih za
avtentikacijo.
Slika 2.1 -‐ Prikaz medsebojnih povezav procesov v spletnem storitvi
Ker so podatki izrazito osebne narave, je poskrbljeno, da so uporabniki ustrezno
avtenticirani, zaradi dostopa do podatkov se izvede tudi avtorizacija, pri kateri
uporabnik spletni storitvi dodeli dostop do svojih podaktov.
4
Ko je uporabnikova istovetnost preverjena in je le-‐ta storitvi dodelil dostop do
podatkov, se prične pridobivanje podatkov, ki so potrebni za nadaljne izvajanje storitve.
Glavni vir podatkov za spletno storitev predstavljajo kontaktni podatki, ki jih ima
uporabnik shranjene v spletni storitvi Google Kontakti, zato storitev le-‐te prenese v
lokalno bazo podatkov, tako da so potem na razpolago za nadaljnjo obdelavo. Pri tem se
zavoljo varovanja podatkov in zmanjševanja porabe plačljivih zmogljivosti izpusti
podatke, ki jih spletna storitev ne potrebuje za delovanje. Sistem naj bo postavljen tako,
da se podatki po prvem prenosu le osvežujejo.
Po pridobitvi podatkov se prične povezovanje uporabnikovih kontaktov z
uporabnikovimi prijatelji (povezavami) na Facebooku. Zato so potrebni kriteriji, ki
povezovanje omogočajo. E-‐poštni naslov vsakega kontakta je edinstven, kar pomeni, da
je le-‐ta z njim v celoti definiran. V primeru, da kontakt ne vsebuje e-‐poštnega naslova, ali
z naslovom ni mogoče najti kontakta v socialnem omrežju Facebook, to predstavlja
problem povezovanja zapisov (ang. record linkage) [6].
Ko so povezave vzpostavljene in zapisane, se tisti kontakti, ki so zanesljivo povezani,
posodobijo s podatki, ki so razpoložljivi na Facebooku. Ker na omrežje samo ni mogoče
zapisovati dodatnih podatkov, je postopek enosmeren.
5
2.1. Avtentikacija in avtorizacija
Postopek se prične, ko uporabnik naloži stran spletne storitve. Potrebno je ugotoviti
istovetnost uporabnika in v primeru, da še ni prijavjen v storitev, tudi vpisati v bazo
uporabnikov. Na sliki 2.2 je prikazan diagram poteka avtorizacije in avtentikacije.
Procesi, ki so obkroženi s prekinjeno črto, potekajo na oddaljenih strežnikih in nad njimi
nimamo nadzora.
Ko je istovetnost uporabnika uspešno ugotovljena (1), se preveri (2), ali je le-‐ta storitvi
dodelil dostop do podatkov pri Google Kontaktih in pri Facebooku. Če uporabnik tega še
ni opravil, ga storitev napoti na avtorizacijo (3), ki se izvede na oddaljenem strežniku. V
primeru uspešne avtorizacije (4) se zapišejo podatki, potrebni za dostop, nakar se
ponovno preveri stanje avtorizacije. V primeru veljavne avtorizacije se proces zaključi in
uporabniku servis prikaže stran, ki potrjuje, da je uspešno zaključil nastavitev storitve.
Slika 2.2 – Potek avtentikacije in avtorizacije
6
2.2. Pridobivanje in shranjevanje podatkov
Podatki, brez katerih ni mogoče povezati kontaktov z njihovimi profili na Facebooku, so
e-‐poštni naslovi, imena in priimki. Zaradi tega se ti podatki prenesejo iz Google
Kontaktov in se shranijo v bazo podatkov. Hkrati se shrani tudi podatek, ki kontakte
enoznačno definira, v tem primeru je to identifikacijski naslov kontakta v Google
Kontakih. Shema procesa je prikazana na sliki 2.3.
Proces se prične s sestavo zahteve (1), ki bo poslana (2) na oddaljeni strežnik. V
primeru, da zahteva vključuje primerne podatke za dostop, oddaljeni strežnik lokalnemu
strežniku vrne (3) zahtevane podatke, v nasprotnem primeru lokalnemu strežniku javi
napako avtorizacije (4). Podatki se na lokalnem strežniku obdelajo (5) in shranijo v bazo
kontaktov (6).
Slika 2.3 -‐ Shema procesa pridobivanja kontaktnih podatkov
7
2.3. Povezovanje kontaktov in prijateljev
S podatki, ki so na rapolago, servis prične postopek povezovanja kontaktov in
uporabnikovih prijateljev na Facebooku. Shema procesa je predstavljena na sliki 2.4.
Proces se prične z branjem kontakta (1), katerega je potrebno povezati, iz baze
kontaktov. S podatki se pripravi zahteva (2), ki se pošlje na oddaljeni strežnik. Na
strežniku se preveri veljavnost avtorizacije (3). Podatki, prejeti z oddaljenega stežnika,
se obdelajo v algoritmu za povezovanje (4). V primeru uspeha pri iskanju povezave (5),
se kontakt z informacijo o povezavi zapiše (6) v bazo kontaktov, v nasprotnem primeru
se proces neuspešno zaključi (7) in ne zapiše nobenih podatkov.
Slika 2.4 – Shema procesa povezovanja kontaktov in uporabnikovih prijateljev
Najbolj preprost algoritem za povezovanje s pomočjo e-‐poštnega naslova preverja, ali
obstaja povezava med oddaljenim računom ter kontaktom. V primeru, da e-‐poštni
8
naslov ni na voljo, ali le-‐ta ne predstavlja povezave med kontaktom in oddaljenim
računom, moramo poskusiti najti povezavo na drugačen način.
2.3.1. Ime, priimek in rojstni dan
Ena možnost je iskanje kontakta s pomočjo imena, priimka in rojstnega dne. V tem
primeru se moramo prepričati ali je tako iskanje sploh smiselno, izračunati moramo
verjetnost, da obstajata dve osebi pri katerih so vsi trije podatki enaki.
Verjetnost !(!) , da imata dve osebi rojstni dan na isti dan, imenujemo problem
rojstnega dne, ta je približno [7]:
! ! = 1− ! ! ≈ 1− !!!(!!!)/(! × !"#)
Pri čemer n predstavlja število oseb ki jih obravnavamo.
V našem primeru upoštevamo tudi letnico rojstva, kar število možnih stanj poveča;
modificirana enačba se glasi:
!! ! = 1− ! ! ≈ 1− !!!(!!!)/(! × !"# × !)
Kjer l predstavlja število let, ki jih privzamemo kot okvir pri izračunu.
Sedaj moramo ugotoviti še število oseb n, ki jih obravnavamo v povezavi z našim
problemom. Predpostavimo, da so imena in priimki nepovezane spremenljivke, zato
lahko iz podatkov [8] Statističnega Urada Republike Slovenije za najpogostejša imena in
priimke razberemo, da je najpogostejše ime Marija, s 69.314 ponovitvami. Najpogostejši
priimek pa je Novak, z 11.311 ponovitvami.
Predpostavimo, da je pogostost imena Marija med ljudmi s priimkom Novak enaka kot
za celotno prebivalstvo Republike Slovenije. Potemtakem je:
! = 11.311×69.3142.032.362 = 385,76 ≅ 386
V primeru, da to uporabimo v enačbi in privzamemo časovni okvir 10 let, dobimo
verjetnost:
9
!!" 386 ≅ 0,9999 = 99,99%
Če privzamemo časovni okvir 100 let je rezultat:
!!"" 386 ≅ 0,8694 = 86,94%
Zaključimo, da je verjetnost enakosti vseh treh podatkov, v primeru Marije Novak, zelo
visoka, zaradi česar ti podatki niso zadostni za enoznačno določitev osebe v Sloveniji.
Ta obravnava sicer predstavlja najslabši možni izid, ki pa je v našem primeru
najpomembnejši, saj moramo biti prepričani, da kontakt in povezava na socialnem
omrežju Facebook predstavljata isto osebo.
2.3.2. Ime, priimek, rojstni dan in prijateljstvo
Če prejšnji primer pogledamo ožje, torej mu dodamo še zahtevo, da mora oseba biti
uporabnikov prijatelj v okviru Facebooka, lahko ugotovimo, da se verjetnost močno
spremeni.
V povprečju ima uporabnik na socialnem omrežju Facebook 120 prijateljev [9]. Torej se
število oseb, ki jih moramo obravnavati v enačbi drastično zmanjša. Sedaj ne
obravnavamo več celotnega prebivalstva Slovenije. V primeru, da bi predpostavke glede
imen in priimkov uporabili sedaj, bi ugotovili, da je v tem primeru:
! =11.3112.032.362×
69.3142.032.362×120 = 0,0227 ≅ 0
Verjetnost, da se med našimi prijatelji nahaja Marija Novak je namreč majhna.
Zato se bomo problema rojstnega dne poslužili drugače, uporabili ga bomo za izračun
števila ljudi, potrebnih za verjetnost ponovitve 0,1 %. Zato uporabimo enačbo [7]:
!(!; 365×!) ≈ 2×365×!× ln1
1− !
Kjer n predstavlja število ljudi, l predstavlja letni okvir, p pa predstavlja verjetnost. V
primeru p=0,1% je:
10
! 0,001; 365×10 ≈ 2.7
Torej moramo v primeru časovnega okvira 10 let, v katerem se pojavljajo rojstni dnevi
prijateljev, imeti skoraj tri prijatelje z enakim imenom in priimkom, zato da bi bila
verjetnost enakosti njihovih podatkov 0,1%. Ker menimo, da to predstavlja dovolj
majhno verjetnost ponovitve pri določanju povezav med kontakti in prijatelji na
socialnem omrežju Facebook, bomo ta princip uporabili tudi v našem servisu.
2.3.3. Enačenje uporabniških imen
Poleg predstavljenih možnosti, bi lahko povezavo poskusili določiti tudi z enačenjem
uporabniških imen, vendar bi morali prej izračunati verjetnost, da uporabniško ime res
predstavlja isto osebo [6]. Ker je ta problem prekompleksen, smo se odločili, da te
metode ne bomo vključili.
2.3.4. Ročno povezovanje
Uporabniku lahko tudi omogočimo, da ročno postavi povezave. Pri tem mu pomagamo
tako, da poiščemo spisek prijateljev na socialnem omrežju Facebook, ki so možne
povezave za dani kontakt. Zatem v uporabniškem vmesniku omogočimo uporabniku
pregled teh kontaktov in vzpostavitev povezav.
11
2.4. Sinhronizacija
Ko je povezovanje kontaktov zaključeno, se lahko prične sinhronizacija. Le-‐ta je
enosmerna, saj podatkov prijateljev na Facebooku ni mogoče spreminjati. Med
sinhronizacijo se pridobijo podatki iz Google Kontaktov in iz Facebooka. Postopek je
prikazan na sliki 2.5. Najprej se pripravita podatkovni zahtevi (1) za oba spletni storitvi.
Oddaljena strežnika preverita istovetnost zahtev (2) in v primeru, da so zahteve
istovetne, vrneta zahtevane podatke (3). Preneseni podatki se primerjajo (4) in po
potrebi se sproži postopek posodobitve. V okviru postopka posodobitve se pripravi
zahteva za posodobitev (5), ki se pošlje na oddaljeni strežnik storitve Google Kontakti.
Ta potrdi spremembo (6) in proces sinhronizacije se uspešno zaključi.
Slika 2.5 -‐ Shema procesa sinhronizacije
12
13
3. Google App Engine Google App Engine omogoča pogon spletnih storitev na Google infrastrukturi [5].
Storitve je mogoče napisati v več programskih jezikih, izmed katerih sta najbolje
podprta Java in Python. Z uporabo prevajalnikov ali interpreterjev, ki podpirajo
izvajanje na JVM (Java Virtual Machine) [10], je mogoče uporabiti tudi druge jezike, ki se
uporabljajo za razvijanje spletnih aplikacij: JavaScript, Ruby ali Scala.
GAE je še posebej zanimiv zaradi nizkih vstopnih stroškov, saj so osnovne storitve na
razpolago brezplačno in je zaradi tega primeren za projekte z omejenimi finančnimi
sredstvi.
Glavne prvine okolja GAE so:
• dinamične spletne vsebine s podporo za večino spletnih tehnologij,
• trajna hramba podatkov s poizvedbami, razvrščanjem in transakcijami,
• avtomatsko skaliranje sistema in prerazporeditev obremenitev,
• APIji za avtentikacijo uporabnikov z uporabo Google računov ter pošiljanje e-‐
pošte,
• lokalno razvojno okolje za simulacijo GAE na osebnem računalniku,
• čakalne vrste opravil (ang. task queues), ki omogočajo izvajanje opravkov
neodvisno od spletnih zahtevkov,
• nastavljanje ponavljajočih se opravil (ang. cronjobs), ki se izvajajo ob želenih
trenutkih.
3.1. Varnost in zanesljivost
Vse GAE aplikacije delujejo v peskovniku (ang. sandbox), torej so ločene od
operacijskega sistema na katerem tečejo. Ker je aplikacija ločena od strežnika, je mogoča
tudi dinamična uporaba večih strežnikov za aplikacjio, kar pomeni višjo zanesljivost
aplikacije ob velikih zahtevah. V tem pogledu so vse GAE aplikacije virtualizirane.
14
Tak način delovanja prinaša tudi omejitve:
• aplikacije ne morejo neposredno dostopati do podatkov na drugih internetnih
straneh, temveč so primorane za to uporabiti APIje, ki so na razpolago v okolju
GAE (primer: pridobivanje podatkov na internetu ter pošiljanje e-‐pošte),
• aplikacije ne morejo zapisovati podatkov v datotečni sistem; namesto tega lahko
uporabljajo storitev za zapis podatkov (datastore)
• aplikacije lahko tečejo samo kot odziv na spletno zahtevo, kot opravilo v vrsti ali
pa ponavljajoče se opravilo. V primeru spletne zahteve se mora aplikacija s
podatki odzvati najkasneje v 30 s, medtem ko je v primeru ostalih opravil
(opravila iz čakalnih vrst ter ponavljajoča opravila) ta omejitev 10 min [11].
3.2. Programiranje za GAE v jeziku Java
Izvedba JVM v GAE omogoča uporabo standardnih Java knjižnic, torej v večini primerov
ni potrebno spreminjati izvorne kode, če prenašamo obstoječe spletne aplikacije na GAE.
Večja težava se pojavi, ko želimo aplikacijo, ki teče na običajnem operacijskem sistemu,
prenesti na GAE.
Sama arhitektura sistema prisili razvijalca v uporabo spletnih tehnologij za vse procese,
ki jih izvede v programski kodi. Zaradi stabilnosti sistema so postavljene tudi časovne
omejitve izvajanja posameznih operacij. Operacije ki se izvajajo kot posledica spletne
zahteve, se morajo izvesti v največ 30 s, medtem ko pa se lahko operacije, ki se izvajajo
zaradi klicev APIja za opravila (Tasks API) ali pa kot ponavljajoča se opravila (cronjobs),
izvajajo do 10 min [11].
Pri programiranju moramo biti pozorni na GAE implementacijo standarnih Java knjižnic,
saj se ta lahko razlikuje v zmogljivostih, kar nam lahko oteži izvedbo.
3.3. Hramba podatkov
Podatki se shranjujejo na porazdeljenem hrambenem sistemu, ki je izjemno prilagodljiv,
zaradi česar se lahko naša aplikacija hitro odzove na povečane zahteve, pa naj bo to
obdelava večje količine podatkov, ali povečano število uporabnikov. Ker potrebe po
15
shranjevanju podatkov niso pri vseh projektih enake, sta omogočena dva principa
shranjevanja podatkov [12]:
• sistem gospodar / suženj (ang. Master/Slave): poudarek je na razpoložljivosti
podatkov, do njih dostopamo hitreje, vse to pa na račun zanesljivosti,
• sistem z visoko stopnjo podvajanja (ang. high replication datastore): poudarek je
na zanesljivosti hrambe podatkov, podatki so na razpolago tudi med izjemnimi
razmerami, a je ta sistem dražji in v določenih primerih se zahteve počasneje
izvajajo.
Hramba podatkov je izjemno konsistentna in deluje vzporedno, pri tem pa se konflikti v
primeru zapisa v isto celico rešujejo z optimističnim nadzorom večopravilnosti [13]
(ang.: optimistic concurrency control -‐ OCC).
Pri OCC predpostavljamo, da bo pogostost hkratnega dostopa do podatkov in
spreminjanja le-‐teh s strani večih uporabnikov majhna. Zato dostopa do podatkov ne
zaklepamo in omogočamo vzporeden dostop. Zaradi ohranjanja konsistence podatkov
smo primorani zavrniti zahtevo po zapisu podatkov s strani uporabnika, če je bil
podatek spremenjen med časom, ko je uporabnik podatek prebral, in časom, ko ga
poskuša zapisati. To je največkrat izvedeno tako, da imamo poleg podatka samega še
ključ, ki predstavlja verzijo podatka in ob zapisu preverimo verzijo podatka ter
zavrnemo zapis v primeru, da obstaja novejši podatek.
3.4. Google App Engine APIji
Na razpolago imamo več aplikacijskih programskih vmesnikov. V nadaljevanju bomo
opisali tiste, ki smo jih uporabili pri izvedbi sinhronizacijskega servisa.
3.4.1. Users API
GAE omogoča uporabo Google računov za avtentikacijo, kar omogoča storitvam hitro
integracijo z drugimi Google storitvami, predvsem pa razreši težavo shranjevanja gesel,
saj celoten postopek izvaja Google. Hkrati je zaradi globoke integracije GAE z Google
računi mogoče omogočiti dostop do administrativnih delov aplikacije samo skrbnikom
aplikacije.
Do podatkov o uporabniku dostopamo preko Users API [14], pri čemer imamo dostop do
enolične identifikacijske številke, e-‐poštnega naslova uporabnika in njegovega vzdevka.
16
3.4.2. Memchache API
Memcache API [15] omogoča shranjevanje podatkov v delovni pomnilnik, kar omogoča
hitrejši dostop do podatkov. Memcache je v Google App Engine izveden v skladu s
specifikacijo JSR 107 [16], dostop do APIja pa je mogoč z uporabo knjižnice
net.sf.jsr107cache.
V našem projektu je dostop do Memcache APIja še posebej pomemben, ker v njem
uporabljamo veliko podatkov, ki so shranjeni v trajnem pomnilniku, do katerega so
dostopi časovno in zmogljivostno zahtevni, z uporabo Memchache funkcije pa
zmanjšamo število klicev branja trajnega pomnilnika tako, da podatke preberemo
enkrat in jih shranimo v delovni pomnilnik za kasnejši dostop.
Dinamični pomnilnik je izveden tako, da shranjeni podatki ostanejo v njem dokler je to
mogoče, oz. dokler ne prične zmanjkovati prostora in se podatki pričnejo izločati iz
njega. Zato moramo pred vsakim prevzemom podatka iz dinamičnega pomnilnika
preveriti, ali podatek še vedno obstaja. V nasprotnem primeru bomo prisiljeni podatek
prebrati iz trajnega pomnilnika.
3.4.3. URL Fetch API
URL fetch API [17] omogoča prenos podatkov z drugih storitev ali strani na spletu.
Dostop je izveden s pomočjo java.net knjižnice, ki ima ozadje izvedeno z nizkimi Google
App Engine funkcijami. To pomeni, da lahko za pridobivanje podatkov uporabimo
izvorno kodo, ki je enaka kot v običajnem Java okolju.
Če se odločimo za to pot, izgubimo dostop do določenih funkcij, ki v tej izvedbi niso
dostopne. Ne moremo namreč preveriti, kakšen je bil odziv spletnega servisa, do
katerega dostopamo. Bolj natančno, z uporabo java.net knjižnice ne moremo ugotoviti,
ali je bila zahteva izvedena uspešno (koda odgovora strežnika 2xx [18]), ali je prišlo do
napake (v našem primeru to predstavlja koda odgovora strežnika 400). Zaradi tega smo
v našem sistemu uporabili nizkonivojski API (ang. low-‐level API), ki omogoča večjo
fleksibilnost na račun višje kompleksnosti programa.
17
4. Dostop do podatkov Za dostop do uporabnikovih podatkov, v tem primeru so to podatki Google Kontaktov in
Facebooka, je potrebno spletni servis pooblastiti za dostop.
To je mogoče izvesti z direktno avtentikacijo uporabnika z njegovim uporabniškim
imenom in geslom, ki ju shranimo v svojo bazo podatkov. Bolje je, če uporabimo
avtentikacijo preko protokola OAuth [19], ki nam omogoča dostop do podatkov
uporabnika brez njegovega gesla, hkrati pa ima uporabnik vedno možnost ta dostop
preklicati, ne da bi zaradi tega bil primoran spremeniti geslo za dostop do zunanje
storitve.
4.1. Protokol OAuth
V tradicionalnem modelu avtentikacije odjemalec-‐strežnik, lastnik podatkov
(uporabnik) potrdi svojo istovetnost z uporabniškim imenom in geslom. V primeru da
potrebuje dostop do teh podatkov odjemalec podatkov (namizna aplikacija, spletni
servis, itd.), je v tem modelu lastnik podatkov primoran svoje dostopne podatke, torej
uporabniško ime in geslo, predati odjemalcu podatkov, ki jih shrani za nadaljno
uporabo. Tak model prinaša mnoge težave:
• odjemalci podatkov so primorani hraniti uporabnikove dostopne podatke,
praviloma v nešifrirani obliki,
• za avtorizacijo z geslom so potrebni dodatni strežniki, kljub temu da tak način
avtorizacije ni varen,
• odjemalci praviloma pridobijo širši dostop do uporabnikovih podatkov, kot je
potrebno za delovanje aplikacije – v našem primeru potrebujemo dostop samo do
storitve kontaktov; če bi uporabljali uporabniško ime in geslo, bi pridobili dostop
do vseh uporabnikovih podatkov,
• lastniki podatkov ne morejo preklicati dostopa do le-‐teh za posamično aplikacijo,
primorani so preklicati dostop za vse aplikacije s spremembo gesla.
Protokol OAuth rešuje te težave z uvedbo novega avtorizacijskega nivoja in strogo
ločitvijo vloge lastnika podatkov in odjemalca, ki do podatkov dostopa. V zahtevi OAuth
odjemalec zaprosi za dostop do podatkov in v ta namen prejme podatke za dostop, ki se
razlikujejo od uporabnikovih.
18
Aplikacija do podatkov uporabnika ne dostopa z geslom, temveč za ta dostop zaprosi
avtorizacijski strežnik za žeton za dostop (ang. access token), v obliki tekstovnega
zapisa, v katerem so zapisani trajanje veljavnosti žetona, njegov namen in drugi
dostopni podatki. Izdajo tega žetona uporabnik potrdi in na ta način aplikaciji omogoči
dostop do zahtevanih podatkov.
4.1.1. Vloge
Protokol OAuth vpeljuje štiri vloge, ki skupaj omogočajo dostop do zaščitenih podatkov,
ki zahtevajo avtorizacijo za dostop:
• lastnik podatkov: subjekt, ki ima pravico dodeliti dostop do zaščitenih podatkov,
• podatkovni strežnik: strežnik, ki hrani zaščitene podatke,
• odjemalec: aplikacija ali storitev, ki zahteva zaščitene podatke v imenu
uporabnika,
• avtorizacijski strežnik: strežnik, ki dodeli odjemalcu žeton za dostop po uspešni
avtentikaciji lastnika podatkov in avtorizaciji dostopa.
4.1.2. Potek avtorizacije
Slika 4.1 prikazuje potek OAuth avtorizacije in interakcije med štirimi vlogami:
a) odjemalec zaprosi za avtorizacijo s strani lastnika podatkov. Zahteva se lahko
izvede neposredno z lastnikom podatkov, zaželjeno pa je, da se avtorizacija
izvede preko avtorizacijskega strežnika,
b) odjemalec prejme potrditev avtorizacije, ki predstavlja avtorizacijo s strani
lastnika podatkov. Tip potrditve zavisi na metodi, ki je bila uporabljena s strani
odjemalca in je podprta s strani avtorizacijskega strežnika,
c) odjemalec zahteva žeton za dostop s tem, da izvede avtentikacijo z
avtorizacijskim strežnikom z uporabo podatkov odjemalca (le ti so bili
pridobljeni vnaprej) in hkrati predloži potrditev avtorizacije s strani lastnika
podatkov,
d) avtorizacijski strežnik ugotovi istovetnost odjemalčevih podatkov in potrditve
avtorizacije ter v primeru, da so le-‐ti veljavni, izda žeton za dostop,
e) odjemalec zahteva zaščitene podatke od podatkovnega strežnika in se predstavi z
žetonom za dostop,
19
f) podatkovni strežnik preveri istovetnost žetona za dostop in v primeru, da je le-‐ta
veljaven, dovoli dostop do podakov.
odjemalec
lastnik
podatkov
avtorizacijski
strežnik
podatkovni
strežnik
avtorizacijska zahteva
potrditev avtorizacije
potrditev avtorizacije
in podatki odjemalca žeton za dostop
žeton za dostop
zaščiteni podatki
(a)
(b)
(c)
(d)
(e)
(f)
Slika 4.1 -‐ prikaz poteka OAuth avtorizacije
20
4.1.3. Različice
Protokol OAuth je specifikacija, ki jo razvija IETF (Internet Engineering Task Force) [20]
(v okviru Internet Society [21]). Specifikacija še ni dokončna, v času pisanja tega dela se
nahaja v 13. verziji [19] (izdani 16 februarja 2011). Tudi zato se izvedenke, ki se
pojavljajo v uporabi, med seboj razlikujejo. Izvedenki, ki ju uporabljata Google in
Facebook, temeljita na 10. verziji specifikacije. Obe izvedbi imata dobro dokumentacijo,
pri Google izvedbi pa je na razpolago obširen API, kar zelo poenostavi izvedbo. Facebook
je prenehal s podporo svojemu Java APIju maja 2008, zaradi tega smo OAuth
avtentikacijo morali izvesti sami.
4.1.4. Primer izvedbe: Facebook
Avtorizacijski postopek pričnemo tako, da uporabnika preusmerimo na naslov [22]:
Če
podrob
no
analizir
amo povezavo, vidimo, da je sestavljena iz več delov:
• začetni del https://www.facebook.com/dialog/oauth je naslov avtorizacijskega
strežnika,
• del za vprašajem je zahteva, v kateri so zapisani podatki o odjemalcu:
o identifikacijska številka aplikacije: client_id=154494971275090,
o povratna povezava: redirect_uri=http://symple-
sync.appspot.com/facebookCallback je naslov, na katerega Facebook
preusmeri uporabnika po uspešni avtentikaciji in avtorizaciji,
o scope=email,offline_access,friends_birthday opisuje pravice [23], ki jih
želimo pridobiti z avtorizacijo:
§ email: pravica branja uporabnikovega e-‐poštnega naslova,
§ offline_access: pravica do dostopa do podatkov tudi ko uporabnik ni
vpisan v Facebook,
§ friends_birthday: pravica do dostopa do datumov rojstnih dni
prijateljev.
https://www.facebook.com/dialog/oauth?client_id=154494971275090
&redirect_uri=http://symple-sync.appspot.com/facebookCallback
&scope=email,offline_access,friends_birthday
21
Naslednji korak je, da Facebook preusmeri uporabnika na naslov, ki je bil podan v
zahtevi. V primeru, da je uporabnik zahtevo potrdil, na konec naslova doda še zahtevo, ki
se glasi ?code=KODA_GENERIRANA_NA_STREŽNIKU. Če uporabnik zahteve ne potrdi, se
odgovor konča z ?error_reason=user_denied&error=access_denied&error_description=The+user+de
nied+your+request, v tem primeru se postopek zaključi neuspešno.
Kodo, ki nam jo strežnik vrne, v primeru potrditve avtorizacije s strani uporabnika,
uporabimo v zahtevi naslovljeni na: https://graph.facebook.com/oauth/access_token?client_id=154494971275090&red
irect_uri= http://symple-sync.appspot.com/facebookCallback
&client_secret=SKRIVNA_KODA&code=KODA_GENERIRANA_NA_STREŽNIKU
Strežnik nam v primeru, da je naša SKRIVNA_KODA pravilna, vrne žeton za dostop, v
primeru da je prišlo do napake, pa vrne HTTP kodo 400 in odgovor v obliki: {"error": {"type": "OAuthException", "message": "Error validating
verification code."}}
Ko uspešno pridobimo žeton, nadaljujemo s korakoma E in F, ki pa ju izvedemo
vsakokrat, ko želimo pridobiti podatke.
Ker smo ob začetku avtorizacije zahtevali pravico do dostopa, ko uporabnik ni prijavljen,
naš žeton velja do preklica s strani uporabnika ali do trenutka, ko uporabnik spremeni
geslo. V nasprotnem primeru bi naš žeton prenehal veljati po kratkem časovnem
intervalu.
22
4.2. Google Contacts Data API
Z avtorizacijo preko OAuth smo pridobili žeton za dostop, ki nam omogoča dostop do
podatkov, ki so na razpolago v spletnem servisu Google Kontakti. Do servisa smo
dostopali preko Google Contacts Data API [27].
Vsa komunikacija z Google servisi poteka preko formata Atom (Atom Syndication
Format). Format Atom definira obliko XML dokumentov, ki se uporabljajo kot viri v
komunikaciji z različnimi storitvami. Ti dokumenti imajo strukturo, določeno s
standardom RFC 4287 [28], standard pa omogoča tudi razširitve, ki jih lahko servis
doda. Zato se format Atom uporablja za strukturiranje širokega spektra podatkov, od
novic na internetnih straneh do podatkov, ki jih shranjujemo na osebnih računalnikih.
4.2.1. Predložitev podatkov za dostop
Za dostop do podatkov moramo najprej izvesti zadnja dva koraka, opisana v protokolu
OAuth. Podatkovnemu strežniku moramo predstaviti naš žeton za dostop ter
identifikacijske podatke naše aplikacije. V primeru servisov Google imamo na razpolago
dve možnosti [29]:
• algoritem HMAC-‐SHA1 [30] (Hash-‐based Message Authentication Code – Secure
Hash Algorithm), ki ne kodira zahtev, a smo zaradi tega primorani ob pridobitvi
žetona za dostop shraniti tudi geslo, ki je vezano nanj. Sicer je osnovna
nastavitev tega bolj preprosta, a je varnost nižja
• algoritem RSA-‐SHA1 [31], pri katerem moramo na Google strežnike najprej
naložiti javni certifikat (ang. public certificate), ki smo ga za ta namen generirali.
Pri tem je varnost višja, saj so vse zahteve šifrirane z našim ključem.
Odločili smo se, da bomo uporabili algoritem RSA-‐SHA1, saj je tako varnost zahtev višja
in je postopek pridobivanja podatkov varnejši.
Za predložitev podatkov za dostop ob zahtevi je treba inicializirati in pripraviti objekt
tipa GoogleOAuthParameters, ki vsebuje podatke o odjemalcu ter dostopne podatke, v
primeru uporabe algoritma RSA-‐SHA1 pa tudi objekt tipa OauthRsaSha1Signer, ki
omogoča varno podpisovanje zahtev, ki se pošiljajo.
Primer:
23
Ti objekti se nato uporabijo pri inicializacji objekta ContactsService kot parametri, ki
omogočijo kasnejšo izvedbo zahtev:
4.2.2. Oblikovanje zahtev za pridobitev podatkov
Zahteve za pridobitev podatkov pripravimo s pomočjo objekta Query, ki je opisan v
knjižnici com.google.gdata.client [32]. Vsaka zahteva mora vsebovati naslov vira, do
katerega želimo dostop. V primeru Google Kontaktov je to
https://www.google.com/m8/feeds/contacts/default/full, ki prestavlja splošni naslov ne
glede na uporabnika, v imenu katerega dostopamo do vira. Primer sestave zahteve:
V primeru lahko vidimo, da najprej ustvarimo objekt feedURL, ki predstavlja povezavo
do vira, do katerega dostopamo. Zatem ustvarimo objekt myQuery, ki predstavlja
poizvedbo. Poizvedbi lahko nastavimo mnoge dodatne kriterije, ki omejujejo število
vrnjenih objektov (setMaxResults), ali pa zahtevajo samo nove objekte (setUpdatedMin).
Na ta način preprečimo prenos nepotrebnih kontaktov.
4.2.3. Izvedba zahteve in vrnjeni podatki
Po pripravi zahteve se ta izvede in pridobljeni podatki se obdelajo. Zahteve izvaja objekt
ContactsService, ki predstavlja vmesnik med servisom in Google strežniki. Tega smo
predhodno inicializirali in mu podali podatke, potrebne za OAuth avtentikacijo .
Servis vrne podatke v objektu tipa ContactFeed, le-‐ta pa predstavlja zbirko vseh
podatkov, ki so bili zahtevani in so bili na razpolago. Do kontaktnih podatkov v objektu
razreda ContactFeed se dostopa preko lastnosti getEntries() v obliki List<ContactEntry>:
GoogleOAuthParameters oauthParameters = new GoogleOAuthParameters(); oauthParameters.setOAuthConsumerKey(“KLJUČ_SERVISA”); oauthParameters.setOAuthConsumerSecret(“SKRIVNA_KODA_SERVISA”); oauthParameters.setOAuthToken(“UPORABNIKOV_ŽETON”); mySigner = new OAuthRsaSha1Signer(ZASEBNI_KLJUČ_SERVISA);
myService.setOAuthCredentials(oauthParameters, mySigner);
URL feedURL = new URL(
"https://www.google.com/m8/feeds/contacts/default/full");
Query myQuery = new Query(feedURL);
myQuery.setMaxResults(2000);
24
V nadaljevanju se podatki obdelajo. Pri tem se preveri ali vsi podatki sploh obstajajo, kar
je mogoče opraviti z uporabo lastnosti ContactEntry objekta, ki se začnejo z has, npr.
hasName(), hasEmailAddresses() in hasBirthday(), tu so navedene tiste lastnosti, ki so
uporabljene v našem servisu.
4.2.4. Zapisovanje podatkov
Kontaktni podatki, zapisani v obliki ContactEntry, se obdelajo in se pošljejo storitvi z
zahtevo za zapis kontakta. To se opravi s klicem metode objekta
ContactsService.update(ContactEntry). Klic ne bo uspel v primeru, da je bil med časom,
ko smo prevzeli kontakt in časom, ko je bila zahteva za zapis oddana, ta spremenjen. V
primeru, da se to dogodi, bo servis odgovoril, da je bila zahteva neuspešna in bomo
primorani kontakt ponovno prenesti in obdelati.
4.3. Komunikacija s socialnim omrežjem Facebook
Ker je Facebook prenehal s podporo svojemu Java API maja 2008, moramo, če želimo
dostopati do podatkov na Facebooku z jezikom Java, uporabiti kakšno od odprtokodnih
rešitev, ki so na razpolago. Tri med njimi so restFB [33], batchFB in facebook-‐java-‐api.
restFB omogoča preprost dostop do podatkov, hkrati pa je prilagoditev programa, v
primeru da želimo uporabiti hitrejši batchFB, manjša. Prav tako je velika prednost
knjižnice restFB, da ni odvisna od zunanjih knjižnic, zaradi česar se hitreje naloži in je
programsko manj zahtevna.
4.3.1. Predložitev OAuth podatkov
V tem primeru je predložitev dostopnih podatkov zelo preprosta, saj je potrebno
predložiti le žeton za dostop, ki ga je servis prejel ob avtorizaciji. Ta preprosta uporaba
je hkrati tudi največja slabost te rešitve, saj smo prisiljeni žeton skrbno varovati, saj
lahko z njim kdorkoli dostopa do podatkov, ki smo jih zahtevali. To se razlikuje od
sistema, ki ga uporablja Google, kjer mora storitev ali aplikacija vedno predložiti tudi
svoje podatke.
resultFeed = myService.getFeed(myQuery, ContactFeed.class);
List<ContactEntry> contactList = resultFeed.getEntries();
25
Objekt za komunikacijo s Facebookom je tipa FacebookClient, ki ob inicializaciji sprejme
vrednost žetona za dostop kot argument:
Na ta način smo identificirali uporabnika in storitev hkrati.
4.3.2. Zahteve in branje podatkov
Za branje posameznih objektov se lahko poslužimo funkcije
facebookClient.fetchObject(arg1, arg2). Z njo izvedemo zahtevo, s katero pridobimo
točno določen objekt. Tako lahko pridobimo podatke o uporabniku:
Objekt User je predefiniran v knjižnici in predstavlja dekodirano obliko objekta JSON, ki
ga prejme knjižnica kot odgovor na zahtevo. Objekte lahko definiramo tudi sami in tako
vežemo podatke direktno na objekte, ki jih že uporabljamo. To izvedemo z označbami, ki
predpisujejo, katera polja objekta odgovarjajo poljem v objektu JSON. Označbe so oblike:
@Facebook(“ime_polja”).
4.3.3. FQL zahteve
Pomemben del socialnega omrežja so povezave, ki jih ima uporabnik. Te lahko
predstavljajo prijatelje, fotografije, dogodke in drugo. Za pridobivanje podatkov
prijateljev, ki ustrezajo specifičnim kriterijem, je potrebno izvesti FQL zahtevo. Zahteve
se izvajajo s poizvedbami FQL [34], ki so primerljive s poizvedbami SQL, a v Facebook
kontekstu. V izvedbah se uporabljajo ukazi kot so SELECT, FROM in WHERE, ki so enaki
kot tisti, ki se uporabljajo v poizvedbah SQL. Razlika je v tem, da so polja, na katerih
poizvedbe izvajamo, definirana vnaprej s strani Facebooka. Primer poizvedbe, ki vrne
vse prijatelje uporabnika:
Polja, ki so zapisana za zahtevo SELECT so polja, ki jih želimo pridobiti. S FROM izrazom
omejimo poizvedbo na določen tip objekta, v našem primeru je to uporabnik. WHERE pa
FacebookClient facebookClient = new DefaultFacebookClient(ŽETON);
User user = facebookClient.fetchObject("me", User.class);
SELECT uid, name, pic_square
FROM user
WHERE uid IN
(SELECT uid2
FROM friend
WHERE uid1 = me())
26
predstavlja pogoje, katerim morajo objekti ustrezati. V našem primeru želimo, da so to
User objekti, ki so povezani z našim uporabnikom.
4.3.4. Iskanje
Z knjižnico restFB nam je preprosto omogočeno tudi iskanje po socialnem omrežju
Facebook. Iskalne zahteve sestavimo in izvedemo s pomočjo metode fetchConnection
(del objekta FacebookClient). Metodi kot prva dva parametra podamo tip iskanja in tip
izhodnega objekta, zatem pa lahko dodamo poljubno količino paramerov, ki jih
sestavimo z metodo Parameter.with(arg1, arg2). Primer takega iskanja v našem servisu,
ki poskuša poiskati uporabnika z danim e-‐poštnim naslovom:
Tu iščemo objekt tipa User, kjer mora biti e-‐poštni naslov tega objekta enak zapisu v
spremenljivki email.
facebookUser = fbClient.fetchConnection("search", User.class, Parameter.with("q", email), Parameter.with("type", "user"));
27
5. Baza podatkov
5.1. Struktura
Bazo podatkov strukturiramo na osnovi dveh glavnih zahtev:
• shranjevanje najmanjše možne količine osebnih podatkov, ki še vedno omogočajo
brezhibno delovanje storitve,
• vsebovanje čim manjše količini vezanih podatkov, da jih ni potrebno nalagati.
Baza je sestavljena iz dveh poglavitnih objektov. Struktura objektov je vidna na sliki 5.1.
Poglavitna objekta predstavljata uporabniške podatke (UserData) in zbirko kontaktov
(ContactList). Primarni ključ je pri obeh enak, vrednost tega je edinstvena
identifikacijska številka uporabnika iz sistema Google Računov.
Slika 5.1 -‐ Struktura baze podatkov
Na objekt ContactList smo vezali kontaktne objekte (GoogleContact), katerih primarni
ključ je edinstvena identifikacijska alfanumerična vrednost, ki je definirana v servisu
Google Kontakti.
28
Na ta način smo omogočili nalaganje uporabniških podatkov, ne da bi nalagali tudi vse
vezane kontakte. Sicer nam to oteži dostop do podatkov, saj moramo vezavo objektov
izvesti sami, a s tem prihranimo veliko časa in plačljivih zmogljivosti.
5.2. Izvedba baze podatkov
Za izvedbo baze podatkov je na rapolago več rešitev. Osnovna rešitev, ki jo omogoča GAE
sam, je uporaba Java Data Objects (JDO) [24]/Java Persistence API (JPA) [25] vmesnikov
Java, ki pa so v GAE izjemno togi. Ker sta JDO/JPA standardna vmesnika do trajno
hranjenih podatkov v jeziku Java, ne vključujeta mnogih zmogljivosti, ki nam jih GAE
ponuja. Zaradi kompleksne uporabe in nefleksibilnosti smo se odločili pregledati druge
možne rešitve, ki omogočajo shranjevanje podatkov na trajen način.
Na razpolago imamo tri vmesnike, ki poenostavljajo uporabo storitve GAE Datastore, to
so Objectify, SimpleDS in twig-‐persist. Medtem ko nam prva dva omogočata
poenostavljeno shranjevanje objektov in vsebujeta veliko funkcij, ki nam lajšajo delo z
storitvijo GAE Datastore, ne poenostavita pa nalaganja in shranjevanja objektov, saj smo
še vedno prisiljeni v uporabo ključev, ki jih moramo sami kodirati in vzdrževati.
V primeru vmesnika twig-‐persist so ključi abstraktirani, torej ni potrebno vzdrževati
zbirke ključev in lahko objekte uporabljamo, kot vse ostale običajne objekte. Zaradi teh
prednosti smo se odločili, da bomo v našem servisu za shranjevanje podaktov uporabili
vmesnik twig-‐persist.
29
5.3. Twig-‐persist
Twig-‐persist [26] je vmesnik za trajno shranjevanje objektov, zgrajen z osnovnimi
funkcijami GAE Datastore API, ki nima mnogih omejitev, ki so prisotne v JDO/JPA-‐GAE
implementaciji trajnega shranjevanja.
Twig-‐persist omogoča:
• paralelne asinhrone klice,
• združevanje večih poizvedb,
• modele Java objektov, ki niso odvisni od datastore storitve.
5.3.1. Uporaba knjižnice
Za uporabo knjižnice najprej prilagodimo tiste Java razrede, ki jih želimo z njo
shranjevati. V ta namen uporabimo posebne označbe (ang. annotations), s katerimi
določimo pomen polj v našem modelu. Označbe so oblike @Označba.
Pozorni moramo biti, da je mogoče vsa polja, ki jih uporabljamo, serializirati – pretvoriti
v tok podatkov (ang. serialize), saj se vsi objekti med shranjevanjem pretvorijo v
serializirano obliko.
5.3.1.1. Primer uporabe označb: ContactList.java
Za primer vzemimo Java razred, poimenovan ContactList, ki predstavlja spisek
kontaktov določenega uporabnika.
package com.nemesis.symple_sync.data; … import com.google.code.twig.annotation.*; public class ContactList implements Serializable { // Identifikacija uporabnika
@Id private String userID; // Spisek uporabnikovih kontaktov @Activate(2) @Child private List<GoogleContact> googleContacts;
// Čas zadnje posodobitve @Embedded @Index private DateTime lastUpdate; … }
30
Najprej uvozimo vse razrede, ki opisujejo uporabljene označbe. Ti razredi se nahajajo v
knjižnici com.google.code.twig.annotation.
V našem primeru imamo štiri različne označbe:
• @Id: ključ, s katerim identificiramo naš objekt. Ta ključ mora biti edinstven za
vsak objekt našega razreda, lahko pa se ponovi v drugih razredih,
• @Child: spisek podrejenih objektov,
• @Embedded: predpis, da se objekt shrani v okviru matičnega objekta in ne kot
posamična entiteta,
• @Activate(2): predpis, v katerih nivojih naj se podrejeni objekt aktivira,
oziroma, kdaj naj se podrejeni objekt naloži iz baze podatkov. V našem primeru
se objekt aktivira samo, če izberemo aktivacijski nivo višji ali enak 2. Na ta način
lahko prevzamemo objekte, ki imajo nase vezane velike količine drugih objektov,
ne da bi podrejene objekte naložili,
• @Index: predpis indeksiranja za polje, ki ga označuje.
Poleg naštetih označb je potrebno omeniti še označbo @Parent, ki predstavlja nadrejeni
objekt. Uporaba te označbe sicer ni nujna, a si zaradi nje laže predstavljamo strukturo
naših podatkov.
5.3.1.2. Shranjevanje podatkov
Najprej je potrebno inicializirati objekt, ki predstavlja podatkovno hrambo
(AnnotationDataStore):
Konstruktorju dodamo parameter false, kar povzroči, da podatkovna hramba indeksira
samo tista polja, ki so označena z označbo @Index. Na ta način prihranimo veliko količino
zmogljivosti.
AnnotationObjectDatastore dataStore =
new AnnotationObjectDatastore(false);
31
Objekte shranjujemo ali prepisujemo z ukazoma
5.3.1.3. Nalaganje in iskanje objetkov
Objekte lahko nalagamo direktno s ključem, če je ta znan:
Tu se obstoječi objekt currentData tipa UserData nadomesti z objektom, ki se naloži iz
baze podatkov, katerega primarni ključ je enak vrednosti userID.
V veliko primerih je treba najti objekte, ki ustrezajo določenim zahtevam. Uporabo
prikazuje naslednji primer iz servisa:
Iskalno zahtevo lahko razdelimo na pomembnejše dele:
• type: predpisuje, kakšen je razred objekta, ki je iskan,
• ancestor: predpisuje, kateri objekt je nadrejen iskanemu objektu, v tem primeru
je to currentContactList,
• addFilter: ta ukaz sprejme tri parametre, prvi predstavlja polje, po katerem
želimo iskati (“matched”), drugi predstavlja tip operacije, ki jo izvedemo, tretji pa
predstavlja vrednost, s katero bomo polje primerjali,
• zahtevo zaključimo z zaključnimi ukazi, ki predpisujejo kaj nam iskanje vrne, v
tem primeru je to število objektov, ki ustrezajo našemu iskanju, kar je zahtevano
z returnCount(), z now() pa je zahtevano, da se podatki prevzemajo sinhrono.
dataStore.store(objekt); // Shranjevanje objekta
dataStore.update(objekt); // Prepisovanje objekta
currentData = dataStore.load(UserData.class, userID);
int unmatchedContacts = dataStore.find().type(GoogleContact.class)
.ancestor(currentContactList)
.addFilter("matched", FilterOperator.EQUAL, false)
.addFilter("tenativeMatches", FilterOperator.EQUAL, false)
.returnCount().now();
32
•
5.3.1.4. Učinkovitost
Pri uporabi twig-‐persist in drugih implementacij vmesnikov s hrambo podatkov v GAE
moramo biti zelo pozorni na učinkovitost operacij. Stremeti moramo k najmanjšemu
možnemu številu klicev DataStore APIja, saj so ti zahtevni in počasni. Prav tako moramo
zaradi načina shranjevanja podatkov v bazo podatkov v svoji aplikaciji preprečevati
hkratno pisanje v isto polje, saj v nasprotnem primeru lahko prihaja do neuspešnih
operacij, ker je bil DataStore prisiljen v zavrnitev vpisa zavoljo vzdrževanja konsistence
podatkov.
33
6. Izvedba servisa Storitev je izvedena v jeziku Java, s specifičnimi rešitvami, ki jih omogoča Google App
Engine. Storitev je zato sestavljena iz mnogih servlet-‐ov [38], objektov programskega
jezika Java, ki omogočajo odgovarjanje na HTTP zahteve in obdelovanje le-‐teh.
6.1. Struktura servisa
Servis je razdeljen v pet poglavitnih paketov. Ti so razdeljeni smiselno, glede na namen
objetkov, ki se v njih nahajajo. Enega od paketov, data, smo že opisali v poglavju o bazi
podatkov. V tem paketu se nahajajo vsi potrebni razredi za shranjevanje in prevzemanje
podatkov. Ostali paketi vsebujejo procese, ki omogočajo delovanje ozadja in
uporabniškega vmesnika spletne storitve.
6.1.1. Paketa uporabniškega vmesnika
Uporabniški vmesnik je sestavljen iz dveh paketov, paket client vsebuje razrede
uporabniškega vmesnika, ki ga uporabnik vidi v svojem brskalniku, medtem ko paket
server vsebuje podporne razrede, ki uporabniškemu vmesniku omogočajo komunikacijo
s strežniškim delom spletne storitve.
Struktura paketov je prikazana na sliki 6.1. Glavni razred paketa client je Symple_sync, ki
skrbi za postavitev uporabniškega vmesnika. Ob obisku spletne strani se izvede glavna
metoda (onModuleLoad()), ki preko vmesnika LoginServiceAsync s klicem RPC zahteva
preverbo, ali je uporabnik prijavljen v sistem. Ta klic na strežniku povzroči izvajanje
razreda LoginServiceImpl, ki izvede preverbo uporabnika in vrne uporabniške podatke, v
primeru da ti obstajajo, v nasprotnem primeru vrne spletni naslov, na katerega je
potrebno napotiti uporabnika, da se le-‐ta lahko prijavi. Vrnjeni podatki se v razredu
Symple_Sync obdelajo in uporabniku se prikaže primerna vsebina; v primeru
prijavljenega uporabnika je to glavna stran (metoda sympleSync()), v nasprotnem
primeru se prikaže stran, ki uporabnika poziva k prijavi (metoda loadLogin()).
34
Slika 6.1 -‐ Struktura paketov client in server
V primeru uspešne prijave sta med podatki, ki jih strežnik vrne uporabniškemu
vmesniku tudi podatka o veljavnosti avtorizacij za Google Kontakte in Facebook. Če
avtorizaciji nista veljavni, vmesnik uporabniku prikaže povezavo, s katero se prične
postopek za avtorizacijo. V primeru, da sta obe avtorizaciji veljavni, vmesnik prikaže
zahvalno sporočilo.
Preostali del uporabniškega vmesnika je namenjem administratorju in prikazuje
uporabnike in statistiko ter omogoča brisanje uporabnikov ali uporabniških podatkov.
Te operacije so izvedene s pomočjo razreda AdminServiceImpl.
6.1.2. Paket ponavljajočih se opravil
Ime paketa ponavljajočih se opravil je cron. V njem se nahajajo vsi razredi, ki
predstavljajo opravila, za katera zahtevamo, da se ponavljajo ob vnaprej določenih urah.
V našem servisu so to naslednji razredi:
• ContactFetcher: zažene opravila za pridobivanje podatkov o uporabnikovih
kontaktih,
• ContactMatcher: zažene opravila za povezovanje uporabnikovih kontaktov z
uporabnikovimi prijatelji na Facebooku,
• ContactSync: zažene opravila za sinhronizacijo podatkov uporabnikovih
kontaktov s podatki, razpoložljivimi na Facebooku.
35
• StatisticsCron: opravilo vodi dnevno statistiko o uporabnikih, beleži število
kontaktov, število prijateljev, število povezanih kontaktov in število možnih
dodatnih povezav
Z izjemo razreda StatisticsCron ti razredi ne opravljajo obdelave podatkov, temveč le
predpišejo obdelavo opravilom iz Java razredov v paketu tasks.
Primer takega delovanja si lahko ogledamo na sliki 6.2. Ponavljajoče opravilo
sinhronizacije (ContactsSync) postavi v čakalno vrsto n opravil za polnjenje čakalne
vrste (SyncQueuer), kjer n predstavlja število uporabnikov.
Slika 6.2 -‐ Proces dodajanja opravil za sinhronizacijo
Opravilo za polnjenje čakalne vrste za vsak kontakt, ki je povezan z uporabnikovim
prijateljem na Facebooku, predpiše opravilo za sinhronizacijo (SyncTask). Tako se ob
vsaki sinhronizaciji ustvari o opravil:
! = !!
!
!!!
36
Poenostavljena izvedba opravila razreda ContactSync v izvorni kodi:
Najprej se iz podatkovne baze pridobijo uporabniški podatki, s katerimi se doda
opravilo za polnjenje čakalne vrste. Pri tem je zahteva sestavljena tako, da je navedena
povezava, na kateri se nahaja opravilo in parameter userID, ki predstavlja edinstveno
identifikacijsko število uporabnika. Nadaljnje operacije so v domeni paketa opravil v
ozadju (tasks).
6.1.3. Paket opravil v ozadju
Paket opravil v ozadju (tasks) vsebuje razrede, ki predstavljajo opravila in se opravljajo
na klic opravil iz paketa cron. Ti razredi so:
• ContactFetcher: na zahtevo opravila razreda cron.ContactFetcher, pridobi podatke
o uporabnikovih kontaktih,
• MatcherQueue: na zahtevo opravila razreda cron.ContactMatcher, napolni čakalno
vrsto z opravili razreda MatcherTask, z namenom povezovanja kontaktov,
• MatcherTask: izvede povezovanje kontaktov in uporabnikovih prijateljev,
• SyncQueuer: na zahtevo opravila razreda cron.ContactSync, napolni čakalno vrsto
sync-‐queue z opravili razreda SyncTask,
• SyncTask: izvede sinhronizacijo podatkov uporabnikovega kontakta s podatki na
Facebooku.
Iterator<UserData> userData = dataStore.find().type(UserData.class) .now();
while (userData.hasNext()) { UserData currentData = userData.next(); if (currentData.isFacebookAuthorizationValid() && currentData.isGoogleAuthorizationValid()) { queue.add(withUrl("/symple_sync/tasks/syncQueuer"
).param("userID", currentData.getUserID())); currentData.setLastSync(); dataStore.update(currentData); } }
37
Poenostavljena izvedba opravila razreda SyncQueuer v izvorni kodi:
Iz baze podatkov se naloži spisek uporabnikovih kontaktov (ContactList). Zatem se
izvede poizvedba, v kateri so zahtevani uporabnikovi kontakti, ki smo jih povezali z
uporabnikovim prijateljem na Facebooku. Opravilo obdela vse kontakte in za vsakega
posebej v vrsto sync-‐queue vstavi opravilo za sinhronizacijo (SyncTask), istočasno z
ukazom cache.put(ključ, kontakt) v dinamični pomnilnik shrani podatke o kontaktu.
Opravilo SyncTask zamenja fotografijo kontakta s tisto, ki je na razpolago na Facebooku,
preveri se pravilnost zapisa imena in priimka kontakta ter v primeru, da je na razpolago
rojstni datum na Facebooku, le-‐tega doda h kontaktu na Google Kontaktih, če ta še ni
prisoten.
ContactList currentContactList =dataStore .load(ContactList.class, userID);
List<GoogleContact> matchedContacts =dataStore.find() .type(GoogleContact.class).ancestor(currentContactList). addFilter("matched", FilterOperator.EQUAL, true) .returnAll().now();
for (GoogleContact currentContact : matchedContacts) { dataStore.activate(currentContact);
cache.put(currentContact.getContactID(), currentContact); String contactID = currentContact.getKey();
queue.add(withUrl("/symple_sync/tasks/syncTask") .param("userID", userID) .param("contactID", contactID));
}
38
6.2. Uporabniški vmesnik
Uporabniški vmesnik je v primeru spletnega servisa spletna stran, ki jo prikažemo v
uporabnikovem brskalniku. Ker v našem primeru uporabljamo v ozadju programski
jezik Java, smo se odločili za uporabo le-‐tega tudi v uporabniškem vmesniku. Za to
imamo na razpolago veliko število ogrodij AJAX (Asynchronous JavaScript And XML
[35]), med drugimi GWT (Google Web Toolkit [36]).
Ogrodja AJAX omogočajo prilagajanje uporabniškega vmesnika brez ponovnega
prevzemanja celotne spletne strani s strani uporabnika. Statični del strani ostaja enak,
medtem ko se dinamični deli prosto spreminjajo in prilagajajo trenutnim podatkom in
zahtevam.
6.2.1. Omejitve uporabniškega vmesnika
Ker uporabniški vmesnik teče v okviru brskalnika, smo omejeni na uporabo razredov in
metod, ki jih je mogoče prevesti v AJAX metode in klice. Vse procesiranje, ki ga izvajamo
v uporabniškem vmesniku, mora biti izvedeno z knjižnicami ogrodja GWT, ki so za to
predvidene. Zaradi tega je potrebno večino operacij izvesti na strežniku, ta omejitev pa
prinaša tudi prednosti, praviloma je to hitrejši odziv uporabniškega vmesnika, ker se
operacije izvajajo asinhrono v ozadju.
6.2.2. Komunikacija med uporabniškim vmesnikom in strežnikom
Komunikacija poteka preko klicev RPC (Remote Procedure Call [37]), ki prenašajo
podatke med strežnikom in brskalnikom. Klici RPC omogočajo abstrakcijo
komunikacijskega vmesnika in tako zelo poenostavijo programiranje, saj se ni potrebno
posvečati vmesnikom, ki podatke prenašajo.
Klice RPC delimo na dva tipa:
• sinhroni: klicatelj čaka na odgovor in medtem se izvajanje na uporabniški stani
ustavi,
• asinhroni: klicatelj v zahtevi definira funkcijo za vračilo podatkov in nadaljuje z
izvajanjem na uporabniški strani.
V ogrodju GWT so mogoči samo asinhroni klici RPC. Tako vmesnik izvede klic RPC in
nadaljuje s prikazovanjem že pridobljenih podatkov, medtem ko se na strežniku izvaja
proces obdelave podatkov. Ko se proces zaključi, strežnik vrne rezultat zahteve
39
uporabniškemu vmesniku, ki rezultat prikaže uporabniku. V tem času ima uporabnik na
razpolago odziven vmesnik, kljub izvajanju zahteve.
6.2.3. Oblika uporabniškega vmesnika
Uporabniški vmesnik oblikujemo s pomočjo datotek CSS (Cascading Style Sheet) na enak
način kot običajno statično spletno stran. Razlika je predvsem v tem, da so objekti
definirani v programskem jeziku Java in niso del statične strani. Vsak objekt ima že v
osnovi definirane oznake, na katere lahko vežemo lastnosti v datotekah CSS, hkrati pa
imamo možnost objektom dodati svoje lastne oznake in tako dodatno prilagoditi videz
strani.
40
6.3. Optimizacija servisa
V GAE je potrebno plačevati za prenos podatkov, procesorski čas in shranjevanje
podatkov. V našem primeru sta najbolj kritična procesorski čas in prenos podatkov, saj
je količina shranjenih podatkov na uporabnika minimalna. Sistem GAE nam javlja
porabo procesorskega časa v milisekundah, ki predstavlja ekvivalent računskih ciklov, ki
jih v tem času opravi procesor 1,2 GHz Intel x86.
Prve izvedbe servisa so uporabljale opravilne vrste za vse procese tako, da se je vsak del
procesa razbil na najmanjšo možno enoto in se izvedel v svojem opravilu. Tako se je v
primeru povezovanja kontaktov za vsak kontakt posebej ustvarilo po eno opravilo.
Proces je bil zelo počasen, hkrati je bilo v administratorskem vmesniku GAE aplikacije
videti, da servis zahteva velike količine plačljivih zmogljivosti že v primeru enega
samega uporabnika.
Z uporabo AppStats [39] za GAE, smo ugotovili kateri del procesa je najpočasnejši.
Posnetek poteka enega opravila, ki poskuša povezati en kontakt, lahko vidimo na
sliki 6.3. Modri pravokotniki predstavljajo čas, ki ga zahteva porabi za izvedbo, medtem
ko rdeči pravokotniki predstavljajo uporabljene plačljive zmogljivosti (procesorski čas).
Kot vidimo se proces v realnem času hitro izvede, a se pri tem porabi velika količina
plačljivih zmogljivosti. Prav tako vidimo, da je največja poraba pri dostopu do baze
podatkov (klici datastore_v3.Get).
Slika 6.3 -‐ Časovni in zmogljivostni potek procesa povezovanja kontakta
Rešitev za ta problem je seveda v tem, da do baze podatkov dostopamo čim manjkrat,
oziroma do nje dostopamo tako, da objekte obdelujemo v skupinah in ne posamično.
41
Opravilo smo zato preuredili tako, da hkrati povezuje po 100 kontaktov. Število
kontaktov smo morali omejiti, saj se lahko v nasprotnem primeru dogodi, da dosežemo
omejitev dolžine izvajanja procesa (10 min). Dostop do baze podatkov v tem primeru
zahteva približno 150% plačljivih zmogljivosti, s tem da smo obdelali 100 kontaktov in
ne enega, kar je razvidno iz slike 6.4. Slika predstavlja potek opravila pri povezovanju
100 kontaktov, potrebno pa je poudariti, da je vmesni del poteka zaradi nazornosti
izpuščen. Ponovno predstavljajo modri pravokotniki realni čas, porabljen za izvedbo
opravila, rdeči pravokotniki pa predstavljajo porabo plačljivih zmogljivosti. Iz slike je
razvidno, da je dostop do podatkov pri enem kontaktu približno tako zahteven kot pri
stotih.
Slika 6.4 -‐ Časovni in zmogljivostni potek procesa povezovanja kontaktov (100 kontaktov)
Podobno težavo smo imeli pri sinhronizacijskem opravilu, saj je dostopalo do vsakega
podatka posebej in tako uporabljalo velike količine plačljivih zmogljivosti. Opravilo smo
optimizirali tako, da smo ob klicu opravila SyncQueuer, ki vstavlja opravila za
sinhronizacijo v vrsto, v dinamični pomnilnik vstavili objekt, ki predstavlja kontakt. Na
ta način podatek preberemo iz baze podatkov le enkrat, kasnejši dostopi pa uporabijo
podatke, ki so shranjeni v dinamičnem pomnilniku. To smo lahko izvedli tako, ker pri
sinhronizaciji kontakta ne zapisujemo nobenih podatkov v bazo.
42
6.4. Analiza stroškov
Če bi želeli spletni servis tržiti, bi morali najprej vedeti, kakšen je strošek le-‐tega na
enega uporabnika. Sicer nam Google pri uporabi GAE podaja brezplačne kvote, a so te za
upravljalca v primeru velike količine uporabnikov zanemarljive.
Trenutno veljavni cenik (uveljavljen 24 februarja 2009 [40]) vsebuje naslednje cene
(vrednosti v € prepračunane po tečajni listi Banke Slovenije dne 29.04.2011 [41]) :
Plačljiva zmogljivost Enota Cena enote Brezplačna kvota
Odhodni prenos podatkov gigazlog 0,08 € (0,12 $) 1 GB / dan
Dohodni prenos podatkov gigazlog 0,067 €
(0,10 $)
1 GB / dan
Procesorski čas ura 0,067 €
(0,10 $)
6,5 ur / dan
Shranjeni podatki gigazlog / mesec 0,10 €
(0,15 $)
1 GB
Tabela 6.1 -‐ Cenik storitev Google App Engine
Za preizkus storitve smo pridobili 7 uporabnikov, katerih podatki so naslednji:
uporabnik število
kontaktov
število
prijateljev
število povezanih
kontaktov
število možnih
povezav
1 989 471 239 196
2 245 235 93 43
3 1073 646 232 315
4 1014 705 291 286
5 244 132 58 40
6 203 485 62 23
7 390 608 84 96
povprečje 628 445 162,5 150,5 Tabela 6.2 -‐ Podatki testnih uporabnikov storitve
Naši uporabniki imajo od 200 do preko 1000 kontaktov in od 130 do 700 prijateljev na
Facebooku. Za izračune privzamemo, da povprečne vrednosti naših uporabnikov
predstavljajo povprečnega uporabnika in izračunamo približen strošek na uporabnika.
43
6.4.1. Shranjevanje podatkov
Poraba podatkov s sedanjimi uporabniki in količino kontaktov se giblje okrog 0,02 GB
pri skupnem številu kontaktov 4158. Povprečna poraba podatkov na kontakt je torej: 0,02 GB4158 = 5 kB/kontakt
Z upoštevanjem povprečnega števila kontaktov na uporabnika lahko izračunamo
zahteve za shranjevanje podatkov na uporabnika:
5×628 = 3167 kB ≅ 0,003 GB
Torej je mesečni strošek na uporabnika za shranjevanje podatkov:
0,003×0,1 € = 0,0003 €
6.4.2. Prenos podatkov
Odhodni in dohodni prenos podatkov je odvisen predvsem od količine povezanih
kontaktov in števila dnevnih sinhronizacij. V trenutni izvedbi servisa se sinhronizacija
izvede 6-‐krat dnevno. Pri trenutnih uporabnikih to pomeni sinhronizacijo 1059-‐ih
kontaktov, torej se mora sinhronizacija dnevno izvesti 6354-‐krat. Če upoštevamo, da je
trenutni dnevni odhodni prenos 0,09 GB in dohodni dnevni prenos 0,06 GB, lahko
določimo da je približna cena prenosa na sinhroniziran kontakt: 0,09 GB6354 ×0,08 €+
0,06 GB6354 ×0,067€ ≅ 1,7×10!!€
Torej je približni mesečni strošek na uporabnika pri šestih dnevnih sinhronizacijah:
1,7×10!! € × 162,5 × 6 × 30 = 0,0516 €
6.4.3. Procesorski čas
Največ procesorskega časa porabimo za povezovanje kontaktov in njihovo
sinhronizacijo. Hkrati je to tudi edina vrednost, ki jo lahko direktno merimo s pomočjo
orodij, ki jih imamo na razpolago. Za povezovanje 100 kontaktov se v sedanji izvedbi
porabi približno 15 s. Torej teoretično za en kontakt porabimo 150 ms.
Tu preverjamo samo kontakte, ki jih še nismo povezali. V našem primeru je povprečje
nepovezanih kontaktov na uporabnika cca. 300, če to vrednost uporabimo za izračun
potrebujemo za obdelavo:
0,150 s × 300 = 45 s = 0,0125 h
44
Sinhronizacija zahteva v povprečju 80 ms na kontakt za sinhronizacijo. V povprečju ima
uporabnik 162,5 povezanih kontaktov in je torej zahtevana količina procesorskega časa,
pri šestih sinhronizacijah na dan:
0,08 s × 162,5 × 6 = 78 s = 0,0216 h
Skupno torej potrebujemo mesečno na uporabnika:
0,0125 h+ 0,0216 h × 0,067€h× 30 = 0,0687 €
6.4.4. Skupni mesečni strošek
Mesečno bomo torej na uporabnika potrebovali približno:
0,0003 €+ 0,0516 €+ 0,0687€ ≅ 0,123 €
Mesečni strošek pri različnih številih uporabnikov torej znaša:
Število uporabnikov Mesečni strošek Mesečni strošek pri upoštevanju brezplačne kvote
100 12,30 € 0 € 1000 123,00 € 55,81 €
10000 1 230,00 € 1133,10 € 100000 12 300,00 € 11989,55 €
Tabela 6.3 -‐ Projekcija stroškov vzdrževanja storitve
Če sedaj upoštevamo količino brezplačno rapoložljivih zmogljivosti, lahko ugotovimo, da
nas omejuje predvsem procesorski čas, saj lahko z brezplačno procesorsko močjo
vzdržujemo približno 190 uporabnikov, v primeru prenosa podatkov se ta številka
povzpne na 1400, prostora za hrambo podatkov pa je dovolj za 330 uporabnikov, če
zahteve ostanejo enake.
45
7. Zaključek V okviru spletnega servisa smo izpolnili vse zahteve, ki so bile postavljene v okviru
naloge. Servis samostojno ugotavlja povezave med uporabnikovimi kontakti in prijatelji
na Facebooku, povezane kontakte pa tudi uspešno sinhronizira. Sinhronizirajo se
kontaktni podatki, do katerih je mogoče dostopati v okviru Facebooka, servis je izveden
tako, da bo v prihodnosti mogoče omogočiti sinhronizacijo dodatnih podatkov, do
katerih bi bil kasneje omogočen dostop.
Ocena mesečnih stroškov na uporabnika v okviru storitve kaže, da bi bili stroški v
primeru javne dostopnosti servisa sprejemljivi in bi bilo mogoče storitev za veliko
število uporabnikov vzdrževati z minimalnimi stroški. Prav tako bi bilo mogoče v
primeru večjega števila uporabnikov optimizirati algoritem za povezovanje kontaktov,
kjer bi lahko povezave, ki bi jih ugotovili, shranili v bazo in jih uporabili pri več
uporabnikih.
Pri testnih uporabnikih in v sedanji izvedbi spletna storitev samostojno poveže 25%
uporabnikovih kontaktov s prijatelji na Facebooku, hkrati pa najde možne povezave še
za 20% kontaktov. Največje težave se pojavljajo pri dostopanju in iskanju podatkov v
okviru Facebooka, saj se vmesniki za dostop do podatkov spreminjajo večkrat letno,
praviloma tako, da programska oprema brez sprememb v izvorni kodi po spremembi
preneha delovati. Prav tako je problem v pridobivanju podatkov, saj so pravila, ki jih
postavlja Facebook, praviloma nedorečena in v večini primerov ne veljajo za vse
aplikacije.
Spletno storitev je mogoče izboljšati z dodatkom uporabniškega vmesnika za ročno
povezovanje kontaktov. Izboljšave so še vedno možne tudi na področju optimizacije, kjer
bi lahko z bolj agresivnim shranjevanjem podatkov v dinamični pomnilnik prihranili
dodatna sredstva in servis tudi pospešili. Sinhronizacija, ki se sedaj izvaja za vse
kontakte ob vsakem klicu, bi se lahko izvajala samo za spremenjene kontakte, prav tako
bi lahko ustvarili sistem, ki bi sinhronizacijo izvajal odzivno, t.j. kot odziv na spremembo
namesto, da se izvaja sinhronizacija ob določenih časovnih terminih. Izboljšave bi bile
možne tudi z dodajanjem drugih spletnih storitev v sinhronizacijo, vstavljanje rojstnih
dni v koledar, sinhronizacija z drugimi socialnimi omrežji.
46
47
Literatura
[1] Matti Haverila, What do we want specifically from the cell phone? An age related study, Telematics and Informatics, vol. In Press, Corrected Proof.
[2] Jure Vrščaj, Razvoj aplikacij na platformi Google App Engine, Diplomska naloga, 2011.
[3] Google Inc., Google Contacts , http://www.google.com/contacts/, 8. april 2011. [4] Facebook , https://www.facebook.com/, 8. april 2011. [5] Google App Engine -‐ Google Code , http://code.google.com/appengine/, 8. april
2011. [6] Daniele Perito, Claude Castelluccia, Mohamed Ali Kaafar, in Pere Manils, How
Unique and Traceable are Usernames?, 1101.5578, jan. 2011. [7] Birthday problem -‐ Wikipedia, the free encyclopedia ,
http://en.wikipedia.org/wiki/Birthday_problem, 9. april 2011. [8] Statistični urad RS -‐ Prebivalstvo, Slovenija, 1. januar 2010 ,
http://www.stat.si/novica_prikazi.aspx?id=3088, 9. april 2011. [9] Inc., Maintained Relationships on Facebook ,
http://www.facebook.com/note.php?note_id=55257228858&ref=mf, 9. april 2011. [10] Tim Lindholm in Frank Yellin, Java(TM) Virtual Machine Specification, 2. izd.,
Prentice Hall, 1999. [11] Google App Engine Blog: App Engine team appearances Winter 2011 ,
http://googleappengine.blogspot.com/2011/01/app-‐engine-‐team-‐appearances-‐winter-‐2011.html, 9. april 2011.
[12] Choosing a Datastore (Java) -‐ Google App Engine -‐ Google Code , http://code.google.com/appengine/docs/java/datastore/hr/, 8. april 2011.
[13] Rod Johnson, Expert one-‐on-‐one J2EE design and development, Indianapolis IN: Wrox, 2003.
[14] Users Java API Overview -‐ Google App Engine -‐ Google Code , http://code.google.com/appengine/docs/java/users/overview.html, 9. april 2011.
[15] Memcache Java API Overview -‐ Google App Engine -‐ Google Code , http://code.google.com/appengine/docs/java/memcache/overview.html, 8. april 2011.
[16] The Java Community Process(SM) Program -‐ JSRs: Java Specification Requests -‐ detail JSR# 107 , http://jcp.org/en/jsr/detail?id=107, 9. april 2011.
[17] URL Fetch Java API Overview -‐ Google App Engine -‐ Google Code , http://code.google.com/appengine/docs/java/urlfetch/overview.html, 9. april 2011.
[18] HTTP/1.1: Status Code Definitions , http://www.w3.org/Protocols/rfc2616/rfc2616-‐sec10.html, 8. april 2011.
[19] Network Working Group, draft-‐ietf-‐oauth-‐v2-‐13 -‐ The OAuth 2.0 Authorization Protocol , http://tools.ietf.org/html/draft-‐ietf-‐oauth-‐v2-‐13, 8. april 2011.
[20] IETF, Internet Engineering Task Force , http://www.ietf.org/, 8. april 2011. [21] Internet Society (ISOC) , http://www.isoc.org/, 9. april 2011. [22] Facebook, Authentication -‐ Facebook Developers ,
https://developers.facebook.com/docs/authentication/, 8. april 2011. [23] Permissions -‐ Facebook Developers ,
https://developers.facebook.com/docs/authentication/permissions/, 8. april 2011. [24] Java Data Objects (JDO) -‐ Home , http://db.apache.org/jdo/, 14. april 2011.
48
[25] The Java Persistence API -‐ A Simpler Programming Model for Entity Persistence , http://www.oracle.com/technetwork/articles/javaee/jpa-‐137156.html, 14. april 2011.
[26] twig-‐persist -‐ Object Datastore for Google App Engine -‐ Google Project Hosting , http://code.google.com/p/twig-‐persist/, 9. april 2011.
[27] Google Contacts Data API -‐ Google Code , http://code.google.com/apis/contacts/, 10. april 2011.
[28] Network Working Group, M. Nottingham, Ed., in R. Sayre, Ed., RFC 4287 -‐ The Atom Syndication Format , http://tools.ietf.org/html/rfc4287, 8. april 2011.
[29] OAuth in the Google Data Protocol Client Libraries -‐ Google Data Protocol -‐ Google Code , http://code.google.com/apis/gdata/docs/auth/oauth.html, 8. april 2011.
[30] Hugo Krawczyk, Ran Canetti, in Mihir Bellare, HMAC: Keyed-‐Hashing for Message Authentication , http://tools.ietf.org/html/rfc2104, 3. maj 2011.
[31] A. Shamir in L. Adleman, A method for obtaining digital signatures and public-‐key cryptosystems, Communications of the ACM, vol. 21, 1978, str. 120–126.
[32] Developer’s Guide: Java -‐ Google Contacts Data API -‐ Google Code , http://code.google.com/apis/contacts/docs/3.0/developers_guide_java.html, 9. april 2011.
[33] RestFB -‐ A Lightweight Java Facebook Graph API and Old REST API Client , http://restfb.com/, 13. april 2011.
[34] Facebook Query Language (FQL) -‐ Facebook Developers , http://developers.facebook.com/docs/reference/fql/, 13. april 2011.
[35] Java Ajax Frameworks -‐ Ajax Patterns , http://ajaxpatterns.org/Java_Ajax_Frameworks, 1. maj 2011.
[36] Google Web Toolkit -‐ Google Code , http://code.google.com/webtoolkit/, 1. maj 2011.
[37] Robert Thurlow, RPC: Remote Procedure Call Protocol Specification Version 2 , http://tools.ietf.org/html/rfc5531, 1. maj 2011.
[38] Rajiv Mordani, Sun Microsystems Inc. Java Transaction API (JTA), dec. 2009. [39] Appstats for Java -‐ Google App Engine -‐ Google Code ,
http://code.google.com/appengine/docs/java/tools/appstats.html, 1. maj 2011. [40] Google App Engine Blog: New! Grow your app beyond the free quotas! ,
http://googleappengine.blogspot.com/2009/02/new-‐grow-‐your-‐app-‐beyond-‐free-‐quotas.html, 1. maj 2011.
[41] Tečajnica Banke Slovenije -‐ referenčni tečaji ECB -‐ Banka Slovenije , http://www.bsi.si/podatki/tec-‐bs.asp, 1. maj 2011.
49
50
51
Izjava
Izjavljam, da sem diplomsko delo izdelal samostojno pod vodstvom mentorja doc. dr.
Boštjana Murovca, univ. dipl. inž. el. Izkazano pomoč drugih sodelavcev sem v celoti
navedel v zahvali.
Matjaž Pečan