టరాన్టూల్ DBMSలో ఉన్నత-స్థాయి ప్రతిరూపణ

హలో, నేను DBMS కోసం అప్లికేషన్‌లను సృష్టిస్తున్నాను టరాన్టూల్ Mail.ru గ్రూప్ ద్వారా అభివృద్ధి చేయబడిన ప్లాట్‌ఫారమ్, ఇది అధిక-పనితీరు గల DBMS మరియు Lua భాషలో అప్లికేషన్ సర్వర్‌ను మిళితం చేస్తుంది. ప్రత్యేకించి, DBMS యొక్క ఇన్-మెమరీ మోడ్‌కు మద్దతు మరియు డేటాతో ఒకే చిరునామా స్థలంలో అప్లికేషన్ బిజినెస్ లాజిక్‌ను అమలు చేయగల సామర్థ్యం కారణంగా టరాన్టూల్ ఆధారంగా పరిష్కారాల యొక్క అధిక వేగం సాధించబడుతుంది. అదే సమయంలో, ACID లావాదేవీలను ఉపయోగించి డేటా నిలకడ నిర్ధారించబడుతుంది (డిస్క్‌లో WAL లాగ్ నిర్వహించబడుతుంది). ప్రతిరూపణ మరియు షార్డింగ్ కోసం టరాన్టూల్ అంతర్నిర్మిత మద్దతును కలిగి ఉంది. సంస్కరణ 2.1 నుండి ప్రారంభించి, SQL భాషలో ప్రశ్నలకు మద్దతు ఉంది. Tarantool ఓపెన్ సోర్స్ మరియు సరళీకృత BSD లైసెన్స్ క్రింద లైసెన్స్ పొందింది. వాణిజ్య ఎంటర్‌ప్రైజ్ వెర్షన్ కూడా ఉంది.

టరాన్టూల్ DBMSలో ఉన్నత-స్థాయి ప్రతిరూపణ
శక్తిని అనుభవించు! (...అకా ప్రదర్శనను ఆస్వాదించండి)

పైన పేర్కొన్నవన్నీ డేటాబేస్‌లతో పనిచేసే అధిక-లోడ్ అప్లికేషన్‌లను రూపొందించడానికి టరాన్టూల్‌ను ఆకర్షణీయమైన ప్లాట్‌ఫారమ్‌గా చేస్తాయి. అటువంటి అప్లికేషన్లలో, తరచుగా డేటా రెప్లికేషన్ అవసరం ఉంటుంది.

పైన పేర్కొన్న విధంగా, Tarantool అంతర్నిర్మిత డేటా ప్రతిరూపణను కలిగి ఉంది. మాస్టర్ లాగ్ (WAL)లో ఉన్న అన్ని లావాదేవీలను ప్రతిరూపాలపై వరుసగా అమలు చేయడం దీని ఆపరేషన్ సూత్రం. సాధారణంగా ఇటువంటి ప్రతిరూపం (మేము దానిని మరింత పిలుస్తాము కింది స్థాయి) అప్లికేషన్ తప్పు సహనాన్ని నిర్ధారించడానికి మరియు/లేదా క్లస్టర్ నోడ్‌ల మధ్య రీడింగ్ లోడ్‌ని పంపిణీ చేయడానికి ఉపయోగించబడుతుంది.

టరాన్టూల్ DBMSలో ఉన్నత-స్థాయి ప్రతిరూపణ
అన్నం. 1. క్లస్టర్ లోపల ప్రతిరూపం

ప్రత్యామ్నాయ దృష్టాంతం యొక్క ఉదాహరణ ప్రాసెసింగ్/పర్యవేక్షణ కోసం ఒక డేటాబేస్లో సృష్టించబడిన డేటాను మరొక డేటాబేస్కు బదిలీ చేయడం. తరువాతి సందర్భంలో, మరింత అనుకూలమైన పరిష్కారం ఉపయోగించవచ్చు ఉన్నతమైన స్థానం రెప్లికేషన్ - అప్లికేషన్ బిజినెస్ లాజిక్ స్థాయిలో డేటా రెప్లికేషన్. ఆ. మేము DBMSలో నిర్మించిన రెడీమేడ్ సొల్యూషన్‌ని ఉపయోగించము, కానీ మేము అభివృద్ధి చేస్తున్న అప్లికేషన్‌లో మా స్వంతంగా ప్రతిరూపణను అమలు చేస్తాము. ఈ విధానం ప్రయోజనాలు మరియు అప్రయోజనాలు రెండింటినీ కలిగి ఉంది. ప్రయోజనాలను జాబితా చేద్దాం.

