Halló, ég er að búa til forrit fyrir DBMS
Finndu kraftinn! (…aka njóttu frammistöðunnar)
Allt ofangreint gerir Tarantool að aðlaðandi vettvangi til að búa til mikið álagsforrit sem vinna með gagnagrunnum. Í slíkum forritum er oft þörf fyrir afritun gagna.
Eins og getið er hér að ofan hefur Tarantool innbyggða gagnaafritun. Meginreglan um starfsemi þess er að framkvæma í röð á eftirlíkingum allar færslur sem eru í aðalskránni (WAL). Venjulega slík afritun (við munum kalla það frekar lágu stigi) er notað til að tryggja villuþol forrita og/eða til að dreifa lestrarálagi á milli klasahnúta.
Hrísgrjón. 1. Afritun innan klasa
Dæmi um aðra atburðarás væri að flytja gögn sem búin eru til í einum gagnagrunni yfir í annan gagnagrunn til vinnslu/eftirlits. Í síðara tilvikinu gæti verið þægilegri lausn að nota Hátt stig afritun - afritun gagna á viðskiptarökfræðistigi forritsins. Þeir. Við notum ekki tilbúna lausn sem er innbyggð í DBMS, heldur innleiðum afritun á eigin spýtur í forritinu sem við erum að þróa. Þessi aðferð hefur bæði kosti og galla. Við skulum telja upp kosti.
1. Umferðarsparnaður:
- Þú getur ekki flutt öll gögnin, heldur aðeins hluta þeirra (til dæmis, þú getur flutt aðeins sumar töflur, sumar dálka þeirra eða færslur sem uppfylla ákveðna viðmiðun);
- Ólíkt afritun á lágu stigi, sem er framkvæmd stöðugt í ósamstilltri (útfærð í núverandi útgáfu af Tarantool - 1.10) eða samstilltri (á að útfæra í síðari útgáfum af Tarantool), er hægt að framkvæma afritun á háu stigi í lotum (þ.e.a.s. forritið samstillir fyrst gögnin - gögn skiptilotu, síðan er hlé á afritun, eftir það á sér stað næsta skiptilota osfrv.);
- ef skrá hefur breyst nokkrum sinnum, geturðu aðeins flutt nýjustu útgáfu hennar (ólíkt afritun á lágu stigi, þar sem allar breytingar sem gerðar eru á masternum verða spilaðar í röð á eftirmyndunum).
2. Það eru engir erfiðleikar við að útfæra HTTP skipti, sem gerir þér kleift að samstilla ytri gagnagrunna.
Hrísgrjón. 2. Afritun yfir HTTP
3. Gagnagrunnsuppbyggingin sem gögn eru flutt á milli þurfa ekki að vera þau sömu (að auki, í almennu tilvikinu, er jafnvel hægt að nota mismunandi DBMS, forritunarmál, vettvang o.s.frv.).
Hrísgrjón. 3. Afritun í ólíkum kerfum
Gallinn er sá að að meðaltali er forritun erfiðari/kostnaðarsamari en stillingar og í stað þess að sérsníða innbyggðu virknina verður þú að útfæra þína eigin.
Ef ofangreindir kostir skipta sköpum í þínum aðstæðum (eða eru nauðsynleg skilyrði), þá er skynsamlegt að nota afritun á háu stigi. Við skulum skoða nokkrar leiðir til að innleiða afritun gagna á háu stigi í Tarantool DBMS.
Lágmörkun umferðar
Svo, einn af kostum afritunar á háu stigi er umferðarsparnaður. Til þess að þessi kostur verði að fullu að veruleika er nauðsynlegt að lágmarka gagnamagnið sem flutt er í hverri skiptilotu. Auðvitað ættum við ekki að gleyma því að í lok lotunnar verður gagnamóttakarinn að vera samstilltur við upprunann (að minnsta kosti fyrir þann hluta gagna sem tekur þátt í afritun).
Hvernig á að lágmarka magn gagna sem flutt er við afritun á háu stigi? Einföld lausn gæti verið að velja gögn eftir dagsetningu og tíma. Til að gera þetta geturðu notað dagsetningar-tíma reitinn sem þegar er til í töflunni (ef hann er til). Til dæmis getur „pöntun“ skjal haft reitinn „áskilinn framkvæmdartími pöntunar“ - delivery_time
. Vandamálið við þessa lausn er að gildin á þessu sviði þurfa ekki að vera í þeirri röð sem samsvarar stofnun pantana. Þannig að við getum ekki munað hámarksgildi reitsins delivery_time
, send á fyrri skiptilotu, og á næstu skiptilotu veldu allar færslur með hærra reitgildi delivery_time
. Færslur með lægra reitgildi gætu hafa verið bætt við á milli skiptilota delivery_time
. Einnig gæti pöntunin hafa tekið breytingum, sem engu að síður höfðu ekki áhrif á völlinn delivery_time
. Í báðum tilvikum verða breytingarnar ekki fluttar frá uppruna til áfangastaðar. Til að leysa þessi vandamál þurfum við að flytja gögn sem „skarast“. Þeir. í hverri skiptilotu munum við flytja öll gögn með svæðisgildinu delivery_time
, fer yfir einhvern tíma í fortíðinni (til dæmis N klukkustundir frá núverandi augnabliki). Hins vegar er augljóst að fyrir stór kerfi er þessi aðferð mjög óþörf og getur dregið úr umferðarsparnaði sem við erum að sækjast eftir að engu. Að auki gæti taflan sem verið er að flytja ekki verið með reit sem tengist dagsetningu og tíma.
Önnur lausn, flóknari hvað varðar útfærslu, er að staðfesta móttöku gagna. Í þessu tilviki, á hverri skiptilotu, eru öll gögn send, móttaka þeirra hefur ekki verið staðfest af viðtakanda. Til að útfæra þetta þarftu að bæta Boolean dálki við upprunatöfluna (td, is_transferred
). Ef viðtakandi staðfestir móttöku færslunnar tekur samsvarandi reitur gildið true
, eftir það tekur færslan ekki lengur þátt í skiptum. Þessi útfærslumöguleiki hefur eftirfarandi ókosti. Í fyrsta lagi, fyrir hverja færslu sem flutt er, verður að búa til staðfestingu og senda. Í grófum dráttum gæti þetta verið sambærilegt við tvöföldun gagnamagns sem flutt er og leiða til tvöföldunar á fjölda hringferða. Í öðru lagi er enginn möguleiki á að senda sömu færsluna til nokkurra viðtakenda (fyrsti móttakandinn sem tekur við mun staðfesta móttöku fyrir sjálfan sig og alla hina).
Aðferð sem hefur ekki þá ókosti sem gefnir eru upp hér að ofan er að bæta dálki við fluttu töfluna til að fylgjast með breytingum í röðum hennar. Slíkur dálkur getur verið af dagsetningu-tíma gerð og verður að vera stilltur/uppfærður af forritinu á núverandi tíma í hvert skipti sem færslum er bætt við/breytt (atómfræðilega með viðbótinni/breytingunni). Sem dæmi skulum við kalla dálkinn update_time
. Með því að vista hámarks reitgildi þessa dálks fyrir yfirfærðar færslur getum við byrjað næstu skiptilotu með þessu gildi (veljið færslur með reitgildinu update_time
, umfram áður geymt gildi). Vandamálið við síðari aðferðina er að gagnabreytingar geta átt sér stað í lotum. Sem afleiðing af reitgildunum í dálknum update_time
er kannski ekki einsdæmi. Þess vegna er ekki hægt að nota þennan dálk fyrir hluta (síðu-fyrir-síðu) gagnaúttak. Til að birta gögn síðu fyrir síðu þarftu að finna upp viðbótarkerfi sem mun líklegast hafa mjög litla skilvirkni (til dæmis að sækja úr gagnagrunninum allar færslur með gildinu update_time
hærra en tiltekið og framleiðir ákveðinn fjölda skráa, frá ákveðnu móti frá upphafi úrtaks).
Þú getur bætt skilvirkni gagnaflutnings með því að bæta aðeins fyrri nálgun. Til að gera þetta munum við nota heiltölugerðina (löng heiltala) sem gildi dálkareitsins til að rekja breytingar. Við skulum nefna dálkinn row_ver
. Reitsgildi þessa dálks verður samt að vera stillt/uppfært í hvert skipti sem skrá er búin til/breytt. En í þessu tilviki verður reitnum ekki úthlutað núverandi dagsetningu og tíma, heldur gildi einhvers teljara, aukið um einn. Þar af leiðandi dálkurinn row_ver
mun innihalda einstök gildi og er ekki aðeins hægt að nota til að sýna „delta“ gögn (gögnum bætt við / breytt frá lokum fyrri skiptilotu), heldur einnig til að skipta þeim niður í síður á einfaldan og áhrifaríkan hátt.
Síðasta fyrirhugaða aðferðin til að lágmarka gagnamagnið sem flutt er innan ramma afritunar á háu stigi virðist mér ákjósanlegast og alhliða. Við skulum skoða það nánar.
Sending gagna með því að nota línuútgáfuteljara
Útfærsla á þjóninum/meistarahlutanum
Í MS SQL Server er sérstök dálktegund til að útfæra þessa nálgun - rowversion
. Hver gagnagrunnur hefur teljara sem hækkar um einn í hvert skipti sem færslu er bætt við/breytt í töflu sem hefur dálk eins og rowversion
. Gildi þessa teljara er sjálfkrafa úthlutað á reit þessa dálks í bættu/breyttu færslunni. Tarantool DBMS er ekki með svipaða innbyggða vélbúnað. Hins vegar í Tarantool er ekki erfitt að útfæra það handvirkt. Við skulum skoða hvernig þetta er gert.
Í fyrsta lagi smá hugtök: töflur í Tarantool eru kallaðar bil og færslur eru kallaðar tuples. Í Tarantool er hægt að búa til röð. Raðir eru ekkert annað en nafngreindir rafallar af röðuðum heiltölugildum. Þeir. þetta er einmitt það sem við þurfum í okkar tilgangi. Hér að neðan munum við búa til slíka röð.
Áður en þú framkvæmir gagnagrunnsaðgerð í Tarantool þarftu að keyra eftirfarandi skipun:
box.cfg{}
Fyrir vikið mun Tarantool byrja að skrifa skyndimyndir gagnagrunns og viðskiptaskrár í núverandi möppu.
Við skulum búa til röð row_version
:
box.schema.sequence.create('row_version',
{ if_not_exists = true })
Valkostur if_not_exists
gerir kleift að keyra sköpunarforskriftina mörgum sinnum: ef hluturinn er til mun Tarantool ekki reyna að búa hann til aftur. Þessi valkostur verður notaður í öllum síðari DDL skipunum.
Við skulum búa til rými sem dæmi.
box.schema.space.create('goods', {
format = {
{
name = 'id',
type = 'unsigned'
},
{
name = 'name',
type = 'string'
},
{
name = 'code',
type = 'unsigned'
},
{
name = 'row_ver',
type = 'unsigned'
}
},
if_not_exists = true
})
Hér setjum við nafn rýmisins (goods
), reitnöfn og gerðir þeirra.
Sjálfvirk aukning reitir í Tarantool eru einnig búnir til með því að nota raðir. Við skulum búa til aðallykil sem stækkar sjálfkrafa eftir reit id
:
box.schema.sequence.create('goods_id',
{ if_not_exists = true })
box.space.goods:create_index('primary', {
parts = { 'id' },
sequence = 'goods_id',
unique = true,
type = 'HASH',
if_not_exists = true
})
Tarantool styður nokkrar tegundir af vísitölum. Algengustu vísitölurnar eru TREE og HASH tegundir, sem byggjast á mannvirkjum sem samsvara nafninu. TREE er fjölhæfasta vísitalan. Það gerir þér kleift að sækja gögn á skipulagðan hátt. En fyrir jafnréttisval hentar HASH betur. Í samræmi við það er ráðlegt að nota HASH fyrir aðallykilinn (sem er það sem við gerðum).
Til að nota dálkinn row_ver
til að flytja breytt gögn þarftu að binda raðgildi við reiti þessa dálks row_ver
. En ólíkt aðallyklinum, gildi dálksviðsins row_ver
ætti að hækka um eitt, ekki aðeins þegar nýjum skrám er bætt við, heldur einnig þegar þeim er breytt. Þú getur notað kveikjur fyrir þetta. Tarantool hefur tvær gerðir af geimkveikjum: before_replace
и on_replace
. Kveikjur eru ræstar í hvert sinn sem gögnin í rýminu breytast (fyrir hverja tuple sem breytingarnar hafa áhrif á er kveikjuaðgerð ræst). Ólíkt on_replace
, before_replace
-triggers leyfa þér að breyta gögnum tuplesins sem kveikjan er keyrð fyrir. Í samræmi við það hentar síðasta gerð kveikjanna okkur.
box.space.goods:before_replace(function(old, new)
return box.tuple.new({new[1], new[2], new[3],
box.sequence.row_version:next()})
end)
Eftirfarandi kveikja kemur í stað reitsgildisins row_ver
geymt tuple í næsta gildi röðarinnar row_version
.
Til að geta dregið gögn úr geimnum goods
eftir dálki row_ver
, búum til vísitölu:
box.space.goods:create_index('row_ver', {
parts = { 'row_ver' },
unique = true,
type = 'TREE',
if_not_exists = true
})
Vísitala tegund - tré (TREE
), vegna þess við þurfum að draga gögnin út í hækkandi röð gildanna í dálknum row_ver
.
Við skulum bæta nokkrum gögnum við rýmið:
box.space.goods:insert{nil, 'pen', 123}
box.space.goods:insert{nil, 'pencil', 321}
box.space.goods:insert{nil, 'brush', 100}
box.space.goods:insert{nil, 'watercolour', 456}
box.space.goods:insert{nil, 'album', 101}
box.space.goods:insert{nil, 'notebook', 800}
box.space.goods:insert{nil, 'rubber', 531}
box.space.goods:insert{nil, 'ruler', 135}
Vegna þess að Fyrsti reiturinn er teljari sem hækkar sjálfvirkt; við sendum núll í staðinn. Tarantool kemur sjálfkrafa í stað næsta gildis. Á sama hátt, eins og gildi dálkareitanna row_ver
þú getur staðist núll - eða ekki tilgreint gildið yfirleitt, vegna þess að þessi dálkur er í síðasta sæti í rýminu.
Við skulum athuga innsetningarniðurstöðuna:
tarantool> box.space.goods:select()
---
- - [1, 'pen', 123, 1]
- [2, 'pencil', 321, 2]
- [3, 'brush', 100, 3]
- [4, 'watercolour', 456, 4]
- [5, 'album', 101, 5]
- [6, 'notebook', 800, 6]
- [7, 'rubber', 531, 7]
- [8, 'ruler', 135, 8]
...
Eins og þú sérð fyllast fyrsti og síðasti reiturinn sjálfkrafa út. Nú verður auðvelt að skrifa aðgerð fyrir síðu fyrir síðu upphleðslu á rýmisbreytingum goods
:
local page_size = 5
local function get_goods(row_ver)
local index = box.space.goods.index.row_ver
local goods = {}
local counter = 0
for _, tuple in index:pairs(row_ver, {
iterator = 'GT' }) do
local obj = tuple:tomap({ names_only = true })
table.insert(goods, obj)
counter = counter + 1
if counter >= page_size then
break
end
end
return goods
end
Fallið tekur gildið sem færibreytu row_ver
, sem byrjar þaðan sem nauðsynlegt er að afferma breytingar, og skilar hluta af breyttum gögnum.
Sýnataka úr gögnum í Tarantool er gerð í gegnum vísitölur. Virka get_goods
notar endurtekningu eftir vísitölu row_ver
að fá breytt gögn. Gerð iterator er GT (Stærri en, stærri en). Þetta þýðir að endurtekinn mun fara í röð yfir vísitölugildin frá samþykkta lyklinum (reitargildi row_ver
).
Ítrekarinn skilar túllum. Til þess að geta flutt gögn í kjölfarið í gegnum HTTP er nauðsynlegt að breyta túllunum í skipulag sem er þægilegt fyrir síðari röðun. Dæmið notar staðlaða aðgerðina fyrir þetta tomap
. Í stað þess að nota tomap
þú getur skrifað þína eigin aðgerð. Til dæmis gætum við viljað endurnefna reit name
, ekki fara framhjá vellinum code
og bæta við reit comment
:
local function unflatten_goods(tuple)
local obj = {}
obj.id = tuple.id
obj.goods_name = tuple.name
obj.comment = 'some comment'
obj.row_ver = tuple.row_ver
return obj
end
Síðustærð úttaksgagna (fjöldi skráa í einum hluta) er ákvörðuð af breytunni page_size
. Í dæminu gildið page_size
er 5. Í alvöru forriti skiptir síðustærðin yfirleitt meira máli. Það fer eftir meðalstærð geimtúpunnar. Besta síðustærð er hægt að ákvarða með reynslu með því að mæla gagnaflutningstíma. Því stærri sem síðustærðin er, því færri er fjöldi ferða fram og til baka á milli sendandi og móttökuhliðar. Þannig geturðu dregið úr heildartíma til að hlaða niður breytingum. Hins vegar, ef síðustærðin er of stór, munum við eyða of langan tíma á þjóninum í að raða sýnishorninu. Þar af leiðandi geta orðið tafir á afgreiðslu annarra beiðna sem berast til þjónsins. Parameter page_size
hægt að hlaða upp úr stillingarskránni. Fyrir hvert sent rými geturðu stillt eigið gildi þess. Hins vegar getur sjálfgefið gildi (til dæmis 100) hentað fyrir flest rými.
Við skulum framkvæma aðgerðina get_goods
:
tarantool> get_goods(0)
---
- - row_ver: 1
code: 123
name: pen
id: 1
- row_ver: 2
code: 321
name: pencil
id: 2
- row_ver: 3
code: 100
name: brush
id: 3
- row_ver: 4
code: 456
name: watercolour
id: 4
- row_ver: 5
code: 101
name: album
id: 5
...
Tökum sviðsgildið row_ver
úr síðustu línu og kalla aðgerðina aftur:
tarantool> get_goods(5)
---
- - row_ver: 6
code: 800
name: notebook
id: 6
- row_ver: 7
code: 531
name: rubber
id: 7
- row_ver: 8
code: 135
name: ruler
id: 8
...
Enn aftur:
tarantool> get_goods(8)
---
- []
...
Eins og þú sérð, þegar það er notað á þennan hátt, skilar aðgerðin öllum plássskrám síðu fyrir síðu goods
. Á eftir síðustu síðu er tómt val.
Gerum breytingar á rýminu:
box.space.goods:update(4, {{'=', 6, 'copybook'}})
box.space.goods:insert{nil, 'clip', 234}
box.space.goods:insert{nil, 'folder', 432}
Við höfum breytt svæðisgildinu name
fyrir eina færslu og bætt við tveimur nýjum færslum.
Við skulum endurtaka síðasta aðgerðarkallið:
tarantool> get_goods(8)
---
- - row_ver: 9
code: 800
name: copybook
id: 6
- row_ver: 10
code: 234
name: clip
id: 9
- row_ver: 11
code: 432
name: folder
id: 10
...
Aðgerðin skilaði breyttum og bættum færslum. Svo aðgerðin get_goods
gerir þér kleift að taka á móti gögnum sem hafa breyst frá síðasta símtali, sem er grundvöllur afritunaraðferðarinnar sem er til skoðunar.
Við munum skilja útgáfu niðurstaðna í gegnum HTTP í formi JSON utan gildissviðs þessarar greinar. Þú getur lesið um þetta hér:
Framkvæmd viðskiptavina/þræla hluta
Skoðum hvernig útfærsla móttökuaðila lítur út. Við skulum búa til pláss á móttökuhliðinni til að geyma niðurhalað gögn:
box.schema.space.create('goods', {
format = {
{
name = 'id',
type = 'unsigned'
},
{
name = 'name',
type = 'string'
},
{
name = 'code',
type = 'unsigned'
}
},
if_not_exists = true
})
box.space.goods:create_index('primary', {
parts = { 'id' },
sequence = 'goods_id',
unique = true,
type = 'HASH',
if_not_exists = true
})
Uppbygging rýmisins líkist uppbyggingu rýmisins í upptökum. En þar sem við ætlum ekki að senda móttekin gögn annars staðar, dálkurinn row_ver
er ekki í rými viðtakanda. Á sviði id
upprunaauðkenni verða skráð. Þess vegna, á móttakarahliðinni, er engin þörf á að gera það sjálfkrafa aukið.
Auk þess þurfum við pláss til að vista verðmæti row_ver
:
box.schema.space.create('row_ver', {
format = {
{
name = 'space_name',
type = 'string'
},
{
name = 'value',
type = 'string'
}
},
if_not_exists = true
})
box.space.row_ver:create_index('primary', {
parts = { 'space_name' },
unique = true,
type = 'HASH',
if_not_exists = true
})
Fyrir hvert hlaðið rými (reitur space_name
) við munum vista síðasta hlaðna gildið hér row_ver
(reitur value
). Dálkurinn virkar sem aðallykill space_name
.
Við skulum búa til aðgerð til að hlaða rýmisgögnum goods
í gegnum HTTP. Til að gera þetta þurfum við bókasafn sem útfærir HTTP biðlara. Eftirfarandi lína hleður bókasafnið og sýnir HTTP biðlarann:
local http_client = require('http.client').new()
Við þurfum líka bókasafn fyrir json afserialization:
local json = require('json')
Þetta er nóg til að búa til gagnahleðsluaðgerð:
local function load_data(url, row_ver)
local url = ('%s?rowVer=%s'):format(url,
tostring(row_ver))
local body = nil
local data = http_client:request('GET', url, body, {
keepalive_idle = 1,
keepalive_interval = 1
})
return json.decode(data.body)
end
Aðgerðin framkvæmir HTTP beiðni á vefslóðina og sendir hana row_ver
sem breytu og skilar afserialized niðurstöðu beiðninnar.
Aðgerðin til að vista móttekin gögn lítur svona út:
local function save_goods(goods)
local n = #goods
box.atomic(function()
for i = 1, n do
local obj = goods[i]
box.space.goods:put(
obj.id, obj.name, obj.code)
end
end)
end
Hringrás til að vista gögn í geimnum goods
sett í færslu (aðgerðin er notuð fyrir þetta box.atomic
) til að fækka diskaðgerðum.
Að lokum, staðbundin rúm samstilling virka goods
með heimild geturðu útfært það svona:
local function sync_goods()
local tuple = box.space.row_ver:get('goods')
local row_ver = tuple and tuple.value or 0
—— set your url here:
local url = 'http://127.0.0.1:81/test/goods/list'
while true do
local goods = load_goods(url, row_ver)
local count = #goods
if count == 0 then
return
end
save_goods(goods)
row_ver = goods[count].rowVer
box.space.row_ver:put({'goods', row_ver})
end
end
Fyrst lesum við áður vistað gildi row_ver
fyrir pláss goods
. Ef það vantar (fyrsta skiptinámið), þá tökum við það sem row_ver
núll. Næst í lotunni gerum við síðu fyrir síðu niðurhal á breyttum gögnum frá upprunanum á tilgreindri slóð. Við hverja endurtekningu vistum við móttekin gögn á viðeigandi staðbundið svæði og uppfærum gildið row_ver
(í geimnum row_ver
og í breyt row_ver
) - taktu gildið row_ver
frá síðustu línu af hlaðnum gögnum.
Til að verjast lykkju fyrir slysni (ef villu verður í forritinu), lykkjan while
hægt að skipta út fyrir for
:
for _ = 1, max_req do ...
Sem afleiðing af framkvæmd aðgerðarinnar sync_goods
pláss goods
móttakarinn mun innihalda nýjustu útgáfur af öllum geimskrám goods
í heimildinni.
Augljóslega er ekki hægt að útvarpa gögnum með þessum hætti. Ef slík þörf er fyrir hendi geturðu notað eyðingarmerki. Bæta við pláss goods
Boolean sviði is_deleted
og í stað þess að eyða færslu líkamlega notum við rökrétta eyðingu - við setjum reitgildið is_deleted
í merkingu true
. Stundum í stað Boolean-sviðs is_deleted
það er þægilegra að nota völlinn deleted
, sem geymir dagsetningu og tíma fyrir rökrétta eyðingu færslunnar. Eftir að hafa framkvæmt rökrétta eyðingu verður skráin sem er merkt til eyðingar flutt frá uppruna til áfangastaðar (samkvæmt rökfræðinni sem fjallað er um hér að ofan).
Röð row_ver
hægt að nota til að senda gögn frá öðrum rýmum: það er engin þörf á að búa til sérstaka röð fyrir hvert sent rými.
Við skoðuðum áhrifaríka leið til afritunar gagna á háu stigi í forritum sem nota Tarantool DBMS.
Niðurstöður
- Tarantool DBMS er aðlaðandi, efnilegur vara til að búa til háhlaðna forrit.
- Afritun gagna á háu stigi hefur ýmsa kosti fram yfir afritun á lágu stigi.
- Afritunaraðferðin á háu stigi sem fjallað er um í greininni gerir þér kleift að lágmarka magn fluttra gagna með því að flytja aðeins þær skrár sem hafa breyst frá síðustu skiptilotu.
Heimild: www.habr.com