1. ట్రాఫిక్ ఆదా:

  • మీరు మొత్తం డేటాను బదిలీ చేయలేరు, కానీ దానిలో కొంత భాగాన్ని మాత్రమే (ఉదాహరణకు, మీరు కొన్ని పట్టికలు, వాటి కొన్ని నిలువు వరుసలు లేదా నిర్దిష్ట ప్రమాణాలకు అనుగుణంగా ఉన్న రికార్డులను మాత్రమే బదిలీ చేయవచ్చు);
  • తక్కువ-స్థాయి రెప్లికేషన్ కాకుండా, అసమకాలిక (ప్రస్తుత టరాన్టూల్ వెర్షన్‌లో అమలు చేయబడింది - 1.10) లేదా సింక్రోనస్ (తరువాతి టరాన్టూల్ వెర్షన్‌లలో అమలు చేయబడుతుంది) మోడ్‌లో నిరంతరం నిర్వహించబడుతుంది, సెషన్‌లలో అధిక-స్థాయి ప్రతిరూపణను నిర్వహించవచ్చు (అంటే, ది అప్లికేషన్ మొదట డేటాను సమకాలీకరిస్తుంది - మార్పిడి సెషన్ డేటా, ఆపై ప్రతిరూపణలో విరామం ఉంది, దాని తర్వాత తదుపరి మార్పిడి సెషన్ జరుగుతుంది, మొదలైనవి);
  • రికార్డు చాలాసార్లు మారినట్లయితే, మీరు దాని తాజా సంస్కరణను మాత్రమే బదిలీ చేయవచ్చు (తక్కువ-స్థాయి ప్రతిరూపణ వలె కాకుండా, దీనిలో మాస్టర్‌పై చేసిన అన్ని మార్పులు ప్రతిరూపాలపై వరుసగా ప్లే చేయబడతాయి).

2. HTTP మార్పిడిని అమలు చేయడంలో ఇబ్బందులు లేవు, ఇది రిమోట్ డేటాబేస్‌లను సమకాలీకరించడానికి మిమ్మల్ని అనుమతిస్తుంది.

టరాన్టూల్ DBMSలో ఉన్నత-స్థాయి ప్రతిరూపణ
అన్నం. 2. HTTPపై ప్రతిరూపం

3. డేటా బదిలీ చేయబడిన డేటాబేస్ నిర్మాణాలు ఒకే విధంగా ఉండవలసిన అవసరం లేదు (అంతేకాకుండా, సాధారణ సందర్భంలో, వివిధ DBMSలు, ప్రోగ్రామింగ్ భాషలు, ప్లాట్‌ఫారమ్‌లు మొదలైన వాటిని ఉపయోగించడం కూడా సాధ్యమే).

టరాన్టూల్ DBMSలో ఉన్నత-స్థాయి ప్రతిరూపణ
అన్నం. 3. వైవిధ్య వ్యవస్థలలో ప్రతిరూపం

ప్రతికూలత ఏమిటంటే, సగటున, ప్రోగ్రామింగ్ కాన్ఫిగరేషన్ కంటే చాలా కష్టం/ఖరీదైనది మరియు అంతర్నిర్మిత కార్యాచరణను అనుకూలీకరించడానికి బదులుగా, మీరు మీ స్వంతంగా అమలు చేయాల్సి ఉంటుంది.

మీ పరిస్థితిలో పైన పేర్కొన్న ప్రయోజనాలు కీలకమైనవి (లేదా అవసరమైన పరిస్థితి) అయితే, అధిక-స్థాయి ప్రతిరూపణను ఉపయోగించడం అర్ధమే. Tarantool DBMSలో అధిక-స్థాయి డేటా ప్రతిరూపణను అమలు చేయడానికి అనేక మార్గాలను చూద్దాం.

ట్రాఫిక్ కనిష్టీకరణ

కాబట్టి, అధిక-స్థాయి ప్రతిరూపణ యొక్క ప్రయోజనాల్లో ఒకటి ట్రాఫిక్ ఆదా. ఈ ప్రయోజనం పూర్తిగా గ్రహించబడాలంటే, ప్రతి మార్పిడి సెషన్‌లో బదిలీ చేయబడిన డేటా మొత్తాన్ని తగ్గించడం అవసరం. వాస్తవానికి, సెషన్ ముగింపులో, డేటా రిసీవర్ తప్పనిసరిగా మూలంతో సమకాలీకరించబడాలని మనం మర్చిపోకూడదు (కనీసం ప్రతిరూపణలో పాల్గొన్న డేటా యొక్క ఆ భాగానికి).

అధిక-స్థాయి ప్రతిరూపణ సమయంలో బదిలీ చేయబడిన డేటా మొత్తాన్ని ఎలా తగ్గించాలి? తేదీ మరియు సమయం వారీగా డేటాను ఎంచుకోవడం ఒక సూటి పరిష్కారం. దీన్ని చేయడానికి, మీరు పట్టికలో ఇప్పటికే ఉన్న తేదీ-సమయం ఫీల్డ్‌ను ఉపయోగించవచ్చు (అది ఉన్నట్లయితే). ఉదాహరణకు, “ఆర్డర్” పత్రంలో “అవసరమైన ఆర్డర్ అమలు సమయం” ఫీల్డ్ ఉండవచ్చు - delivery_time. ఈ పరిష్కారంతో సమస్య ఏమిటంటే, ఈ ఫీల్డ్‌లోని విలువలు ఆర్డర్‌ల సృష్టికి అనుగుణంగా ఉండే క్రమంలో ఉండవలసిన అవసరం లేదు. కాబట్టి మేము గరిష్ట ఫీల్డ్ విలువను గుర్తుంచుకోలేము delivery_time, మునుపటి మార్పిడి సెషన్‌లో ప్రసారం చేయబడింది మరియు తదుపరి మార్పిడి సెషన్‌లో అధిక ఫీల్డ్ విలువతో అన్ని రికార్డ్‌లను ఎంచుకోండి delivery_time. ఎక్స్ఛేంజ్ సెషన్‌ల మధ్య తక్కువ ఫీల్డ్ విలువ కలిగిన రికార్డ్‌లు జోడించబడి ఉండవచ్చు delivery_time. అలాగే, ఆర్డర్ మార్పులకు లోనవుతుంది, అయితే ఇది ఫీల్డ్‌ను ప్రభావితం చేయలేదు delivery_time. రెండు సందర్భాల్లో, మార్పులు మూలం నుండి గమ్యస్థానానికి బదిలీ చేయబడవు. ఈ సమస్యలను పరిష్కరించడానికి, మేము "అతివ్యాప్తి" డేటాను బదిలీ చేయాలి. ఆ. ప్రతి మార్పిడి సెషన్‌లో మేము ఫీల్డ్ విలువతో మొత్తం డేటాను బదిలీ చేస్తాము delivery_time, గతంలో కొంత పాయింట్‌ను మించిపోయింది (ఉదాహరణకు, ప్రస్తుత క్షణం నుండి N గంటలు). అయినప్పటికీ, పెద్ద సిస్టమ్‌ల కోసం ఈ విధానం చాలా అనవసరమైనది మరియు మనం కష్టపడుతున్న ట్రాఫిక్ పొదుపులను ఏమీ లేకుండా తగ్గించగలదని స్పష్టంగా తెలుస్తుంది. అదనంగా, బదిలీ చేయబడిన పట్టిక తేదీ-సమయంతో అనుబంధించబడిన ఫీల్డ్‌ను కలిగి ఉండకపోవచ్చు.

మరొక పరిష్కారం, అమలు పరంగా మరింత సంక్లిష్టమైనది, డేటా రసీదుని గుర్తించడం. ఈ సందర్భంలో, ప్రతి మార్పిడి సెషన్ సమయంలో, మొత్తం డేటా ప్రసారం చేయబడుతుంది, దీని రసీదు గ్రహీతచే నిర్ధారించబడలేదు. దీన్ని అమలు చేయడానికి, మీరు సోర్స్ టేబుల్‌కి బూలియన్ కాలమ్‌ను జోడించాలి (ఉదాహరణకు, is_transferred) రిసీవర్ రికార్డ్ యొక్క రసీదుని అంగీకరిస్తే, సంబంధిత ఫీల్డ్ విలువను తీసుకుంటుంది true, దీని తర్వాత ఎంట్రీ ఇకపై ఎక్స్ఛేంజీలలో పాల్గొనదు. ఈ అమలు ఎంపిక క్రింది ప్రతికూలతలను కలిగి ఉంది. ముందుగా, బదిలీ చేయబడిన ప్రతి రికార్డుకు, తప్పనిసరిగా రసీదుని రూపొందించి పంపాలి. స్థూలంగా చెప్పాలంటే, ఇది బదిలీ చేయబడిన డేటా మొత్తాన్ని రెట్టింపు చేయడం మరియు రౌండ్‌ట్రిప్‌ల సంఖ్యను రెట్టింపు చేయడంతో పోల్చవచ్చు. రెండవది, ఒకే రికార్డును అనేక రిసీవర్‌లకు పంపే అవకాశం లేదు (మొదట స్వీకరించే రిసీవర్ తనకు మరియు ఇతరులందరికీ రసీదుని నిర్ధారిస్తుంది).

Способ, лишенный недостатков, приведенных выше, состоит в добавлении в передаваемую таблицу колонки для отслеживания изменений ее строк. Такая колонка может иметь тип дата-время и должна задаваться/обновляться приложением на текущее время каждый раз при добавлении/изменении записей (атомарно с добавлением/изменением). В качестве примера назовем колонку update_time. బదిలీ చేయబడిన రికార్డుల కోసం ఈ నిలువు వరుస యొక్క గరిష్ట ఫీల్డ్ విలువను సేవ్ చేయడం ద్వారా, మేము ఈ విలువతో తదుపరి మార్పిడి సెషన్‌ను ప్రారంభించవచ్చు (ఫీల్డ్ విలువతో రికార్డ్‌లను ఎంచుకోండి update_time, గతంలో నిల్వ చేసిన విలువను మించిపోయింది). తరువాతి విధానంలో సమస్య ఏమిటంటే డేటా మార్పులు బ్యాచ్‌లలో సంభవించవచ్చు. కాలమ్‌లోని ఫీల్డ్ విలువల ఫలితంగా update_time ప్రత్యేకంగా ఉండకపోవచ్చు. అందువలన, ఈ కాలమ్ పోర్షన్డ్ (పేజీ-వారీ-పేజీ) డేటా అవుట్‌పుట్ కోసం ఉపయోగించబడదు. పేజీల వారీగా డేటాను ప్రదర్శించడానికి, మీరు చాలా తక్కువ సామర్థ్యాన్ని కలిగి ఉండే అదనపు మెకానిజమ్‌లను కనుగొనవలసి ఉంటుంది (ఉదాహరణకు, డేటాబేస్ నుండి అన్ని రికార్డులను విలువతో తిరిగి పొందడం update_time ఇచ్చిన దాని కంటే ఎక్కువ మరియు నిర్దిష్ట సంఖ్యలో రికార్డులను ఉత్పత్తి చేస్తుంది, నమూనా ప్రారంభం నుండి నిర్దిష్ట ఆఫ్‌సెట్ నుండి ప్రారంభమవుతుంది).

మీరు మునుపటి విధానాన్ని కొద్దిగా మెరుగుపరచడం ద్వారా డేటా బదిలీ సామర్థ్యాన్ని మెరుగుపరచవచ్చు. దీన్ని చేయడానికి, మార్పులను ట్రాక్ చేయడానికి మేము పూర్ణాంక రకాన్ని (దీర్ఘ పూర్ణాంకం) కాలమ్ ఫీల్డ్ విలువలుగా ఉపయోగిస్తాము. కాలమ్‌కి పేరు పెడదాం row_ver. రికార్డ్ సృష్టించబడిన/సవరించిన ప్రతిసారీ ఈ నిలువు వరుస యొక్క ఫీల్డ్ విలువ తప్పనిసరిగా సెట్ చేయబడాలి/నవీకరించబడాలి. కానీ ఈ సందర్భంలో, ఫీల్డ్ ప్రస్తుత తేదీ-సమయం కేటాయించబడదు, కానీ కొన్ని కౌంటర్ యొక్క విలువ ఒకటి పెరిగింది. ఫలితంగా, కాలమ్ row_ver ప్రత్యేక విలువలను కలిగి ఉంటుంది మరియు "డెల్టా" డేటాను (మునుపటి ఎక్స్ఛేంజ్ సెషన్ ముగిసినప్పటి నుండి డేటా జోడించబడింది/మార్చబడింది) ప్రదర్శించడానికి మాత్రమే కాకుండా, దానిని పేజీలుగా సులభంగా మరియు ప్రభావవంతంగా విభజించడానికి కూడా ఉపయోగించవచ్చు.

హై-లెవల్ రెప్లికేషన్ ఫ్రేమ్‌వర్క్‌లో బదిలీ చేయబడిన డేటా మొత్తాన్ని కనిష్టీకరించే చివరి ప్రతిపాదిత పద్ధతి నాకు అత్యంత అనుకూలమైనది మరియు సార్వత్రికమైనది. దానిని మరింత వివరంగా పరిశీలిద్దాం.

రో వెర్షన్ కౌంటర్‌ని ఉపయోగించి డేటాను పాస్ చేయడం

సర్వర్/మాస్టర్ పార్ట్ యొక్క అమలు

MS SQL సర్వర్‌లో, ఈ విధానాన్ని అమలు చేయడానికి ప్రత్యేక కాలమ్ రకం ఉంది - rowversion. ప్రతి డేటాబేస్ ఒక కౌంటర్‌ను కలిగి ఉంటుంది, అది ప్రతిసారీ రికార్డ్‌ను జోడించినప్పుడు/మార్చినప్పుడు ఇలా నిలువు వరుసను కలిగి ఉంటుంది rowversion. జోడించిన/మార్చబడిన రికార్డ్‌లోని ఈ నిలువు వరుస ఫీల్డ్‌కు ఈ కౌంటర్ విలువ స్వయంచాలకంగా కేటాయించబడుతుంది. Tarantool DBMSలో ఇలాంటి అంతర్నిర్మిత మెకానిజం లేదు. అయితే, టరాన్టూల్‌లో దీన్ని మాన్యువల్‌గా అమలు చేయడం కష్టం కాదు. ఇది ఎలా జరుగుతుందో చూద్దాం.

మొదట, ఒక చిన్న పదజాలం: టరాన్టూల్‌లోని పట్టికలను ఖాళీలు అని పిలుస్తారు మరియు రికార్డులను టుపుల్స్ అని పిలుస్తారు. టరాన్టూల్‌లో మీరు సీక్వెన్స్‌లను సృష్టించవచ్చు. సీక్వెన్స్‌లు ఆర్డర్ చేసిన పూర్ణాంకాల విలువల పేరున్న జనరేటర్‌లు తప్ప మరేమీ కాదు. ఆ. మా ప్రయోజనాల కోసం ఇది ఖచ్చితంగా అవసరం. క్రింద మేము అటువంటి క్రమాన్ని సృష్టిస్తాము.

టరాన్టూల్‌లో ఏదైనా డేటాబేస్ ఆపరేషన్ చేసే ముందు, మీరు కింది ఆదేశాన్ని అమలు చేయాలి:

box.cfg{}

ఫలితంగా, Tarantool ప్రస్తుత డైరెక్టరీకి డేటాబేస్ స్నాప్‌షాట్‌లు మరియు లావాదేవీ లాగ్‌లను వ్రాయడం ప్రారంభిస్తుంది.

ఒక క్రమాన్ని క్రియేట్ చేద్దాం row_version:

box.schema.sequence.create('row_version',
    { if_not_exists = true })

ఎంపిక if_not_exists సృష్టి స్క్రిప్ట్‌ను అనేకసార్లు అమలు చేయడానికి అనుమతిస్తుంది: ఆబ్జెక్ట్ ఉనికిలో ఉన్నట్లయితే, Tarantool దానిని మళ్లీ సృష్టించడానికి ప్రయత్నించదు. ఈ ఎంపిక అన్ని తదుపరి DDL ఆదేశాలలో ఉపయోగించబడుతుంది.

ఉదాహరణగా స్పేస్‌ని క్రియేట్ చేద్దాం.

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
})

ఇక్కడ మనం స్పేస్ పేరును సెట్ చేసాము (goods), ఫీల్డ్ పేర్లు మరియు వాటి రకాలు.

టరాన్టూల్‌లో ఆటో-ఇంక్రిమెంటింగ్ ఫీల్డ్‌లు కూడా సీక్వెన్స్‌లను ఉపయోగించి సృష్టించబడతాయి. ఫీల్డ్ వారీగా స్వీయ-పెంపు ప్రాథమిక కీని సృష్టిద్దాం 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
})

టరాన్టూల్ అనేక రకాల సూచికలకు మద్దతు ఇస్తుంది. అత్యంత సాధారణంగా ఉపయోగించే సూచికలు TREE మరియు HASH రకాలు, ఇవి పేరుకు సంబంధించిన నిర్మాణాలపై ఆధారపడి ఉంటాయి. TREE అనేది అత్యంత బహుముఖ సూచిక రకం. ఇది వ్యవస్థీకృత పద్ధతిలో డేటాను తిరిగి పొందడానికి మిమ్మల్ని అనుమతిస్తుంది. కానీ సమానత్వ ఎంపిక కోసం, HASH మరింత అనుకూలంగా ఉంటుంది. దీని ప్రకారం, ప్రాథమిక కీ కోసం HASHని ఉపయోగించడం మంచిది (ఇది మేము చేసాము).

నిలువు వరుసను ఉపయోగించడానికి row_ver మార్చబడిన డేటాను బదిలీ చేయడానికి, మీరు ఈ కాలమ్ యొక్క ఫీల్డ్‌లకు సీక్వెన్స్ విలువలను బైండ్ చేయాలి row_ver. కానీ ప్రాథమిక కీ వలె కాకుండా, కాలమ్ ఫీల్డ్ విలువ row_ver కొత్త రికార్డులను జోడించేటప్పుడు మాత్రమే కాకుండా, ఇప్పటికే ఉన్న వాటిని మార్చేటప్పుడు కూడా ఒకటి పెంచాలి. మీరు దీని కోసం ట్రిగ్గర్లను ఉపయోగించవచ్చు. టరాన్టూల్ రెండు రకాల స్పేస్ ట్రిగ్గర్‌లను కలిగి ఉంది: before_replace и on_replace. స్పేస్‌లోని డేటా మారినప్పుడల్లా ట్రిగ్గర్లు తొలగించబడతాయి (మార్పుల ద్వారా ప్రభావితమైన ప్రతి టుపుల్‌కు, ట్రిగ్గర్ ఫంక్షన్ ప్రారంభించబడుతుంది). కాకుండా on_replace, before_replace-ట్రిగ్గర్‌లు ట్రిగ్గర్ అమలు చేయబడిన టుపుల్ యొక్క డేటాను సవరించడానికి మిమ్మల్ని అనుమతిస్తాయి. దీని ప్రకారం, చివరి రకమైన ట్రిగ్గర్లు మాకు సరిపోతాయి.

box.space.goods:before_replace(function(old, new)
    return box.tuple.new({new[1], new[2], new[3],
        box.sequence.row_version:next()})
end)

కింది ట్రిగ్గర్ ఫీల్డ్ విలువను భర్తీ చేస్తుంది row_ver సీక్వెన్స్ యొక్క తదుపరి విలువకు tuple నిల్వ చేయబడింది row_version.

స్పేస్ నుండి డేటాను సంగ్రహించడానికి goods కాలమ్ ద్వారా row_ver, సూచికను సృష్టిద్దాం:

box.space.goods:create_index('row_ver', {
    parts = { 'row_ver' },
    unique = true,
    type = 'TREE',
    if_not_exists = true
})

సూచిక రకం - చెట్టు (TREE), ఎందుకంటే కాలమ్‌లోని విలువల ఆరోహణ క్రమంలో మేము డేటాను సంగ్రహించవలసి ఉంటుంది row_ver.

స్పేస్‌కి కొంత డేటాను యాడ్ చేద్దాం:

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}

ఎందుకంటే మొదటి ఫీల్డ్ ఆటో-ఇంక్రిమెంటింగ్ కౌంటర్; బదులుగా మేము నిల్ పాస్ చేస్తాము. Tarantool స్వయంచాలకంగా తదుపరి విలువను భర్తీ చేస్తుంది. అదేవిధంగా, కాలమ్ ఫీల్డ్‌ల విలువ వలె row_ver మీరు nil పాస్ చేయవచ్చు - లేదా విలువను పూర్తిగా పేర్కొనవద్దు, ఎందుకంటే ఈ కాలమ్ స్పేస్‌లో చివరి స్థానాన్ని ఆక్రమించింది.

చొప్పించే ఫలితాన్ని తనిఖీ చేద్దాం:

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]
...

మీరు గమనిస్తే, మొదటి మరియు చివరి ఫీల్డ్‌లు స్వయంచాలకంగా పూరించబడతాయి. ఇప్పుడు ఖాళీ మార్పులను పేజీల వారీగా అప్‌లోడ్ చేయడం కోసం ఫంక్షన్‌ను వ్రాయడం సులభం అవుతుంది 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

ఫంక్షన్ విలువను పరామితిగా తీసుకుంటుంది row_ver, మార్పులను అన్‌లోడ్ చేయడానికి అవసరమైన దాని నుండి ప్రారంభించి, మార్చబడిన డేటాలో కొంత భాగాన్ని అందిస్తుంది.

టరాన్టూల్‌లో డేటా నమూనా సూచికల ద్వారా జరుగుతుంది. ఫంక్షన్ get_goods ఇండెక్స్ ద్వారా ఇటరేటర్‌ని ఉపయోగిస్తుంది row_ver మార్చబడిన డేటాను స్వీకరించడానికి. ఇటరేటర్ రకం GT (గ్రేటర్ దాన్, గ్రేటర్ కంటే). దీనర్థం ఇటరేటర్ పాస్ చేసిన కీ (ఫీల్డ్ విలువ) నుండి ప్రారంభమయ్యే సూచిక విలువలను వరుసగా పర్యవేక్షిస్తుంది row_ver).

ఇటరేటర్ టుపుల్స్‌ను తిరిగి ఇస్తుంది. తదనంతరం HTTP ద్వారా డేటాను బదిలీ చేయడానికి, టుపుల్స్‌ను తదుపరి సీరియలైజేషన్‌కు అనుకూలమైన ఆకృతికి మార్చడం అవసరం. ఉదాహరణ దీని కోసం ప్రామాణిక ఫంక్షన్‌ను ఉపయోగిస్తుంది tomap. బదులుగా ఉపయోగించడం tomap మీరు మీ స్వంత ఫంక్షన్‌ను వ్రాయవచ్చు. ఉదాహరణకు, మేము ఫీల్డ్ పేరు మార్చాలనుకోవచ్చు name, ఫీల్డ్ పాస్ లేదు code మరియు ఫీల్డ్‌ను జోడించండి 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

అవుట్‌పుట్ డేటా యొక్క పేజీ పరిమాణం (ఒక భాగంలోని రికార్డుల సంఖ్య) వేరియబుల్ ద్వారా నిర్ణయించబడుతుంది page_size. ఉదాహరణలో విలువ page_size 5. నిజమైన ప్రోగ్రామ్‌లో, పేజీ పరిమాణం సాధారణంగా ముఖ్యమైనది. ఇది స్పేస్ టుపుల్ యొక్క సగటు పరిమాణంపై ఆధారపడి ఉంటుంది. డేటా బదిలీ సమయాన్ని కొలవడం ద్వారా సరైన పేజీ పరిమాణాన్ని అనుభవపూర్వకంగా నిర్ణయించవచ్చు. పేజీ పరిమాణం పెద్దది, పంపడం మరియు స్వీకరించే వైపుల మధ్య రౌండ్‌ట్రిప్‌ల సంఖ్య తక్కువగా ఉంటుంది. ఈ విధంగా మీరు మార్పులను డౌన్‌లోడ్ చేయడానికి మొత్తం సమయాన్ని తగ్గించవచ్చు. అయితే, పేజీ పరిమాణం చాలా పెద్దగా ఉంటే, మేము నమూనాను సీరియలైజ్ చేయడానికి సర్వర్‌లో ఎక్కువ సమయం గడుపుతాము. ఫలితంగా, సర్వర్‌కు వచ్చే ఇతర అభ్యర్థనలను ప్రాసెస్ చేయడంలో ఆలస్యం కావచ్చు. పరామితి page_size కాన్ఫిగరేషన్ ఫైల్ నుండి లోడ్ చేయవచ్చు. ప్రతి ప్రసారం చేయబడిన స్థలం కోసం, మీరు దాని స్వంత విలువను సెట్ చేయవచ్చు. అయినప్పటికీ, చాలా ఖాళీలకు డిఫాల్ట్ విలువ (ఉదాహరణకు, 100) అనుకూలంగా ఉండవచ్చు.

ఫంక్షన్‌ని ఎగ్జిక్యూట్ చేద్దాం 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
...

క్షేత్ర విలువను తీసుకుందాం row_ver చివరి పంక్తి నుండి మరియు ఫంక్షన్‌కు మళ్లీ కాల్ చేయండి:

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
...

మరొక సారి:

tarantool> get_goods(8)
---
- []
...

మీరు చూడగలిగినట్లుగా, ఈ విధంగా ఉపయోగించినప్పుడు, ఫంక్షన్ పేజీలవారీగా అన్ని స్పేస్ రికార్డ్‌లను అందిస్తుంది goods. చివరి పేజీ తర్వాత ఖాళీ ఎంపిక ఉంటుంది.

స్పేస్‌లో మార్పులు చేద్దాం:

box.space.goods:update(4, {{'=', 6, 'copybook'}})
box.space.goods:insert{nil, 'clip', 234}
box.space.goods:insert{nil, 'folder', 432}

మేము ఫీల్డ్ విలువను మార్చాము name ఒక ఎంట్రీ కోసం మరియు రెండు కొత్త ఎంట్రీలను జోడించారు.

చివరి ఫంక్షన్ కాల్‌ని పునరావృతం చేద్దాం:

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
...

ఫంక్షన్ మార్చిన మరియు జోడించిన రికార్డులను తిరిగి ఇచ్చింది. కాబట్టి ఫంక్షన్ get_goods దాని చివరి కాల్ నుండి మారిన డేటాను స్వీకరించడానికి మిమ్మల్ని అనుమతిస్తుంది, ఇది పరిశీలనలో ఉన్న ప్రతిరూపణ పద్ధతికి ఆధారం.

మేము ఈ కథనం యొక్క పరిధికి వెలుపల JSON రూపంలో HTTP ద్వారా ఫలితాల జారీని వదిలివేస్తాము. మీరు దీని గురించి ఇక్కడ చదువుకోవచ్చు: https://habr.com/ru/company/mailru/blog/272141/

క్లయింట్/బానిస భాగం యొక్క అమలు

స్వీకరించే వైపు అమలు ఎలా ఉంటుందో చూద్దాం. డౌన్‌లోడ్ చేసిన డేటాను నిల్వ చేయడానికి స్వీకరించే వైపు ఖాళీని సృష్టిద్దాం:

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
})

స్థలం యొక్క నిర్మాణం మూలంలోని స్థలం యొక్క నిర్మాణాన్ని పోలి ఉంటుంది. కానీ మేము అందుకున్న డేటాను మరెక్కడా పాస్ చేయబోము కాబట్టి, కాలమ్ row_ver గ్రహీత స్థలంలో లేదు. రంగంలో id సోర్స్ ఐడెంటిఫైయర్‌లు రికార్డ్ చేయబడతాయి. అందువల్ల, రిసీవర్ వైపు దానిని స్వయంచాలకంగా పెంచాల్సిన అవసరం లేదు.

అదనంగా, విలువలను సేవ్ చేయడానికి మాకు స్థలం అవసరం 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
})

లోడ్ చేయబడిన ప్రతి స్థలానికి (ఫీల్డ్ space_name) మేము చివరిగా లోడ్ చేసిన విలువను ఇక్కడ సేవ్ చేస్తాము row_ver (క్షేత్రం value) కాలమ్ ప్రాథమిక కీ వలె పనిచేస్తుంది space_name.

స్పేస్ డేటాను లోడ్ చేయడానికి ఒక ఫంక్షన్‌ని క్రియేట్ చేద్దాం goods HTTP ద్వారా. దీన్ని చేయడానికి, మాకు HTTP క్లయింట్‌ని అమలు చేసే లైబ్రరీ అవసరం. కింది పంక్తి లైబ్రరీని లోడ్ చేస్తుంది మరియు HTTP క్లయింట్‌ను ఇన్‌స్టాంటియేట్ చేస్తుంది:

local http_client = require('http.client').new()

json డీరియలైజేషన్ కోసం మాకు లైబ్రరీ కూడా అవసరం:

local json = require('json')

డేటా లోడింగ్ ఫంక్షన్‌ని సృష్టించడానికి ఇది సరిపోతుంది:

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

ఫంక్షన్ url చిరునామాకు HTTP అభ్యర్థనను అమలు చేస్తుంది మరియు దానిని పంపుతుంది row_ver పారామీటర్‌గా మరియు అభ్యర్థన యొక్క డీరియలైజ్డ్ ఫలితాన్ని అందిస్తుంది.

అందుకున్న డేటాను సేవ్ చేసే ఫంక్షన్ ఇలా కనిపిస్తుంది:

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

స్పేస్‌లో డేటాను సేవ్ చేసే చక్రం goods లావాదేవీలో ఉంచబడింది (ఫంక్షన్ దీని కోసం ఉపయోగించబడుతుంది box.atomic) డిస్క్ ఆపరేషన్ల సంఖ్యను తగ్గించడానికి.

చివరగా, లోకల్ స్పేస్ సింక్రొనైజేషన్ ఫంక్షన్ goods మూలాధారంతో మీరు దీన్ని ఇలా అమలు చేయవచ్చు:

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

ముందుగా మనం గతంలో సేవ్ చేసిన విలువను చదువుతాము row_ver స్థలం కోసం goods. అది తప్పిపోయినట్లయితే (మొదటి ఎక్స్ఛేంజ్ సెషన్), అప్పుడు మేము దానిని తీసుకుంటాము row_ver సున్నా. సైకిల్‌లో తదుపరి మేము పేర్కొన్న url వద్ద మూలం నుండి మార్చబడిన డేటాను పేజీల వారీగా డౌన్‌లోడ్ చేస్తాము. ప్రతి పునరావృతం వద్ద, మేము స్వీకరించిన డేటాను తగిన స్థానిక స్థలానికి సేవ్ చేస్తాము మరియు విలువను నవీకరిస్తాము row_ver (అంతరిక్షంలో row_ver మరియు వేరియబుల్ లో row_ver) - విలువను తీసుకోండి row_ver లోడ్ చేయబడిన డేటా యొక్క చివరి పంక్తి నుండి.

ప్రమాదవశాత్తు లూపింగ్ నుండి రక్షించడానికి (ప్రోగ్రామ్‌లో లోపం సంభవించినట్లయితే), లూప్ while ద్వారా భర్తీ చేయవచ్చు for:

for _ = 1, max_req do ...

ఫంక్షన్ అమలు ఫలితంగా sync_goods స్థలం goods రిసీవర్ అన్ని స్పేస్ రికార్డ్‌ల యొక్క తాజా వెర్షన్‌లను కలిగి ఉంటుంది goods మూలంలో.

సహజంగానే, డేటా తొలగింపు ఈ విధంగా ప్రసారం చేయబడదు. అటువంటి అవసరం ఉన్నట్లయితే, మీరు తొలగింపు గుర్తును ఉపయోగించవచ్చు. స్పేస్‌కి జోడించండి goods బూలియన్ ఫీల్డ్ is_deleted మరియు రికార్డ్‌ను భౌతికంగా తొలగించడానికి బదులుగా, మేము లాజికల్ తొలగింపును ఉపయోగిస్తాము - మేము ఫీల్డ్ విలువను సెట్ చేస్తాము is_deleted అర్థం లోకి true. కొన్నిసార్లు బూలియన్ ఫీల్డ్‌కు బదులుగా is_deleted ఫీల్డ్‌ను ఉపయోగించడం మరింత సౌకర్యవంతంగా ఉంటుంది deleted, ఇది రికార్డు యొక్క తార్కిక తొలగింపు తేదీ-సమయాన్ని నిల్వ చేస్తుంది. తార్కిక తొలగింపును చేసిన తర్వాత, తొలగింపు కోసం గుర్తు పెట్టబడిన రికార్డ్ మూలం నుండి గమ్యస్థానానికి బదిలీ చేయబడుతుంది (పైన చర్చించిన తర్కం ప్రకారం).

సీక్వెన్స్ row_ver ఇతర ఖాళీల నుండి డేటాను ప్రసారం చేయడానికి ఉపయోగించవచ్చు: ప్రతి ప్రసారం చేయబడిన స్థలం కోసం ప్రత్యేక క్రమాన్ని సృష్టించాల్సిన అవసరం లేదు.

మేము Tarantool DBMSని ఉపయోగించే అప్లికేషన్‌లలో ఉన్నత-స్థాయి డేటా ప్రతిరూపణ యొక్క ప్రభావవంతమైన మార్గాన్ని పరిశీలించాము.

కనుగొన్న

  1. Tarantool DBMS అనేది అధిక-లోడ్ అప్లికేషన్‌లను రూపొందించడానికి ఆకర్షణీయమైన, ఆశాజనకమైన ఉత్పత్తి.
  2. తక్కువ-స్థాయి ప్రతిరూపణ కంటే అధిక-స్థాయి డేటా ప్రతిరూపణకు అనేక ప్రయోజనాలు ఉన్నాయి.
  3. వ్యాసంలో చర్చించిన ఉన్నత-స్థాయి రెప్లికేషన్ పద్ధతి గత మార్పిడి సెషన్ నుండి మారిన రికార్డులను మాత్రమే బదిలీ చేయడం ద్వారా బదిలీ చేయబడిన డేటా మొత్తాన్ని తగ్గించడానికి మిమ్మల్ని అనుమతిస్తుంది.

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి